Merge "gralloc4-vts: setting USAGE is always BAD_VALUE"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 0e18f48..543acf6 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -7,7 +7,7 @@
       "name": "vts_treble_vintf_vendor_test"
     },
     {
-      "name": "hidl_implementation_test"
+      "name": "hal_implementation_test"
     }
   ]
 }
diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
index c2e310c..2026d8f 100644
--- a/audio/6.0/IDevice.hal
+++ b/audio/6.0/IDevice.hal
@@ -149,7 +149,10 @@
                     AudioConfig suggestedConfig);
 
     /**
-     * Returns whether HAL supports audio patches.
+     * Returns whether HAL supports audio patches. Patch represents a connection
+     * between signal source(s) and signal sink(s). If HAL doesn't support
+     * patches natively (in hardware) then audio system will need to establish
+     * them in software.
      *
      * @return supports true if audio patches are supported.
      */
@@ -316,7 +319,9 @@
     close() generates (Result retval);
 
     /**
-     * Applies an audio effect to an audio device.
+     * Applies an audio effect to an audio device. The effect is inserted
+     * according to its insertion preference specified by INSERT_... EffectFlags
+     * in the EffectDescriptor.
      *
      * @param device identifies the sink or source device this effect must be applied to.
      *               "device" is the AudioPortHandle indicated for the device when the audio
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
index 26e8acb..b2806c7 100644
--- a/audio/common/6.0/types.hal
+++ b/audio/common/6.0/types.hal
@@ -91,37 +91,76 @@
 enum AudioStreamType : int32_t {
     // These values must kept in sync with
     //  frameworks/base/media/java/android/media/AudioSystem.java
+    /** Used to identify the default audio stream volume. */
     DEFAULT          = -1,
+    /** Specifies the minimum value for use in checks and loops. */
     MIN              = 0,
+    /** Used to identify the volume of audio streams for phone calls. */
     VOICE_CALL       = 0,
+    /** Used to identify the volume of audio streams for system sounds. */
     SYSTEM           = 1,
+    /**
+     * Used to identify the volume of audio streams for the phone ring
+     * and message alerts.
+     */
     RING             = 2,
+    /** Used to identify the volume of audio streams for music playback. */
     MUSIC            = 3,
+    /** Used to identify the volume of audio streams for alarms. */
     ALARM            = 4,
+    /** Used to identify the volume of audio streams for notifications. */
     NOTIFICATION     = 5,
+    /**
+     * Used to identify the volume of audio streams for phone calls
+     * when connected on bluetooth.
+     */
     BLUETOOTH_SCO    = 6,
-    ENFORCED_AUDIBLE = 7,  // Sounds that cannot be muted by user and must be
-                           // routed to speaker
+    /**
+     * Used to identify the volume of audio streams for enforced system
+     * sounds in certain countries (e.g camera in Japan). */
+    ENFORCED_AUDIBLE = 7,
+    /** Used to identify the volume of audio streams for DTMF tones. */
     DTMF             = 8,
-    TTS              = 9,  // Transmitted Through Speaker.  Plays over speaker
-                           // only, silent on other devices
-    ACCESSIBILITY    = 10, // For accessibility talk back prompts
-    ASSISTANT        = 11, // For virtual assistant service
+    /**
+     * Used to identify the volume of audio streams exclusively transmitted
+     * through the speaker (TTS) of the device.
+     */
+    TTS              = 9,
+    /**
+     * Used to identify the volume of audio streams for accessibility prompts.
+     */
+    ACCESSIBILITY    = 10,
+    /** Used to identify the volume of audio streams for virtual assistant. */
+    ASSISTANT        = 11,
 };
 
 @export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
 enum AudioSource : int32_t {
     // These values must kept in sync with
     //  frameworks/base/media/java/android/media/MediaRecorder.java,
-    //  frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
     //  system/media/audio_effects/include/audio_effects/audio_effects_conf.h
+    /** Default audio source. */
     DEFAULT             = 0,
+    /** Microphone audio source. */
     MIC                 = 1,
+    /** Voice call uplink (Tx) audio source. */
     VOICE_UPLINK        = 2,
+    /** Voice call downlink (Rx) audio source. */
     VOICE_DOWNLINK      = 3,
+    /** Voice call uplink + downlink audio source. */
     VOICE_CALL          = 4,
+    /**
+     * Microphone audio source tuned for video recording, with the same
+     * orientation as the camera if available.
+     */
     CAMCORDER           = 5,
+    /** Microphone audio source tuned for voice recognition. */
     VOICE_RECOGNITION   = 6,
+    /**
+     * Microphone audio source tuned for voice communications such as VoIP. It
+     * will for instance take advantage of echo cancellation or automatic gain
+     * control if available.
+     */
     VOICE_COMMUNICATION = 7,
     /**
      * Source for the mix to be presented remotely. An example of remote
@@ -146,7 +185,9 @@
      * to include all post processing applied to the playback path.
      */
     ECHO_REFERENCE      = 1997,
+    /** Virtual source for the built-in FM tuner. */
     FM_TUNER            = 1998,
+    /** Virtual source for the last captured hotword. */
     HOTWORD             = 1999,
 };
 
@@ -562,7 +603,7 @@
     IN_CALL          = 2,
     /** Calls handled by apps (Eg: Hangout). */
     IN_COMMUNICATION = 3,
-    /** Call screening in progress */
+    /** Call screening in progress. */
     CALL_SCREEN      = 4,
 };
 
@@ -748,23 +789,85 @@
     // These values must kept in sync with
     //  frameworks/base/media/java/android/media/AudioAttributes.java
     // Note that not all framework values are exposed
+    /**
+     * Usage value to use when the usage is unknown.
+     */
     UNKNOWN                            = 0,
+    /**
+     * Usage value to use when the usage is media, such as music, or movie
+     * soundtracks.
+     */
     MEDIA                              = 1,
+    /**
+     * Usage value to use when the usage is voice communications, such as
+     * telephony or VoIP.
+     */
     VOICE_COMMUNICATION                = 2,
+    /**
+     * Usage value to use when the usage is in-call signalling, such as with
+     * a "busy" beep, or DTMF tones.
+     */
     VOICE_COMMUNICATION_SIGNALLING     = 3,
+    /**
+     * Usage value to use when the usage is an alarm (e.g. wake-up alarm).
+     */
     ALARM                              = 4,
+    /**
+     * Usage value to use when the usage is a generic notification.
+     */
     NOTIFICATION                       = 5,
+    /**
+     * Usage value to use when the usage is telephony ringtone.
+     */
     NOTIFICATION_TELEPHONY_RINGTONE    = 6,
+    /**
+     * Usage value to use when the usage is for accessibility, such as with
+     * a screen reader.
+     */
     ASSISTANCE_ACCESSIBILITY           = 11,
+    /**
+     * Usage value to use when the usage is driving or navigation directions.
+     */
     ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
+    /**
+     * Usage value to use when the usage is sonification, such as  with user
+     * interface sounds.
+     */
     ASSISTANCE_SONIFICATION            = 13,
+    /**
+     * Usage value to use when the usage is for game audio.
+     */
     GAME                               = 14,
+    /**
+     * Usage value to use when feeding audio to the platform and replacing
+     * "traditional" audio source, such as audio capture devices.
+     */
     VIRTUAL_SOURCE                     = 15,
+    /**
+     * Usage value to use for audio responses to user queries, audio
+     * instructions or help utterances.
+     */
     ASSISTANT                          = 16,
+    /**
+     * Usage value to use for assistant voice interaction with remote caller
+     * on Cell and VoIP calls.
+     */
     CALL_ASSISTANT                     = 17,
+    /**
+     * Usage value to use when the usage is an emergency.
+     */
     EMERGENCY                          = 1000,
+    /**
+     * Usage value to use when the usage is a safety sound.
+     */
     SAFETY                             = 1001,
+    /**
+     * Usage value to use when the usage is a vehicle status.
+     */
     VEHICLE_STATUS                     = 1002,
+    /**
+     * Usage value to use when the usage is an announcement.
+     */
     ANNOUNCEMENT                       = 1003,
 };
 
@@ -773,10 +876,30 @@
 enum AudioContentType : uint32_t {
     // Do not change these values without updating their counterparts
     // in frameworks/base/media/java/android/media/AudioAttributes.java
+    /**
+     * Content type value to use when the content type is unknown, or other than
+     * the ones defined.
+     */
     UNKNOWN      = 0,
+    /**
+     * Content type value to use when the content type is speech.
+     */
     SPEECH       = 1,
+    /**
+     * Content type value to use when the content type is music.
+     */
     MUSIC        = 2,
+    /**
+     * Content type value to use when the content type is a soundtrack,
+     * typically accompanying a movie or TV program.
+     */
     MOVIE        = 3,
+    /**
+     * Content type value to use when the content type is a sound used to
+     * accompany a user action, such as a beep or sound effect expressing a key
+     * click, or event, such as the type of a sound for a bonus being received
+     * in a game. These sounds are mostly synthesized or short Foley sounds.
+     */
     SONIFICATION = 4,
 };
 
diff --git a/audio/common/all-versions/copyHAL.sh b/audio/common/all-versions/copyHAL.sh
index d07012f..0a32a51 100755
--- a/audio/common/all-versions/copyHAL.sh
+++ b/audio/common/all-versions/copyHAL.sh
@@ -21,11 +21,12 @@
 
 readonly FWK_DIRECTORY=frameworks/av/media/libaudiohal
 readonly IMPL_DIRECTORY=impl
-readonly IMPL_FACTORYHAL=$IMPL_DIRECTORY/include/libaudiohal/FactoryHalHidl.h
+readonly IMPL_FACTORYHAL=FactoryHalHidl.cpp
 
 readonly VTS_DIRECTORY=test/vts-testcase/hal/audio
 readonly VTS_LIST=test/vts/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk
 readonly WATCHDOG=frameworks/base/services/core/java/com/android/server/Watchdog.cpp
+readonly DUMP_UTILS=frameworks/native/libs/dumputils/dump_utils.cpp
 readonly GSI_CURRENT=build/make/target/product/gsi/current.txt
 
 readonly BASE_VERSION=${1:-$(ls $ANDROID_BUILD_TOP/$HAL_DIRECTORY | grep -E '[0-9]+\.[0-9]+' |
@@ -149,7 +150,7 @@
 
 createFrameworkAdapter() {
     updateVersion -v original_before=1 Android.bp
-    updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $IMPL_FACTORYHAL/Android.bp
+    updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $IMPL_DIRECTORY/Android.bp
     updateVersion -v original_after=1 $IMPL_FACTORYHAL
 }
 echo "Now creating the framework adapter version"
@@ -171,6 +172,9 @@
 echo "Now update watchdog"
 runIfNeeded $(dirname $WATCHDOG) updateAudioVersion -v original_before=1 $(basename $WATCHDOG)
 
+echo "Now update dumputils"
+runIfNeeded $(dirname $DUMP_UTILS) updateAudioVersion -v original_before=1 $(basename $DUMP_UTILS)
+
 echo "Now update GSI current.txt"
 runIfNeeded $(dirname $GSI_CURRENT) update-vndk-list.sh
 
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
index f58a599..3e8b715 100644
--- a/audio/common/all-versions/default/service/Android.bp
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -24,24 +24,6 @@
         "liblog",
         "libutils",
         "libhardware",
-        "android.hardware.audio@2.0",
-        "android.hardware.audio@4.0",
-        "android.hardware.audio@5.0",
-        "android.hardware.audio@6.0",
-        "android.hardware.audio.common@2.0",
-        "android.hardware.audio.common@4.0",
-        "android.hardware.audio.common@5.0",
-        "android.hardware.audio.common@6.0",
-        "android.hardware.audio.effect@2.0",
-        "android.hardware.audio.effect@4.0",
-        "android.hardware.audio.effect@5.0",
-        "android.hardware.audio.effect@6.0",
-        "android.hardware.bluetooth.a2dp@1.0",
-        "android.hardware.bluetooth.audio@2.0",
-        "android.hardware.soundtrigger@2.0",
-        "android.hardware.soundtrigger@2.1",
-        "android.hardware.soundtrigger@2.2",
-        "android.hardware.soundtrigger@2.3",
     ],
 }
 
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 00bcb19..147d062 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -16,20 +16,9 @@
 
 #define LOG_TAG "audiohalservice"
 
-#include <android/hardware/audio/2.0/IDevicesFactory.h>
-#include <android/hardware/audio/4.0/IDevicesFactory.h>
-#include <android/hardware/audio/5.0/IDevicesFactory.h>
-#include <android/hardware/audio/6.0/IDevicesFactory.h>
-#include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/5.0/IEffectsFactory.h>
-#include <android/hardware/audio/effect/6.0/IEffectsFactory.h>
-#include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
-#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
-#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
-#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h>
+#include <string>
+#include <vector>
+
 #include <binder/ProcessState.h>
 #include <cutils/properties.h>
 #include <hidl/HidlTransportSupport.h>
@@ -39,13 +28,20 @@
 using namespace android::hardware;
 using android::OK;
 
+using InterfacesList = std::vector<std::string>;
+
 /** Try to register the provided factories in the provided order.
  *  If any registers successfully, do not register any other and return true.
  *  If all fail, return false.
  */
-template <class... Factories>
-bool registerPassthroughServiceImplementations() {
-    return ((registerPassthroughServiceImplementation<Factories>() != OK) && ...);
+template <class Iter>
+static bool registerPassthroughServiceImplementations(Iter first, Iter last) {
+    for (; first != last; ++first) {
+        if (registerPassthroughServiceImplementation(*first) == OK) {
+            return true;
+        }
+    }
+    return false;
 }
 
 int main(int /* argc */, char* /* argv */ []) {
@@ -62,36 +58,58 @@
     }
     configureRpcThreadpool(16, true /*callerWillJoin*/);
 
-    // Keep versions on a separate line for easier parsing
+    // Automatic formatting tries to compact the lines, making them less readable
     // clang-format off
-    LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
-                                audio::V6_0::IDevicesFactory,
-                                audio::V5_0::IDevicesFactory,
-                                audio::V4_0::IDevicesFactory,
-                                audio::V2_0::IDevicesFactory>()),
-                        "Could not register audio core API");
+    const std::vector<InterfacesList> mandatoryInterfaces = {
+        {
+            "Audio Core API",
+            "android.hardware.audio@6.0::IDevicesFactory",
+            "android.hardware.audio@5.0::IDevicesFactory",
+            "android.hardware.audio@4.0::IDevicesFactory",
+            "android.hardware.audio@2.0::IDevicesFactory"
+        },
+        {
+            "Audio Effect API",
+            "android.hardware.audio.effect@6.0::IEffectsFactory",
+            "android.hardware.audio.effect@5.0::IEffectsFactory",
+            "android.hardware.audio.effect@4.0::IEffectsFactory",
+            "android.hardware.audio.effect@2.0::IEffectsFactory",
+        }
+    };
 
-    LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
-                                audio::effect::V6_0::IEffectsFactory,
-                                audio::effect::V5_0::IEffectsFactory,
-                                audio::effect::V4_0::IEffectsFactory,
-                                audio::effect::V2_0::IEffectsFactory>()),
-                        "Could not register audio effect API");
+    const std::vector<InterfacesList> optionalInterfaces = {
+        {
+            "Soundtrigger API",
+            "android.hardware.soundtrigger@2.3::ISoundTriggerHw",
+            "android.hardware.soundtrigger@2.2::ISoundTriggerHw",
+            "android.hardware.soundtrigger@2.1::ISoundTriggerHw",
+            "android.hardware.soundtrigger@2.0::ISoundTriggerHw",
+        },
+        {
+            "Bluetooth Audio API",
+            "android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory"
+        },
+        // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
+        {
+            "Bluetooth Audio Offload API",
+            "android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioOffload"
+        }
+    };
     // clang-format on
 
-    ALOGW_IF((registerPassthroughServiceImplementations<
-                     soundtrigger::V2_3::ISoundTriggerHw, soundtrigger::V2_2::ISoundTriggerHw,
-                     soundtrigger::V2_1::ISoundTriggerHw, soundtrigger::V2_0::ISoundTriggerHw>()),
-             "Could not register soundtrigger API");
+    for (const auto& listIter : mandatoryInterfaces) {
+        auto iter = listIter.begin();
+        const std::string& interfaceFamilyName = *iter++;
+        LOG_ALWAYS_FATAL_IF(!registerPassthroughServiceImplementations(iter, listIter.end()),
+                            "Could not register %s", interfaceFamilyName.c_str());
+    }
 
-    ALOGW_IF(registerPassthroughServiceImplementations<
-                     bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>(),
-             "Could not register Bluetooth audio API");
-
-    // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
-    ALOGW_IF(registerPassthroughServiceImplementations<
-                     bluetooth::a2dp::V1_0::IBluetoothAudioOffload>(),
-             "Could not register Bluetooth audio offload API");
+    for (const auto& listIter : optionalInterfaces) {
+        auto iter = listIter.begin();
+        const std::string& interfaceFamilyName = *iter++;
+        ALOGW_IF(!registerPassthroughServiceImplementations(iter, listIter.end()),
+                 "Could not register %s", interfaceFamilyName.c_str());
+    }
 
     joinRpcThreadpool();
 }
diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt
index 2dfcb9b..cd5ca2a 100644
--- a/audio/effect/6.0/xml/api/current.txt
+++ b/audio/effect/6.0/xml/api/current.txt
@@ -3,11 +3,13 @@
 
   public class AudioEffectsConf {
     ctor public AudioEffectsConf();
+    method public audio.effects.V6_0.AudioEffectsConf.DeviceEffects getDeviceEffects();
     method public audio.effects.V6_0.EffectsType getEffects();
     method public audio.effects.V6_0.LibrariesType getLibraries();
     method public audio.effects.V6_0.AudioEffectsConf.Postprocess getPostprocess();
     method public audio.effects.V6_0.AudioEffectsConf.Preprocess getPreprocess();
     method public audio.effects.V6_0.VersionType getVersion();
+    method public void setDeviceEffects(audio.effects.V6_0.AudioEffectsConf.DeviceEffects);
     method public void setEffects(audio.effects.V6_0.EffectsType);
     method public void setLibraries(audio.effects.V6_0.LibrariesType);
     method public void setPostprocess(audio.effects.V6_0.AudioEffectsConf.Postprocess);
@@ -15,6 +17,11 @@
     method public void setVersion(audio.effects.V6_0.VersionType);
   }
 
+  public static class AudioEffectsConf.DeviceEffects {
+    ctor public AudioEffectsConf.DeviceEffects();
+    method public java.util.List<audio.effects.V6_0.DeviceProcessType> getDevicePort();
+  }
+
   public static class AudioEffectsConf.Postprocess {
     ctor public AudioEffectsConf.Postprocess();
     method public java.util.List<audio.effects.V6_0.StreamPostprocessType> getStream();
@@ -25,6 +32,72 @@
     method public java.util.List<audio.effects.V6_0.StreamPreprocessType> getStream();
   }
 
+  public class DeviceProcessType extends audio.effects.V6_0.StreamProcessingType {
+    ctor public DeviceProcessType();
+    method public String getAddress();
+    method public audio.effects.V6_0.DeviceType getType();
+    method public void setAddress(String);
+    method public void setType(audio.effects.V6_0.DeviceType);
+  }
+
+  public enum DeviceType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_AUX_DIGITAL;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BACK_MIC;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BUILTIN_MIC;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_BUS;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_COMMUNICATION;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_ECHO_REFERENCE;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_FM_TUNER;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_HDMI;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_HDMI_ARC;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_IP;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_LINE;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_LOOPBACK;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_PROXY;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_SPDIF;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_TELEPHONY_RX;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_TV_TUNER;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_USB_ACCESSORY;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_USB_DEVICE;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_USB_HEADSET;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_VOICE_CALL;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_IN_WIRED_HEADSET;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_AUX_DIGITAL;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_AUX_LINE;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_BUS;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_EARPIECE;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_FM;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_HDMI;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_HDMI_ARC;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_HEARING_AID;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_IP;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_LINE;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_PROXY;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_SPDIF;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_SPEAKER;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_TELEPHONY_TX;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_USB_ACCESSORY;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_USB_DEVICE;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_USB_HEADSET;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+    enum_constant public static final audio.effects.V6_0.DeviceType AUDIO_DEVICE_OUT_WIRED_HEADSET;
+  }
+
   public class EffectImplType {
     ctor public EffectImplType();
     method public String getLibrary();
@@ -69,6 +142,8 @@
   public enum StreamInputType {
     method public String getRawName();
     enum_constant public static final audio.effects.V6_0.StreamInputType camcorder;
+    enum_constant public static final audio.effects.V6_0.StreamInputType echo_reference;
+    enum_constant public static final audio.effects.V6_0.StreamInputType fm_tuner;
     enum_constant public static final audio.effects.V6_0.StreamInputType mic;
     enum_constant public static final audio.effects.V6_0.StreamInputType unprocessed;
     enum_constant public static final audio.effects.V6_0.StreamInputType voice_call;
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
index a7ff20b..eeaaf63 100644
--- a/audio/effect/6.0/xml/audio_effects_conf.xsd
+++ b/audio/effect/6.0/xml/audio_effects_conf.xsd
@@ -36,6 +36,8 @@
       <xs:enumeration value="voice_communication"/>
       <xs:enumeration value="unprocessed"/>
       <xs:enumeration value="voice_performance"/>
+      <xs:enumeration value="echo_reference"/>
+      <xs:enumeration value="fm_tuner"/>
     </xs:restriction>
   </xs:simpleType>
   <xs:simpleType name="streamOutputType">
@@ -58,6 +60,65 @@
       <xs:pattern value="[^/].*"/>
     </xs:restriction>
   </xs:simpleType>
+  <xs:simpleType name="deviceType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+      <!-- Due to the xml format, IN types can not be a separated from OUT types -->
+      <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+      <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_ECHO_REFERENCE"/>
+    </xs:restriction>
+  </xs:simpleType>
   <!-- Complex types -->
   <xs:complexType name="librariesType">
     <xs:annotation>
@@ -174,6 +235,31 @@
       </xs:extension>
     </xs:complexContent>
   </xs:complexType>
+  <xs:complexType name="deviceProcessType">
+    <xs:annotation>
+      <xs:documentation xml:lang="en">
+        Audio Device Effects configuration. The processing configuration consists
+        of a list of effects to be automatically added on a device Port when involved in an audio
+        patch.
+        Valid device type are listed in "deviceType" and shall be aligned.
+        Each stream element contains a list of "apply" elements. The value of the
+        "effect" attr must correspond to the name of an "effect" element.
+        Note that if the device is involved in a hardware patch, the effect must be hardware
+        accelerated.
+        Example:
+        <devicePort address="BUS00_USAGE_MAIN" type="AUDIO_DEVICE_OUT_BUS">
+            <apply effect="equalizer"/>
+            <apply effect="effect2"/>
+        </devicePort>
+      </xs:documentation>
+    </xs:annotation>
+    <xs:complexContent>
+      <xs:extension base="aec:streamProcessingType">
+         <xs:attribute name="address" type="xs:string" use="required"/>
+         <xs:attribute name="type" type="aec:deviceType" use="required"/>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
   <!-- Root element -->
   <xs:element name="audio_effects_conf">
     <xs:complexType>
@@ -194,6 +280,13 @@
             </xs:sequence>
           </xs:complexType>
         </xs:element>
+        <xs:element name="deviceEffects" minOccurs="0" maxOccurs="1">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="devicePort" type="aec:deviceProcessType" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
       </xs:sequence>
       <xs:attribute name="version" type="aec:versionType" use="required"/>
     </xs:complexType>
@@ -227,4 +320,4 @@
       <xs:field xpath="@effect"/>
     </xs:keyref>
   </xs:element>
-</xs:schema>
\ No newline at end of file
+</xs:schema>
diff --git a/automotive/audiocontrol/1.0/default/Android.bp b/automotive/audiocontrol/1.0/default/Android.bp
index 3d04c89..ae4b805 100644
--- a/automotive/audiocontrol/1.0/default/Android.bp
+++ b/automotive/audiocontrol/1.0/default/Android.bp
@@ -30,9 +30,4 @@
         "libutils",
     ],
     vintf_fragments: ["audiocontrol_manifest.xml"],
-    cflags: [
-        "-DLOG_TAG=\"AudCntrlDrv\"",
-        "-O0",
-        "-g",
-    ],
 }
diff --git a/automotive/can/1.0/ICanController.hal b/automotive/can/1.0/ICanController.hal
index 0c6f53e..aaf85e9 100644
--- a/automotive/can/1.0/ICanController.hal
+++ b/automotive/can/1.0/ICanController.hal
@@ -27,51 +27,22 @@
  */
 interface ICanController {
     /**
-     * Type of an interface, a mean to express the domain of device address.
+     * Type of an interface, an equivalent to BusConfig::InterfaceId
+     * union discriminator. Defines a number of specific standard hardware
+     * families and a generic catch-all type of {@see INDEXED}.
      */
     enum InterfaceType : uint8_t {
-        /**
-         * Virtual SocketCAN interface.
-         *
-         * The address is an interface name, such as vcan0. If the interface
-         * doesn't exist, HAL server must create it.
-         *
-         * Valid InterfaceIdentifier types:
-         *  - address.
-         */
+        /** Virtual SocketCAN interface. */
         VIRTUAL,
 
-        /**
-         * Native SocketCAN interface.
-         *
-         * The address is an interface name, such as can0.
-         *
-         * Valid InterfaceIdentifier types:
-         *  - address;
-         *  - serialno.
-         */
+        /** Native SocketCAN interface. */
         SOCKETCAN,
 
-        /**
-         * Serial-based interface.
-         *
-         * The address is a patch to a device, such as /dev/ttyUSB0.
-         *
-         * Valid InterfaceIdentifier types:
-         *  - address;
-         *  - serialno.
-         */
+        /** Serial line CAN interface. */
         SLCAN,
 
-        /**
-         * Proprietary interface, specific to the hardware system Android
-         * is running on. Instead of using address field, the interface is
-         * addressed with 0-based index.
-         *
-         * Valid InterfaceIdentifier types:
-         *  - index
-         */
-        INDEXED
+        /** Proprietary, device-specific interface. */
+        INDEXED,
     };
 
     enum Result : uint8_t {
@@ -92,13 +63,19 @@
         NOT_SUPPORTED,
 
         /**
-         * Provided address (interface name, device path) doesn't exist or there
-         * is no device with a given serial no.
+         * Provided interface ID (index, name, device path) doesn't exist or
+         * there is no device with a given serial number.
          */
-        BAD_ADDRESS,
+        BAD_INTERFACE_ID,
 
         /** Provided bit rate is not supported by the hardware. */
         BAD_BITRATE,
+
+        /**
+         * Provided service name ({@see BusConfig#name}) either has invalid
+         * format or is not listed in device manifest file.
+         */
+        BAD_SERVICE_NAME,
     };
 
     /**
@@ -106,49 +83,76 @@
      *
      * ISO TP and CAN FD are currently not supported.
      */
-    struct BusConfiguration {
+    struct BusConfig {
         /**
          * Name under which ICanBus HIDL service should be published.
          *
          * It must consist of only alphanumeric characters and underscore
          * (a-z, A-Z, 0-9, '_'), at least 1 and at most 32 characters long.
+         *
+         * This field is *not* meant to distinguish between hardware interfaces
+         * nor preselect parameters like bitrate. The only intended side-effect
+         * of changing it should be a different ICanBus HIDL service name and
+         * the HIDL service should make no assumptions on its contents.
          */
         string name;
 
         /**
-         * Type of the hardware (or virtual) CAN interface.
+         * Hardware interface configuration.
+         *
+         * This union's discriminator has an equivalent enum
+         * {@see InterfaceType} to express compatibility via
+         * getSupportedInterfaceTypes().
          */
-        InterfaceType iftype;
+        safe_union InterfaceId {
+            /** Virtual SocketCAN interface. */
+            struct Virtual {
+                /** Interface name, such as vcan0. If the interface doesn't
+                 * exist, HAL server must create it.
+                 */
+                string ifname;
+            } virtualif;
 
-        /**
-         * Identification of hardware interface to configure.
-         */
-        safe_union InterfaceIdentifier {
-            /**
-             * Interface name or other mean of identification of the specific
-             * interface port. Syntax depends on {@see iftype}, for details
-             * {@see InterfaceType}.
-             */
-            string address;
+            /** Native SocketCAN interface. */
+            safe_union Socketcan {
+                /** Interface name, such as can0. */
+                string ifname;
+                /**
+                 * Alternatively to providing {@see ifname}, one may provide a
+                 * list of interface serial number suffixes. If there happens to
+                 * be a device (like USB2CAN) with a matching serial number
+                 * suffix, the HAL service will have to select it.
+                 *
+                 * Client may utilize this in two ways: by matching against the
+                 * entire serial number, or the last few characters (usually
+                 * one). The former is better for small-scale test deployments
+                 * (with just a handful of vehicles), the latter is good for
+                 * larger scale (where a small suffix list may support large
+                 * test fleet).
+                 */
+                vec<string> serialno;
+            } socketcan;
+
+            /** Serial line CAN interface. */
+            safe_union Slcan {
+                /** Path to a device, such as /dev/ttyUSB0. */
+                string ttyname;
+                /**
+                 * List of interface serial number suffixes.
+                 * {@see Socketcan::serialno}
+                 */
+                vec<string> serialno;
+            } slcan;
 
             /**
-             * Numerical identifier of interface, used for InterfaceType#INDEXED.
-             */
-            uint8_t index;
-
-            /**
-             * Alternatively to providing {@see address}, one may provide a list
-             * of interface serial number suffixes. If there happens to be
-             * a device (like USB2CAN) with a matching serial number suffix,
-             * it gets selected.
+             * Proprietary, device-specific interface.
              *
-             * Client may utilize this in two ways: by matching against the
-             * entire serial number, or the last few characters (usually one).
-             * The former is better for small-scale test deployments (with just
-             * a handful of vehicles), the latter is good for larger scale
-             * (where a small suffix list may support large test fleet).
+             * Non-SocketCAN interfaces should use this variant.
              */
-            vec<string> serialno;
+            struct Indexed {
+                /** Interface number, 0-based. */
+                uint8_t index;
+            } indexed;
         } interfaceId;
 
         /**
@@ -156,7 +160,8 @@
          *
          * Typical bit rates are: 100000, 125000, 250000, 500000.
          *
-         * For virtual interfaces this value is ignored.
+         * For {@see interfaceId#virtual} and pre-configured
+         * {@see interfaceId#indexed} interfaces this value is ignored.
          */
         uint32_t bitrate;
     };
@@ -164,17 +169,17 @@
     /**
      * Fetches the list of interface types supported by this HAL server.
      *
-     * @return iftypes The list of supported interface types
+     * @return iftypes The list of supported interface types.
      */
     getSupportedInterfaceTypes() generates (vec<InterfaceType> iftypes);
 
     /**
      * Bring up the CAN interface and publish ICanBus server instance.
      *
-     * @param config Configuration of the CAN interface
+     * @param config Configuration of the CAN interface.
      * @return result OK if the operation succeeded; error code otherwise.
      */
-    upInterface(BusConfiguration config) generates (Result result);
+    upInterface(BusConfig config) generates (Result result);
 
     /**
      * Unpublish ICanBus server instance and bring down the CAN interface.
@@ -182,9 +187,9 @@
      * In case of failure, at least the ICanBus server instance must be
      * unpublished and resources freed on best-effort basis.
      *
-     * @param name Name of the interface (@see BusConfiguration#name} to
-     * bring down
-     * @return success true in case of success, false otherwise
+     * @param name Name of the interface (@see BusConfig#name} to
+     * bring down.
+     * @return success true in case of success, false otherwise.
      */
     downInterface(string name) generates (bool success);
 };
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 8fb09eb..9f704c1 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -124,7 +124,7 @@
     if (!isUp.has_value()) {
         // preUp() should prepare the interface (either create or make sure it's there)
         LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
-        return ICanController::Result::BAD_ADDRESS;
+        return ICanController::Result::BAD_INTERFACE_ID;
     }
 
     if (!*isUp && !netdevice::up(mIfname)) {
diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp
index ef04d01..aafbecc 100644
--- a/automotive/can/1.0/default/CanBusNative.cpp
+++ b/automotive/can/1.0/default/CanBusNative.cpp
@@ -28,7 +28,7 @@
 ICanController::Result CanBusNative::preUp() {
     if (!netdevice::exists(mIfname)) {
         LOG(ERROR) << "Interface " << mIfname << " doesn't exist";
-        return ICanController::Result::BAD_ADDRESS;
+        return ICanController::Result::BAD_INTERFACE_ID;
     }
 
     if (mBitrate == 0) {
diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp
index 0feee8f..d15905d 100644
--- a/automotive/can/1.0/default/CanBusSlcan.cpp
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -81,7 +81,7 @@
     mFd = base::unique_fd(open(mUartName.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY));
     if (!mFd.ok()) {
         LOG(ERROR) << "SLCAN Failed to open " << mUartName << ": " << strerror(errno);
-        return ICanController::Result::BAD_ADDRESS;
+        return ICanController::Result::BAD_INTERFACE_ID;
     }
 
     // If the device is already up, update the iface name in our CanBusSlcan object
diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp
index fb648c1..0700c77 100644
--- a/automotive/can/1.0/default/CanController.cpp
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -27,7 +27,8 @@
 
 namespace android::hardware::automotive::can::V1_0::implementation {
 
-using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
+using IfId = ICanController::BusConfig::InterfaceId;
+using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator;
 
 Return<void> CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) {
     _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN,
@@ -40,15 +41,14 @@
     return std::regex_match(name, nameRE);
 }
 
-Return<ICanController::Result> CanController::upInterface(
-        const ICanController::BusConfiguration& config) {
+Return<ICanController::Result> CanController::upInterface(const ICanController::BusConfig& config) {
     LOG(VERBOSE) << "Attempting to bring interface up: " << toString(config);
 
     std::lock_guard<std::mutex> lck(mCanBusesGuard);
 
     if (!isValidName(config.name)) {
         LOG(ERROR) << "Bus name " << config.name << " is invalid";
-        return ICanController::Result::UNKNOWN_ERROR;
+        return ICanController::Result::BAD_SERVICE_NAME;
     }
 
     if (mCanBuses.find(config.name) != mCanBuses.end()) {
@@ -58,24 +58,23 @@
 
     sp<CanBus> busService;
 
-    if (config.iftype == ICanController::InterfaceType::SOCKETCAN) {
-        // TODO(b/135918744): support serialno
-        if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
-            busService = new CanBusNative(config.interfaceId.address(), config.bitrate);
+    if (config.interfaceId.getDiscriminator() == IfIdDisc::socketcan) {
+        // TODO(b/142654031): support serialno
+        auto& socketcan = config.interfaceId.socketcan();
+        if (socketcan.getDiscriminator() == IfId::Socketcan::hidl_discriminator::ifname) {
+            busService = new CanBusNative(socketcan.ifname(), config.bitrate);
         } else {
-            return ICanController::Result::BAD_ADDRESS;
+            return ICanController::Result::BAD_INTERFACE_ID;
         }
-    } else if (config.iftype == ICanController::InterfaceType::VIRTUAL) {
-        if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
-            busService = new CanBusVirtual(config.interfaceId.address());
+    } else if (config.interfaceId.getDiscriminator() == IfIdDisc::virtualif) {
+        busService = new CanBusVirtual(config.interfaceId.virtualif().ifname);
+    } else if (config.interfaceId.getDiscriminator() == IfIdDisc::slcan) {
+        // TODO(b/142654031): support serialno
+        auto& slcan = config.interfaceId.slcan();
+        if (slcan.getDiscriminator() == IfId::Slcan::hidl_discriminator::ttyname) {
+            busService = new CanBusSlcan(slcan.ttyname(), config.bitrate);
         } else {
-            return ICanController::Result::BAD_ADDRESS;
-        }
-    } else if (config.iftype == ICanController::InterfaceType::SLCAN) {
-        if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
-            busService = new CanBusSlcan(config.interfaceId.address(), config.bitrate);
-        } else {
-            return ICanController::Result::BAD_ADDRESS;
+            return ICanController::Result::BAD_INTERFACE_ID;
         }
     } else {
         return ICanController::Result::NOT_SUPPORTED;
@@ -91,7 +90,7 @@
         if (!busService->down()) {
             LOG(WARNING) << "Failed to bring down CAN bus that failed to register";
         }
-        return ICanController::Result::UNKNOWN_ERROR;
+        return ICanController::Result::BAD_SERVICE_NAME;
     }
 
     mCanBuses[config.name] = busService;
diff --git a/automotive/can/1.0/default/CanController.h b/automotive/can/1.0/default/CanController.h
index 99a551a..27e82f3 100644
--- a/automotive/can/1.0/default/CanController.h
+++ b/automotive/can/1.0/default/CanController.h
@@ -25,8 +25,7 @@
 struct CanController : public ICanController {
     Return<void> getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) override;
 
-    Return<ICanController::Result> upInterface(
-            const ICanController::BusConfiguration& config) override;
+    Return<ICanController::Result> upInterface(const ICanController::BusConfig& config) override;
     Return<bool> downInterface(const hidl_string& name) override;
 
   private:
diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp
index 5494ba3..33755bf 100644
--- a/automotive/can/1.0/tools/canhalctrl.cpp
+++ b/automotive/can/1.0/tools/canhalctrl.cpp
@@ -71,15 +71,31 @@
         if (!isSupported(ctrl, type)) continue;
         anySupported = true;
 
-        ICanController::BusConfiguration config = {};
+        ICanController::BusConfig config = {};
         config.name = busName;
-        config.iftype = type;
         config.bitrate = bitrate;
 
-        if (type == ICanController::InterfaceType::INDEXED) {
-            config.interfaceId.index(std::stol(interface));
+        // TODO(b/146214370): move interfaceId constructors to a library
+        using IfCfg = ICanController::BusConfig::InterfaceId;
+        if (type == ICanController::InterfaceType::VIRTUAL) {
+            config.interfaceId.virtualif({interface});
+        } else if (type == ICanController::InterfaceType::SOCKETCAN) {
+            IfCfg::Socketcan socketcan = {};
+            socketcan.ifname(interface);
+            config.interfaceId.socketcan(socketcan);
+        } else if (type == ICanController::InterfaceType::SLCAN) {
+            IfCfg::Slcan slcan = {};
+            slcan.ttyname(interface);
+            config.interfaceId.slcan(slcan);
+        } else if (type == ICanController::InterfaceType::INDEXED) {
+            auto idx = std::stol(interface);
+            if (idx < 0 || idx > UINT8_MAX) {
+                std::cerr << "Interface index out of range: " << idx;
+                return -1;
+            }
+            config.interfaceId.indexed({uint8_t(idx)});
         } else {
-            config.interfaceId.address(interface);
+            CHECK(false) << "Unexpected interface type: " << toString(type);
         }
 
         const auto upresult = ctrl->upInterface(config);
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
index efaad53..68d555d 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -81,7 +81,7 @@
 struct Bus {
     DISALLOW_COPY_AND_ASSIGN(Bus);
 
-    Bus(sp<ICanController> controller, const ICanController::BusConfiguration& config)
+    Bus(sp<ICanController> controller, const ICanController::BusConfig& config)
         : mIfname(config.name), mController(controller) {
         const auto result = controller->upInterface(config);
         EXPECT_EQ(ICanController::Result::OK, result);
@@ -122,6 +122,7 @@
 
     void send(const CanMessage& msg) {
         EXPECT_NE(mBus, nullptr);
+        if (!mBus) return;
         const auto result = mBus->send(msg);
         EXPECT_EQ(Result::OK, result);
     }
@@ -196,10 +197,9 @@
     const auto idx = mLastIface++;
     EXPECT_LT(idx, mBusNames.size());
 
-    ICanController::BusConfiguration config = {};
+    ICanController::BusConfig config = {};
     config.name = mBusNames[idx];
-    config.iftype = InterfaceType::VIRTUAL;
-    config.interfaceId.address("vcan50");
+    config.interfaceId.virtualif({"vcan50"});
 
     return Bus(mCanController, config);
 }
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
index b2edd78..8397215 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -31,6 +31,7 @@
 
 using hardware::hidl_vec;
 using InterfaceType = ICanController::InterfaceType;
+using IfId = ICanController::BusConfig::InterfaceId;
 
 static utils::SimpleHidlEnvironment<ICanController>* gEnv = nullptr;
 
@@ -89,10 +90,23 @@
 
 bool CanControllerHalTest::up(InterfaceType iftype, std::string srvname, std::string ifname,
                               ICanController::Result expected) {
-    ICanController::BusConfiguration config = {};
+    ICanController::BusConfig config = {};
     config.name = srvname;
-    config.iftype = iftype;
-    config.interfaceId.address(ifname);
+
+    // TODO(b/146214370): move interfaceId constructors to a library
+    if (iftype == InterfaceType::SOCKETCAN) {
+        IfId::Socketcan socketcan = {};
+        socketcan.ifname(ifname);
+        config.interfaceId.socketcan(socketcan);
+    } else if (iftype == InterfaceType::SLCAN) {
+        IfId::Slcan slcan = {};
+        slcan.ttyname(ifname);
+        config.interfaceId.slcan(slcan);
+    } else if (iftype == InterfaceType::VIRTUAL) {
+        config.interfaceId.virtualif({ifname});
+    } else {
+        EXPECT_TRUE(false) << "Unexpected iftype: " << toString(iftype);
+    }
 
     const auto upresult = mCanController->upInterface(config);
 
@@ -155,54 +169,64 @@
     assertRegistered(name, false);
 }
 
-TEST_F(CanControllerHalTest, IdentifierCompatibility) {
-    using IdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
-    static const std::map<InterfaceType, std::vector<IdDisc>> compatMatrix = {
-            {InterfaceType::VIRTUAL, {IdDisc::address}},
-            {InterfaceType::SOCKETCAN, {IdDisc::address, IdDisc::serialno}},
-            {InterfaceType::SLCAN, {IdDisc::address, IdDisc::serialno}},
-            {InterfaceType::INDEXED, {IdDisc::index}},
+TEST_F(CanControllerHalTest, ConfigCompatibility) {
+    // using random-ish addresses, which may not be valid - we can't test the success case
+    // TODO(b/146214370): move interfaceId constructors to a library
+    IfId virtualCfg = {};
+    virtualCfg.virtualif({"vcan70"});
+
+    IfId::Socketcan socketcanIfname = {};
+    socketcanIfname.ifname("can0");
+    IfId socketcanIfnameCfg = {};
+    socketcanIfnameCfg.socketcan(socketcanIfname);
+
+    IfId::Socketcan socketcanSerial = {};
+    socketcanSerial.serialno({"1234", "2345"});
+    IfId socketcanSerialCfg = {};
+    socketcanSerialCfg.socketcan(socketcanSerial);
+
+    IfId::Slcan slcanTtyname = {};
+    slcanTtyname.ttyname("/dev/ttyUSB0");
+    IfId slcanTtynameCfg = {};
+    slcanTtynameCfg.slcan(slcanTtyname);
+
+    IfId::Slcan slcanSerial = {};
+    slcanSerial.serialno({"dead", "beef"});
+    IfId slcanSerialCfg = {};
+    slcanSerialCfg.slcan(slcanSerial);
+
+    IfId indexedCfg = {};
+    indexedCfg.indexed({0});
+
+    static const std::vector<std::pair<InterfaceType, IfId>> compatMatrix = {
+            {InterfaceType::VIRTUAL, virtualCfg},
+            {InterfaceType::SOCKETCAN, socketcanIfnameCfg},
+            {InterfaceType::SOCKETCAN, socketcanSerialCfg},
+            {InterfaceType::SLCAN, slcanTtynameCfg},
+            {InterfaceType::SLCAN, slcanSerialCfg},
+            {InterfaceType::INDEXED, indexedCfg},
     };
-    static const std::vector<IdDisc> allDisc = {IdDisc::address, IdDisc::index, IdDisc::serialno};
 
-    for (const auto [iftype, supported] : compatMatrix) {
-        for (const auto iddisc : allDisc) {
-            LOG(INFO) << "Compatibility testing: " << iftype << " / " << iddisc;
+    for (const auto [iftype, cfg] : compatMatrix) {
+        LOG(INFO) << "Compatibility testing: " << iftype << " / " << cfg;
 
-            ICanController::BusConfiguration config = {};
-            config.name = "compattestsrv";
-            config.iftype = iftype;
-            config.bitrate = 125000;
+        ICanController::BusConfig config = {};
+        config.name = "compattestsrv";
+        config.bitrate = 125000;
+        config.interfaceId = cfg;
 
-            // using random-ish addresses, which may not be valid - we can't test the success case
-            if (iddisc == IdDisc::address) {
-                config.interfaceId.address("can0");
-            } else if (iddisc == IdDisc::index) {
-                config.interfaceId.index(0);
-            } else if (iddisc == IdDisc::serialno) {
-                config.interfaceId.serialno({"dummy", "dummier"});
-            }
+        const auto upresult = mCanController->upInterface(config);
 
-            const auto upresult = mCanController->upInterface(config);
+        if (!isSupported(iftype)) {
+            ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
+            continue;
+        }
+        ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult);
 
-            if (!isSupported(iftype)) {
-                ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
-                continue;
-            }
-            ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult);
-
-            bool isSupportedDisc =
-                    std::find(supported.begin(), supported.end(), iddisc) != supported.end();
-            if (!isSupportedDisc) {
-                ASSERT_EQ(ICanController::Result::BAD_ADDRESS, upresult);
-                continue;
-            }
-
-            if (upresult == ICanController::Result::OK) {
-                const auto dnresult = mCanController->downInterface(config.name);
-                ASSERT_TRUE(dnresult);
-                continue;
-            }
+        if (upresult == ICanController::Result::OK) {
+            const auto dnresult = mCanController->downInterface(config.name);
+            ASSERT_TRUE(dnresult);
+            continue;
         }
     }
 }
@@ -211,7 +235,7 @@
     const std::string name = "";
 
     assertRegistered(name, false);
-    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) {
+    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::BAD_SERVICE_NAME)) {
         GTEST_SKIP();
     }
     assertRegistered(name, false);
@@ -222,7 +246,7 @@
     const std::string name = "ab012345678901234567890123456789c";
 
     assertRegistered(name, false);
-    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) {
+    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::BAD_SERVICE_NAME)) {
         GTEST_SKIP();
     }
     assertRegistered(name, false);
@@ -232,7 +256,9 @@
     const std::string name = mBusNames[0];
 
     assertRegistered(name, false);
-    if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP();
+    if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_INTERFACE_ID)) {
+        GTEST_SKIP();
+    }
     assertRegistered(name, false);
 }
 
@@ -240,10 +266,30 @@
     const std::string name = mBusNames[0];
 
     assertRegistered(name, false);
-    if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) {
+    if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_INTERFACE_ID)) {
         GTEST_SKIP();
     }
     assertRegistered(name, false);
+
+    auto supported =
+            up(InterfaceType::SOCKETCAN, name, "", ICanController::Result::BAD_INTERFACE_ID);
+    ASSERT_TRUE(supported);
+    assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadSlcanAddress) {
+    const std::string name = mBusNames[0];
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::SLCAN, name, "/dev/shouldnotexist123",
+            ICanController::Result::BAD_INTERFACE_ID)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, false);
+
+    auto supported = up(InterfaceType::SLCAN, name, "", ICanController::Result::BAD_INTERFACE_ID);
+    ASSERT_TRUE(supported);
+    assertRegistered(name, false);
 }
 
 }  // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
index 3c30744..383b54c 100644
--- a/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
@@ -35,8 +35,7 @@
 
 DEFINE_CAN_HAL_PRINTER(CanMessage, toString)
 DEFINE_CAN_HAL_PRINTER(ErrorEvent, toString)
-DEFINE_CAN_HAL_PRINTER_SIMPLE(
-        ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator, int)
+DEFINE_CAN_HAL_PRINTER(ICanController::BusConfig::InterfaceId, toString);
 DEFINE_CAN_HAL_PRINTER(ICanController::InterfaceType, toString)
 DEFINE_CAN_HAL_PRINTER(ICanController::Result, toString)
 DEFINE_CAN_HAL_PRINTER(Result, toString)
diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp
index c850c91..17f31e4 100644
--- a/automotive/evs/1.1/Android.bp
+++ b/automotive/evs/1.1/Android.bp
@@ -10,9 +10,11 @@
         "types.hal",
         "IEvsCamera.hal",
         "IEvsCameraStream.hal",
+        "IEvsDisplay.hal",
         "IEvsEnumerator.hal",
     ],
     interfaces: [
+        "android.frameworks.automotive.display@1.0",
         "android.hardware.automotive.evs@1.0",
         "android.hardware.camera.device@3.2",
         "android.hardware.graphics.common@1.0",
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
index fc68e60..38e6c42 100644
--- a/automotive/evs/1.1/IEvsCamera.hal
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -178,4 +178,41 @@
      *                values as backing camera devices.
      */
     getIntParameter(CameraParam id) generates(EvsResult result, vec<int32_t> value);
+
+    /**
+     * Request driver specific information from the HAL implementation.
+     *
+     * The values allowed for opaqueIdentifier are driver specific,
+     * but no value passed in may crash the driver. The driver should
+     * return EvsResult::INVALID_ARG for any unrecognized opaqueIdentifier.
+     *
+     * @param  opaqueIdentifier An unique identifier of the information to
+     *                          request.
+     * @return result           EvsResult::OK if the driver recognizes a given
+     *                          identifier.
+     *                          EvsResult::INVALID_ARG, otherwise.
+     * @return value            Requested information.  Zero-size vector is
+     *                          returned if the driver does not recognize a
+     *                          given identifier.
+     */
+    getExtendedInfo_1_1(uint32_t opaqueIdentifier)
+        generates (EvsResult result, vec<uint8_t> value);
+
+    /**
+     * Send a driver specific value to the HAL implementation.
+     *
+     * This extension is provided to facilitate car specific
+     * extensions, but no HAL implementation may require this call
+     * in order to function in a default state.
+     * INVALID_ARG is returned if the opaqueValue is not meaningful to
+     * the driver implementation.
+     *
+     * @param  opaqueIdentifier An unique identifier of the information to
+     *                          program.
+     *         opaqueValue      A value to program.
+     * @return result           EvsResult::OK is returned if this call is successful.
+     *                          EvsResult::INVALID_ARG, otherwise.
+     */
+    setExtendedInfo_1_1(uint32_t opaqueIdentifier, vec<uint8_t> opaqueValue)
+        generates (EvsResult result);
 };
diff --git a/automotive/evs/1.1/IEvsDisplay.hal b/automotive/evs/1.1/IEvsDisplay.hal
new file mode 100644
index 0000000..38da536
--- /dev/null
+++ b/automotive/evs/1.1/IEvsDisplay.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.evs@1.1;
+
+import @1.0::IEvsDisplay;
+import @1.0::EvsResult;
+import android.frameworks.automotive.display@1.0::HwDisplayConfig;
+import android.frameworks.automotive.display@1.0::HwDisplayState;
+
+/**
+ * Represents a single display.
+ */
+interface IEvsDisplay extends @1.0::IEvsDisplay {
+    /**
+     * Returns the description of this display.
+     *
+     * @return cfg   Current configuration of this display.
+     * @return state Current state of this display.
+     */
+    getDisplayInfo_1_1() generates (HwDisplayConfig cfg, HwDisplayState state);
+};
diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal
index 1695821..84dd21f 100644
--- a/automotive/evs/1.1/IEvsEnumerator.hal
+++ b/automotive/evs/1.1/IEvsEnumerator.hal
@@ -17,6 +17,7 @@
 package android.hardware.automotive.evs@1.1;
 
 import IEvsCamera;
+import IEvsDisplay;
 import @1.0::IEvsEnumerator;
 import @1.0::EvsResult;
 import android.hardware.camera.device@3.2::Stream;
@@ -47,4 +48,32 @@
      *                   configured differently by another client.
      */
     openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera);
+
+    /**
+     * Tells whether this is EVS manager or HAL implementation.
+     *
+     * @return result False for EVS manager implementations and true for all others.
+     */
+    isHardware() generates (bool result);
+
+    /**
+     * Returns a list of all EVS displays available to the system
+     *
+     * @return displayIds Identifiers of available displays.
+     */
+    getDisplayIdList() generates (vec<uint8_t> displayIds);
+
+    /**
+     * Get exclusive access to IEvsDisplay for the system
+     *
+     * There can be more than one EVS display objects for the system and this function
+     * requests access to the display identified by a given ID. If the target EVS display
+     * is not available or is already in use the old instance shall be closed and give
+     * the new caller exclusive access.
+     * When done using the display, the caller may release it by calling closeDisplay().
+     *
+     * @param  id      Target display identifier.
+     * @return display EvsDisplay object to be used.
+     */
+    openDisplay_1_1(uint8_t id) generates (IEvsDisplay display);
 };
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
index 88fd657..a35c9db 100644
--- a/automotive/evs/1.1/default/Android.bp
+++ b/automotive/evs/1.1/default/Android.bp
@@ -27,6 +27,10 @@
         "libutils",
         "libcamera_metadata",
         "libtinyxml2",
+        "android.hidl.token@1.0-utils",
+        "android.frameworks.automotive.display@1.0",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
     ],
 
     cflags: [
@@ -41,7 +45,7 @@
 
 prebuilt_etc {
     name: "evs_default_configuration.xml",
-
+    soc_specific: true,
     src: "resources/evs_default_configuration.xml",
     sub_dir: "automotive/evs",
 }
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
index b7e4efa..5196c95 100644
--- a/automotive/evs/1.1/default/EvsCamera.cpp
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -280,7 +280,7 @@
     return EvsResult::OK;
 }
 
-Return<EvsResult> EvsCamera::forceMaster(const sp<IEvsDisplay>& ) {
+Return<EvsResult> EvsCamera::forceMaster(const sp<IEvsDisplay_1_0>& ) {
     // Default implementation does not expect multiple subscribers and therefore
     // return a success code always.
     return EvsResult::OK;
@@ -334,6 +334,27 @@
 }
 
 
+Return<EvsResult> EvsCamera::setExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                                 const hidl_vec<uint8_t>& opaqueValue) {
+    // Default implementation does not use an extended info.
+    (void)opaqueIdentifier;
+    (void)opaqueValue;
+    return EvsResult::INVALID_ARG;
+}
+
+
+Return<void> EvsCamera::getExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                            getExtendedInfo_1_1_cb _hidl_cb) {
+    // Default implementation does not use an extended info.
+    (void)opaqueIdentifier;
+
+    hidl_vec<uint8_t> value;
+    _hidl_cb(EvsResult::INVALID_ARG, value);
+    return Void();
+}
+
+
+
 bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) {
     if (bufferCount < 1) {
         ALOGE("Ignoring request to set buffer count to zero");
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
index 72a1b57..0fa83b4 100644
--- a/automotive/evs/1.1/default/EvsCamera.h
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -20,7 +20,7 @@
 #include <android/hardware/automotive/evs/1.1/types.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
-#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
 #include <ui/GraphicBuffer.h>
 
 #include <thread>
@@ -33,7 +33,8 @@
 using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
 using ::android::hardware::automotive::evs::V1_0::CameraDesc;
-using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
 
 
 namespace android {
@@ -68,7 +69,7 @@
     Return<EvsResult> resumeVideoStream() override;
     Return<EvsResult> doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
     Return<EvsResult> setMaster() override;
-    Return<EvsResult> forceMaster(const sp<IEvsDisplay>& display) override;
+    Return<EvsResult> forceMaster(const sp<IEvsDisplay_1_0>& display) override;
     Return<EvsResult> unsetMaster() override;
     Return<void>      getParameterList(getParameterList_cb _hidl_cb) override;
     Return<void>      getIntParameterRange(CameraParam id,
@@ -77,6 +78,10 @@
                                       setIntParameter_cb _hidl_cb) override;
     Return<void>      getIntParameter(CameraParam id,
                                       getIntParameter_cb _hidl_cb) override;
+    Return<EvsResult> setExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                          const hidl_vec<uint8_t>& opaqueValue) override;
+    Return<void>      getExtendedInfo_1_1(uint32_t opaqueIdentifier,
+                                          getExtendedInfo_1_1_cb _hidl_cb) override;
 
     static sp<EvsCamera> Create(const char *deviceName);
     static sp<EvsCamera> Create(const char *deviceName,
diff --git a/automotive/evs/1.1/default/EvsDisplay.cpp b/automotive/evs/1.1/default/EvsDisplay.cpp
index 74c099a..2b5a4a9 100644
--- a/automotive/evs/1.1/default/EvsDisplay.cpp
+++ b/automotive/evs/1.1/default/EvsDisplay.cpp
@@ -21,6 +21,8 @@
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/GraphicBufferMapper.h>
 
+using ::android::frameworks::automotive::display::V1_0::HwDisplayConfig;
+using ::android::frameworks::automotive::display::V1_0::HwDisplayState;
 
 namespace android {
 namespace hardware {
@@ -31,6 +33,13 @@
 
 
 EvsDisplay::EvsDisplay() {
+    EvsDisplay(nullptr, 0);
+}
+
+
+EvsDisplay::EvsDisplay(sp<IAutomotiveDisplayProxyService> pDisplayProxy, uint64_t displayId)
+    : mDisplayProxy(pDisplayProxy),
+      mDisplayId(displayId) {
     ALOGD("EvsDisplay instantiated");
 
     // Set up our self description
@@ -327,6 +336,18 @@
 }
 
 
+Return<void> EvsDisplay::getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) {
+    if (mDisplayProxy != nullptr) {
+        return mDisplayProxy->getDisplayInfo(mDisplayId, _info_cb);
+    } else {
+        HwDisplayConfig nullConfig;
+        HwDisplayState  nullState;
+        _info_cb(nullConfig, nullState);
+        return Void();
+    }
+}
+
+
 } // namespace implementation
 } // namespace V1_1
 } // namespace evs
diff --git a/automotive/evs/1.1/default/EvsDisplay.h b/automotive/evs/1.1/default/EvsDisplay.h
index 2a56535..9b2ed90 100644
--- a/automotive/evs/1.1/default/EvsDisplay.h
+++ b/automotive/evs/1.1/default/EvsDisplay.h
@@ -17,14 +17,16 @@
 #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H
 #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H
 
-#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
 #include <ui/GraphicBuffer.h>
 
-using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
 using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
 using ::android::hardware::automotive::evs::V1_0::DisplayState;
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
 using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
 
 namespace android {
 namespace hardware {
@@ -43,9 +45,12 @@
     Return<void>         getTargetBuffer(getTargetBuffer_cb _hidl_cb)  override;
     Return<EvsResult>    returnTargetBufferForDisplay(const BufferDesc_1_0& buffer)  override;
 
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsDisplay follow.
+    Return<void>         getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) override;
 
     // Implementation details
     EvsDisplay();
+    EvsDisplay(sp<IAutomotiveDisplayProxyService> pDisplayProxy, uint64_t displayId);
     virtual ~EvsDisplay() override;
 
     void forceShutdown();   // This gets called if another caller "steals" ownership of the display
@@ -60,6 +65,9 @@
     DisplayState    mRequestedState = DisplayState::NOT_VISIBLE;
 
     std::mutex      mAccessLock;
+
+    sp<IAutomotiveDisplayProxyService> mDisplayProxy;
+    uint64_t                           mDisplayId;
 };
 
 } // namespace implementation
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
index a010729..0319560 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -34,18 +34,38 @@
 std::list<EvsEnumerator::CameraRecord>   EvsEnumerator::sCameraList;
 wp<EvsDisplay>                           EvsEnumerator::sActiveDisplay;
 unique_ptr<ConfigManager>                EvsEnumerator::sConfigManager;
+sp<IAutomotiveDisplayProxyService>       EvsEnumerator::sDisplayProxyService;
+std::unordered_map<uint8_t, uint64_t>    EvsEnumerator::sDisplayPortList;
 
 
-EvsEnumerator::EvsEnumerator() {
+EvsEnumerator::EvsEnumerator(sp<IAutomotiveDisplayProxyService> windowService) {
     ALOGD("EvsEnumerator created");
 
     // Add sample camera data to our list of cameras
     // In a real driver, this would be expected to can the available hardware
     sConfigManager =
-        ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml");
+        ConfigManager::Create("/vendor/etc/automotive/evs/evs_default_configuration.xml");
+
+    // Add available cameras
     for (auto v : sConfigManager->getCameraList()) {
         sCameraList.emplace_back(v.c_str());
     }
+
+    if (sDisplayProxyService == nullptr) {
+        /* sets a car-window service handle */
+        sDisplayProxyService = windowService;
+    }
+
+    // Add available displays
+    if (sDisplayProxyService != nullptr) {
+        // Get a display ID list.
+        sDisplayProxyService->getDisplayIdList([](const auto& displayIds) {
+            for (const auto& id : displayIds) {
+                const auto port = id & 0xF;
+                sDisplayPortList.insert_or_assign(port, id);
+            }
+        });
+    }
 }
 
 
@@ -165,7 +185,7 @@
 }
 
 
-Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay() {
+Return<sp<IEvsDisplay_1_0>> EvsEnumerator::openDisplay() {
     ALOGD("openDisplay");
 
     // If we already have a display active, then we need to shut it down so we can
@@ -185,7 +205,42 @@
 }
 
 
-Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& pDisplay) {
+Return<void> EvsEnumerator::getDisplayIdList(getDisplayIdList_cb _list_cb) {
+    hidl_vec<uint8_t> ids;
+
+    ids.resize(sDisplayPortList.size());
+    unsigned i = 0;
+    for (const auto& [port, id] : sDisplayPortList) {
+        ids[i++] = port;
+    }
+
+    _list_cb(ids);
+    return Void();
+}
+
+
+Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay_1_1(uint8_t port) {
+    ALOGD("%s", __FUNCTION__);
+
+    // If we already have a display active, then we need to shut it down so we can
+    // give exclusive access to the new caller.
+    sp<EvsDisplay> pActiveDisplay = sActiveDisplay.promote();
+    if (pActiveDisplay != nullptr) {
+        ALOGW("Killing previous display because of new caller");
+        closeDisplay(pActiveDisplay);
+    }
+
+    // Create a new display interface and return it
+    pActiveDisplay = new EvsDisplay(sDisplayProxyService, sDisplayPortList[port]);
+    sActiveDisplay = pActiveDisplay;
+
+    ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get());
+    return pActiveDisplay;
+}
+
+
+
+Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay_1_0>& pDisplay) {
     ALOGD("closeDisplay");
 
     // Do we still have a display object we think should be active?
diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h
index 475ec76..9415953 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.h
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -19,19 +19,22 @@
 
 #include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/frameworks/automotive/display/1.0/IAutomotiveDisplayProxyService.h>
 
 #include <list>
 
 #include "ConfigManager.h"
 
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
 using ::android::hardware::automotive::evs::V1_0::DisplayState;
 using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
 using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
 using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
 using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
-
+using IEvsDisplay_1_0  = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1  = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+using android::frameworks::automotive::display::V1_0::IAutomotiveDisplayProxyService;
 
 namespace android {
 namespace hardware {
@@ -51,17 +54,20 @@
     Return<void>                getCameraList(getCameraList_cb _hidl_cb)  override;
     Return<sp<IEvsCamera_1_0>>  openCamera(const hidl_string& cameraId) override;
     Return<void>                closeCamera(const ::android::sp<IEvsCamera_1_0>& carCamera)  override;
-    Return<sp<IEvsDisplay>>     openDisplay()  override;
-    Return<void>                closeDisplay(const ::android::sp<IEvsDisplay>& display)  override;
+    Return<sp<IEvsDisplay_1_0>> openDisplay()  override;
+    Return<void>                closeDisplay(const ::android::sp<IEvsDisplay_1_0>& display)  override;
     Return<DisplayState>        getDisplayState()  override;
 
     // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
     Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb)  override;
     Return<sp<IEvsCamera_1_1>>  openCamera_1_1(const hidl_string& cameraId,
                                                const Stream& streamCfg) override;
+    Return<bool> isHardware() override { return true; }
+    Return<void>                getDisplayIdList(getDisplayIdList_cb _list_cb) override;
+    Return<sp<IEvsDisplay_1_1>> openDisplay_1_1(uint8_t port) override;
 
     // Implementation details
-    EvsEnumerator();
+    EvsEnumerator(sp<IAutomotiveDisplayProxyService> windowService = nullptr);
 
 private:
     // NOTE:  All members values are static so that all clients operate on the same state
@@ -82,6 +88,10 @@
     static wp<EvsDisplay>            sActiveDisplay;
 
     static unique_ptr<ConfigManager> sConfigManager;
+
+    static sp<IAutomotiveDisplayProxyService> sDisplayProxyService;
+    static std::unordered_map<uint8_t,
+                              uint64_t> sDisplayPortList;
 };
 
 } // namespace implementation
diff --git a/automotive/evs/1.1/default/ServiceNames.h b/automotive/evs/1.1/default/ServiceNames.h
index 1178da5..84b1697 100644
--- a/automotive/evs/1.1/default/ServiceNames.h
+++ b/automotive/evs/1.1/default/ServiceNames.h
@@ -14,4 +14,4 @@
  * limitations under the License.
  */
 
-const static char kEnumeratorServiceName[] = "EvsEnumeratorHw";
+const static char kEnumeratorServiceName[] = "hw/0";
diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp
index 5135864..374b646 100644
--- a/automotive/evs/1.1/default/service.cpp
+++ b/automotive/evs/1.1/default/service.cpp
@@ -34,7 +34,6 @@
 
 // Generated HIDL files
 using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
-using android::hardware::automotive::evs::V1_0::IEvsDisplay;
 
 // The namespace in which all our implementation code lives
 using namespace android::hardware::automotive::evs::V1_1::implementation;
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
index f88d223..aafdb70 100644
--- a/automotive/evs/1.1/types.hal
+++ b/automotive/evs/1.1/types.hal
@@ -69,6 +69,8 @@
      * Time that this buffer is being filled.
      */
     int64_t timestamp;
+
+    vec<uint8_t> metadata;
 };
 
 /**
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 4fc4e4c..2c8c1e1 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -54,9 +54,11 @@
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
 #include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <system/camera_metadata.h>
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.h>
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
@@ -76,6 +78,8 @@
 using ::android::hardware::graphics::common::V1_0::PixelFormat;
 using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
 using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
 
 /*
  * Plese note that this is different from what is defined in
@@ -117,7 +121,7 @@
         pEnumerator = getService<IEvsEnumerator>(service_name);
         ASSERT_NE(pEnumerator.get(), nullptr);
 
-        mIsHwModule = !service_name.compare(kEnumeratorName);
+        mIsHwModule = pEnumerator->isHardware();
     }
 
     virtual void TearDown() override {
@@ -292,6 +296,17 @@
                                     }
             );
 
+            // Verify methods for extended info
+            const auto id = 0xFFFFFFFF; // meaningless id
+            hidl_vec<uint8_t> values;
+            auto err = pCam->setExtendedInfo_1_1(id, values);
+            ASSERT_EQ(EvsResult::INVALID_ARG, err);
+
+            pCam->getExtendedInfo_1_1(id, [](const auto& result, const auto& data) {
+                ASSERT_EQ(EvsResult::INVALID_ARG, result);
+                ASSERT_EQ(0, data.size());
+            });
+
             // Explicitly close the camera so resources are released right away
             pEnumerator->closeCamera(pCam);
         }
@@ -567,9 +582,30 @@
     // output format.
     Stream nullCfg = {};
 
-    // Request exclusive access to the EVS display
-    sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+    // Request available display IDs
+    uint8_t targetDisplayId = 0;
+    pEnumerator->getDisplayIdList([&targetDisplayId](auto ids) {
+        ASSERT_GT(ids.size(), 0);
+        targetDisplayId = ids[0];
+    });
+
+    // Request exclusive access to the first EVS display
+    sp<IEvsDisplay_1_1> pDisplay = pEnumerator->openDisplay_1_1(targetDisplayId);
     ASSERT_NE(pDisplay, nullptr);
+    ALOGI("Display %d is in use.", targetDisplayId);
+
+    // Get the display descriptor
+    pDisplay->getDisplayInfo_1_1([](const auto& config, const auto& state) {
+        android::DisplayConfig* pConfig = (android::DisplayConfig*)config.data();
+        const auto width = pConfig->resolution.getWidth();
+        const auto height = pConfig->resolution.getHeight();
+        ALOGI("    Resolution: %dx%d", width, height);
+        ASSERT_GT(width, 0);
+        ASSERT_GT(height, 0);
+
+        android::ui::DisplayState* pState = (android::ui::DisplayState*)state.data();
+        ASSERT_NE(pState->layerStack, -1);
+    });
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
@@ -1556,7 +1592,7 @@
     Stream nullCfg = {};
 
     // Request exclusive access to the EVS display
-    sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+    sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
     ASSERT_NE(pDisplay, nullptr);
 
     // Test each reported camera
@@ -1920,7 +1956,7 @@
     loadCameraList();
 
     // Request exclusive access to the EVS display
-    sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+    sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
     ASSERT_NE(pDisplay, nullptr);
 
     // Test each reported camera
diff --git a/automotive/evs/1.1/vts/fuzzing/Android.bp b/automotive/evs/1.1/vts/fuzzing/Android.bp
new file mode 100644
index 0000000..48427ee
--- /dev/null
+++ b/automotive/evs/1.1/vts/fuzzing/Android.bp
@@ -0,0 +1,50 @@
+//
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+    name: "android.hardware.automotive.evs@fuzz-defaults",
+    defaults: ["VtsHalTargetTestDefaults"],
+    shared_libs: [
+        "libui",
+        "libcamera_metadata",
+    ],
+    static_libs: [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.evs@common-default-lib",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.camera.device@3.2",
+    ],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
+
+cc_fuzz {
+    name: "VtsHalEvsV1_1CameraOpenFuzz",
+    defaults: ["android.hardware.automotive.evs@fuzz-defaults"],
+    srcs: [
+        "VtsHalEvsV1_1CameraOpenFuzz.cpp",
+    ],
+    fuzz_config: {
+        // wait for Haiku device ready
+        fuzz_on_haiku_device: false,
+        fuzz_on_haiku_host: false,
+    },
+}
diff --git a/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp b/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp
new file mode 100644
index 0000000..4f05d21
--- /dev/null
+++ b/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
+using ::android::hardware::camera::device::V3_2::Stream;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
+    UNUSED(argc);
+    UNUSED(argv);
+    pEnumerator = IEvsEnumerator::getService(kEnumeratorName);
+    sp<EvsDeathRecipient> dr = new EvsDeathRecipient();
+
+    pEnumerator->linkToDeath(dr, 0);
+
+    loadCameraList();
+    return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+
+    std::vector<sp<IEvsCamera_1_1>> camList;
+    Stream nullCfg = {};
+
+    while (fdp.remaining_bytes() > 4) {
+        switch (fdp.ConsumeIntegralInRange<uint32_t>(0, 3)) {
+            case 0:  // open camera
+            {
+                uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, cameraInfo.size() - 1);
+                sp<IEvsCamera_1_1> pCam =
+                        IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(
+                                                         cameraInfo[whichCam].v1.cameraId, nullCfg))
+                                .withDefault(nullptr);
+                camList.emplace_back(pCam);
+                break;
+            }
+            case 1:  // close camera
+            {
+                if (!camList.empty()) {
+                    uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, camList.size() - 1);
+                    pEnumerator->closeCamera(camList[whichCam]);
+                }
+                break;
+            }
+            case 2:  // get camera info
+            {
+                if (!camList.empty()) {
+                    uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, camList.size() - 1);
+                    camList[whichCam]->getCameraInfo_1_1([](CameraDesc desc) { UNUSED(desc); });
+                }
+                break;
+            }
+            case 3:  // setMaxFramesInFlight
+            {
+                if (!camList.empty()) {
+                    uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, camList.size() - 1);
+                    int32_t numFrames = fdp.ConsumeIntegral<int32_t>();
+                    camList[whichCam]->setMaxFramesInFlight(numFrames);
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    return 0;
+}
diff --git a/automotive/evs/1.1/vts/fuzzing/common.h b/automotive/evs/1.1/vts/fuzzing/common.h
new file mode 100644
index 0000000..af6fd54
--- /dev/null
+++ b/automotive/evs/1.1/vts/fuzzing/common.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalEvsTest"
+#define UNUSED(x) (void)(x)
+
+const static char kEnumeratorName[] = "EvsEnumeratorHw";
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/StrongPointer.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+
+using ::android::sp;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_vec;
+
+static sp<IEvsEnumerator> pEnumerator;
+static std::vector<CameraDesc> cameraInfo;
+
+class EvsDeathRecipient : public hidl_death_recipient {
+  public:
+    void serviceDied(uint64_t /*cookie*/,
+                     const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
+        abort();
+    }
+};
+
+void loadCameraList() {
+    // SetUp() must run first!
+    assert(pEnumerator != nullptr);
+
+    // Get the camera list
+    pEnumerator->getCameraList_1_1([](hidl_vec<CameraDesc> cameraList) {
+        ALOGI("Camera list callback received %zu cameras", cameraList.size());
+        cameraInfo.reserve(cameraList.size());
+        for (auto&& cam : cameraList) {
+            ALOGI("Found camera %s", cam.v1.cameraId.c_str());
+            cameraInfo.push_back(cam);
+        }
+    });
+}
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index a94a37e..8e57901 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -47,6 +47,9 @@
         "common/src/VehicleUtils.cpp",
         "common/src/VmsUtils.cpp",
     ],
+    shared_libs: [
+        "libbase",
+    ],
     local_include_dirs: ["common/include/vhal_v2_0"],
     export_include_dirs: ["common/include"],
 }
@@ -82,20 +85,6 @@
     ],
 }
 
-// VHal virtualization utils
-cc_library_static {
-    name: "android.hardware.automotive.vehicle@2.0-virtualization-utils",
-    vendor: true,
-    defaults: ["vhal_v2_0_defaults"],
-    srcs: [
-        "impl/vhal_v2_0/virtualization/Utils.cpp",
-    ],
-    export_include_dirs: ["impl"],
-    shared_libs: [
-        "libbase",
-    ],
-}
-
 cc_test {
     name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests",
     vendor: true,
@@ -109,6 +98,9 @@
         "tests/VehiclePropConfigIndex_test.cpp",
         "tests/VmsUtils_test.cpp",
     ],
+    shared_libs: [
+        "libbase",
+    ],
     header_libs: ["libbase_headers"],
     test_suites: ["general-tests"],
 }
@@ -147,59 +139,3 @@
         "libqemu_pipe",
     ],
 }
-
-cc_binary {
-    name: "android.hardware.automotive.vehicle@2.0-virtualization-service",
-    defaults: ["vhal_v2_0_defaults"],
-    init_rc: ["android.hardware.automotive.vehicle@2.0-virtualization-service.rc"],
-    vendor: true,
-    relative_install_path: "hw",
-    srcs: [
-        "impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp",
-        "VirtualizedVehicleService.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "libcutils",
-        "libjsoncpp",
-        "libprotobuf-cpp-full",
-        "libgrpc++",
-    ],
-    static_libs: [
-        "android.hardware.automotive.vehicle@2.0-manager-lib",
-        "android.hardware.automotive.vehicle@2.0-default-impl-lib",
-        "android.hardware.automotive.vehicle@2.0-grpc",
-        "android.hardware.automotive.vehicle@2.0-virtualization-utils",
-        "libqemu_pipe",
-    ],
-    cflags: [
-        "-Wno-unused-parameter"
-    ],
-}
-
-cc_binary {
-    name: "android.hardware.automotive.vehicle@2.0-virtualization-grpc-server",
-    init_rc: ["android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc"],
-    defaults: ["vhal_v2_0_defaults"],
-    vendor: true,
-    relative_install_path: "hw",
-    srcs: [
-        "impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp",
-        "VirtualizationGrpcServer.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "libjsoncpp",
-        "libprotobuf-cpp-full",
-        "libgrpc++",
-    ],
-    static_libs: [
-        "android.hardware.automotive.vehicle@2.0-manager-lib",
-        "android.hardware.automotive.vehicle@2.0-default-impl-lib",
-        "android.hardware.automotive.vehicle@2.0-grpc",
-        "android.hardware.automotive.vehicle@2.0-virtualization-utils",
-    ],
-    cflags: [
-        "-Wno-unused-parameter"
-    ],
-}
diff --git a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp
deleted file mode 100644
index cca65d9..0000000
--- a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <android-base/logging.h>
-#include <getopt.h>
-#include <unistd.h>
-
-#include "vhal_v2_0/virtualization/GrpcVehicleServer.h"
-#include "vhal_v2_0/virtualization/Utils.h"
-
-int main(int argc, char* argv[]) {
-    namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl;
-
-    vhal_impl::VsockServerInfo serverInfo;
-
-    // unique values to identify the options
-    constexpr int OPT_VHAL_SERVER_CID = 1001;
-    constexpr int OPT_VHAL_SERVER_PORT_NUMBER = 1002;
-
-    struct option longOptions[] = {
-            {"server_cid", 1, 0, OPT_VHAL_SERVER_CID},
-            {"server_port", 1, 0, OPT_VHAL_SERVER_PORT_NUMBER},
-            {nullptr, 0, nullptr, 0},
-    };
-
-    int optValue;
-    while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) {
-        switch (optValue) {
-            case OPT_VHAL_SERVER_CID:
-                serverInfo.serverCid = std::atoi(optarg);
-                LOG(DEBUG) << "Vehicle HAL server CID: " << serverInfo.serverCid;
-                break;
-            case OPT_VHAL_SERVER_PORT_NUMBER:
-                serverInfo.serverPort = std::atoi(optarg);
-                LOG(DEBUG) << "Vehicle HAL server port: " << serverInfo.serverPort;
-                break;
-            default:
-                // ignore other options
-                break;
-        }
-    }
-
-    if (serverInfo.serverCid == 0 || serverInfo.serverPort == 0) {
-        LOG(FATAL) << "Invalid server information, CID: " << serverInfo.serverCid
-                   << "; port: " << serverInfo.serverPort;
-        // Will abort after logging
-    }
-
-    auto server = vhal_impl::makeGrpcVehicleServer(vhal_impl::getVsockUri(serverInfo));
-    server->Start();
-    return 0;
-}
diff --git a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp
deleted file mode 100644
index 1de81ae..0000000
--- a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <cutils/properties.h>
-#include <hidl/HidlTransportSupport.h>
-
-#include <vhal_v2_0/EmulatedVehicleConnector.h>
-#include <vhal_v2_0/EmulatedVehicleHal.h>
-#include <vhal_v2_0/VehicleHalManager.h>
-#include <vhal_v2_0/virtualization/GrpcVehicleClient.h>
-#include <vhal_v2_0/virtualization/Utils.h>
-
-using namespace android;
-using namespace android::hardware;
-using namespace android::hardware::automotive::vehicle::V2_0;
-
-int main(int argc, char* argv[]) {
-    constexpr const char* VHAL_SERVER_CID_PROPERTY_KEY = "ro.vendor.vehiclehal.server.cid";
-    constexpr const char* VHAL_SERVER_PORT_PROPERTY_KEY = "ro.vendor.vehiclehal.server.port";
-
-    auto property_get_uint = [](const char* key, unsigned int default_value) {
-        auto value = property_get_int64(key, default_value);
-        if (value < 0 || value > UINT_MAX) {
-            LOG(DEBUG) << key << ": " << value << " is out of bound, using default value '"
-                       << default_value << "' instead";
-            return default_value;
-        }
-        return static_cast<unsigned int>(value);
-    };
-
-    impl::VsockServerInfo serverInfo{property_get_uint(VHAL_SERVER_CID_PROPERTY_KEY, 0),
-                                     property_get_uint(VHAL_SERVER_PORT_PROPERTY_KEY, 0)};
-
-    if (serverInfo.serverCid == 0 || serverInfo.serverPort == 0) {
-        LOG(FATAL) << "Invalid server information, CID: " << serverInfo.serverCid
-                   << "; port: " << serverInfo.serverPort;
-        // Will abort after logging
-    }
-
-    auto store = std::make_unique<VehiclePropertyStore>();
-    auto connector = impl::makeGrpcVehicleClient(impl::getVsockUri(serverInfo));
-    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get());
-    auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
-    auto service = std::make_unique<VehicleHalManager>(hal.get());
-
-    configureRpcThreadpool(4, true /* callerWillJoin */);
-
-    LOG(INFO) << "Registering as service...";
-    status_t status = service->registerAsService();
-
-    if (status != OK) {
-        LOG(ERROR) << "Unable to register vehicle service (" << status << ")";
-        return 1;
-    }
-
-    LOG(INFO) << "Ready";
-    joinRpcThreadpool();
-
-    return 1;
-}
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc
deleted file mode 100644
index 29147ad..0000000
--- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc
+++ /dev/null
@@ -1,10 +0,0 @@
-# It is an interim state to run GRPC server as an Android service.
-# Eventually it will run outside of Android (e.g., AGL),
-# so the command line arguments are expected, though not conventionally used in Android
-service vendor.vehicle-hal-2.0-server \
-        /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server \
-        -server_cid ${ro.vendor.vehiclehal.server.cid:-0} \
-        -server_port ${ro.vendor.vehiclehal.server.port:-0}
-    class hal
-    user vehicle_network
-    group system inet
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc
deleted file mode 100644
index 234de59..0000000
--- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-service.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service vendor.vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-service
-    class hal
-    user vehicle_network
-    group system inet
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
index d40f122..00b5afe 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
@@ -65,6 +65,12 @@
     // updateStatus is true if and only if the value is
     // generated by car (ECU/fake generator/injected)
     virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0;
+
+    // Dump method forwarded from HIDL's debug()
+    // If implemented, it must return whether the caller should dump its state.
+    virtual bool dump(const hidl_handle& /* handle */, const hidl_vec<hidl_string>& /* options */) {
+        return true;
+    }
 };
 
 /**
@@ -97,6 +103,13 @@
     // updateStatus is true if and only if the value is
     // generated by car (ECU/fake generator/injected)
     virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0;
+
+    // Dump method forwarded from HIDL's debug()
+    // If implemented, it must return whether the caller should dump its state.
+    virtual bool onDump(const hidl_handle& /* handle */,
+                        const hidl_vec<hidl_string>& /* options */) {
+        return true;
+    }
 };
 
 /**
@@ -134,6 +147,10 @@
         return this->onPropertyValue(value, updateStatus);
     }
 
+    bool dump(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override {
+        return this->onDump(handle, options);
+    }
+
     // To be implemented:
     // virtual std::vector<VehiclePropConfig> onGetAllPropertyConfig() = 0;
     // virtual void onPropertyValue(const VehiclePropValue& value) = 0;
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
index fd28483..fe01867 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
@@ -70,6 +70,26 @@
      */
     virtual void onCreate() {}
 
+    /**
+     * Dump method forwarded from HIDL's debug().
+     *
+     * By default it doesn't dump anything and let caller dump its properties, but it could be
+     * override to change the behavior. For example:
+     *
+     * - To augment caller's dump, it should dump its state and return true.
+     * - To not dump anything at all, it should just return false.
+     * - To provide custom dump (like dumping just specific state or executing a custom command),
+     *   it should check if options is not empty, handle the options accordingly, then return false.
+     *
+     * @param handle handle used to dump the contents.
+     * @param options options passed to dump.
+     *
+     * @return whether the caller should dump its state.
+     */
+    virtual bool dump(const hidl_handle& /* handle */, const hidl_vec<hidl_string>& /* options */) {
+        return true;
+    }
+
     void init(
         VehiclePropValuePool* valueObjectPool,
         const HalEventFunction& onHalEvent,
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
index c1e9e88..fcfe761 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
@@ -73,7 +73,9 @@
                                    int32_t propId)  override;
     Return<void> debugDump(debugDump_cb _hidl_cb = nullptr) override;
 
-private:
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
+
+  private:
     using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr;
     // Returns true if needs to call again shortly.
     using RetriableAction = std::function<bool()>;
@@ -96,6 +98,22 @@
     bool checkReadPermission(const VehiclePropConfig &config) const;
     void onAllClientsUnsubscribed(int32_t propertyId);
 
+    // Dump and commands
+    // TODO: most functions below (exception dump() and cmdSetOne()) should be const, but they rely
+    // on IVehicle.get(), which isn't...
+    void cmdDump(int fd, const hidl_vec<hidl_string>& options);
+    void cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId);
+    void cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config);
+
+    static bool checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options, size_t minSize);
+    static bool checkCallerHasWritePermissions(int fd);
+    static bool safelyParseInt(int fd, int index, std::string s, int* out);
+    void cmdHelp(int fd) const;
+    void cmdListAllProperties(int fd) const;
+    void cmdDumpAllProperties(int fd);
+    void cmdDumpSpecificProperties(int fd, const hidl_vec<hidl_string>& options);
+    void cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options);
+
     static bool isSubscribable(const VehiclePropConfig& config,
                                SubscribeFlags flags);
     static bool isSampleRateFixed(VehiclePropertyChangeMode mode);
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index 393d3ec..5bebd1e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -21,11 +21,20 @@
 #include <cmath>
 #include <fstream>
 
-#include <android/log.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
 #include <android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h>
+#include <android/log.h>
+
+#include <hwbinder/IPCThreadState.h>
+
+#include <utils/SystemClock.h>
 
 #include "VehicleUtils.h"
 
+// TODO: figure out how to include private/android_filesystem_config.h instead...
+#define AID_ROOT 0 /* traditional unix root user */
+
 namespace android {
 namespace hardware {
 namespace automotive {
@@ -34,6 +43,10 @@
 
 using namespace std::placeholders;
 
+using ::android::base::EqualsIgnoreCase;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+
 constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10);
 
 const VehiclePropValue kEmptyValue{};
@@ -172,6 +185,251 @@
     return Void();
 }
 
+Return<void> VehicleHalManager::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds == 0) {
+        ALOGE("Invalid parameters passed to debug()");
+        return Void();
+    }
+
+    bool shouldContinue = mHal->dump(fd, options);
+    if (!shouldContinue) {
+        ALOGI("Dumped HAL only");
+        return Void();
+    }
+
+    // Do our dump
+    cmdDump(fd->data[0], options);
+    return Void();
+}
+
+void VehicleHalManager::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
+    if (options.size() == 0) {
+        cmdDumpAllProperties(fd);
+        return;
+    }
+    std::string option = options[0];
+    if (EqualsIgnoreCase(option, "--help")) {
+        cmdHelp(fd);
+    } else if (EqualsIgnoreCase(option, "--list")) {
+        cmdListAllProperties(fd);
+    } else if (EqualsIgnoreCase(option, "--get")) {
+        cmdDumpSpecificProperties(fd, options);
+    } else if (EqualsIgnoreCase(option, "--set")) {
+        cmdSetOneProperty(fd, options);
+    } else {
+        dprintf(fd, "Invalid option: %s\n", option.c_str());
+    }
+}
+
+bool VehicleHalManager::checkCallerHasWritePermissions(int fd) {
+    // Double check that's only called by root - it should be be blocked at the HIDL debug() level,
+    // but it doesn't hurt to make sure...
+    if (hardware::IPCThreadState::self()->getCallingUid() != AID_ROOT) {
+        dprintf(fd, "Must be root\n");
+        return false;
+    }
+    return true;
+}
+
+bool VehicleHalManager::checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options,
+                                           size_t minSize) {
+    size_t size = options.size();
+    if (size >= minSize) {
+        return true;
+    }
+    dprintf(fd, "Invalid number of arguments: required at least %zu, got %zu\n", minSize, size);
+    return false;
+}
+
+bool VehicleHalManager::safelyParseInt(int fd, int index, std::string s, int* out) {
+    if (!android::base::ParseInt(s, out)) {
+        dprintf(fd, "non-integer argument at index %d: %s\n", index, s.c_str());
+        return false;
+    }
+    return true;
+}
+
+void VehicleHalManager::cmdHelp(int fd) const {
+    dprintf(fd, "Usage: \n\n");
+    dprintf(fd, "[no args]: dumps (id and value) all supported properties \n");
+    dprintf(fd, "--help: shows this help\n");
+    dprintf(fd, "--list: lists the ids of all supported properties\n");
+    dprintf(fd, "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n");
+    // TODO: support other formats (int64, float, bytes)
+    dprintf(fd,
+            "--set <PROP> <i|s> <VALUE_1> [<i|s> <VALUE_N>] [a AREA_ID] : sets the value of "
+            "property PROP, using arbitrary number of key/value parameters (i for int32, "
+            "s for string) and an optional area.\n"
+            "Notice that the string value can be set just once, while the other can have multiple "
+            "values (so they're used in the respective array)\n");
+}
+
+void VehicleHalManager::cmdListAllProperties(int fd) const {
+    auto& halConfig = mConfigIndex->getAllConfigs();
+    size_t size = halConfig.size();
+    if (size == 0) {
+        dprintf(fd, "no properties to list\n");
+        return;
+    }
+    int i = 0;
+    dprintf(fd, "listing %zu properties\n", size);
+    for (const auto& config : halConfig) {
+        dprintf(fd, "%d: %d\n", ++i, config.prop);
+    }
+}
+
+void VehicleHalManager::cmdDumpAllProperties(int fd) {
+    auto& halConfig = mConfigIndex->getAllConfigs();
+    size_t size = halConfig.size();
+    if (size == 0) {
+        dprintf(fd, "no properties to dump\n");
+        return;
+    }
+    int rowNumber = 0;
+    dprintf(fd, "dumping %zu properties\n", size);
+    for (auto& config : halConfig) {
+        cmdDumpOneProperty(fd, ++rowNumber, config);
+    }
+}
+
+void VehicleHalManager::cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config) {
+    size_t numberAreas = config.areaConfigs.size();
+    if (numberAreas == 0) {
+        if (rowNumber > 0) {
+            dprintf(fd, "%d: ", rowNumber);
+        }
+        cmdDumpOneProperty(fd, config.prop, /* areaId= */ 0);
+        return;
+    }
+    for (size_t j = 0; j < numberAreas; ++j) {
+        if (rowNumber > 0) {
+            if (numberAreas > 1) {
+                dprintf(fd, "%d/%zu: ", rowNumber, j);
+            } else {
+                dprintf(fd, "%d: ", rowNumber);
+            }
+        }
+        cmdDumpOneProperty(fd, config.prop, config.areaConfigs[j].areaId);
+    }
+}
+
+void VehicleHalManager::cmdDumpSpecificProperties(int fd, const hidl_vec<hidl_string>& options) {
+    if (!checkArgumentsSize(fd, options, 2)) return;
+
+    // options[0] is the command itself...
+    int rowNumber = 0;
+    size_t size = options.size();
+    for (size_t i = 1; i < size; ++i) {
+        int prop;
+        if (!safelyParseInt(fd, i, options[i], &prop)) return;
+        const auto* config = getPropConfigOrNull(prop);
+        if (config == nullptr) {
+            dprintf(fd, "No property %d\n", prop);
+            continue;
+        }
+        if (size > 2) {
+            // Only show row number if there's more than 1
+            rowNumber++;
+        }
+        cmdDumpOneProperty(fd, rowNumber, *config);
+    }
+}
+
+void VehicleHalManager::cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId) {
+    VehiclePropValue input;
+    input.prop = prop;
+    input.areaId = areaId;
+    auto callback = [&](StatusCode status, const VehiclePropValue& output) {
+        if (status == StatusCode::OK) {
+            dprintf(fd, "%s\n", toString(output).c_str());
+        } else {
+            dprintf(fd, "Could not get property %d. Error: %s\n", prop, toString(status).c_str());
+        }
+    };
+    get(input, callback);
+}
+
+void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) {
+    if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return;
+
+    size_t size = options.size();
+
+    // Syntax is --set PROP Type1 Value1 TypeN ValueN, so number of arguments must be even
+    if (size % 2 != 0) {
+        dprintf(fd, "must pass even number of arguments (passed %zu)\n", size);
+        return;
+    }
+    int numberValues = (size - 2) / 2;
+
+    VehiclePropValue prop;
+    if (!safelyParseInt(fd, 1, options[1], &prop.prop)) return;
+    prop.timestamp = elapsedRealtimeNano();
+    prop.status = VehiclePropertyStatus::AVAILABLE;
+
+    // First pass: calculate sizes
+    int sizeInt32 = 0;
+    int stringIndex = 0;
+    int areaIndex = 0;
+    for (int i = 2, kv = 1; kv <= numberValues; kv++) {
+        // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step
+        std::string type = options[i];
+        std::string value = options[i + 1];
+        if (EqualsIgnoreCase(type, "i")) {
+            sizeInt32++;
+        } else if (EqualsIgnoreCase(type, "s")) {
+            if (stringIndex != 0) {
+                dprintf(fd,
+                        "defining string value (%s) again at index %d (already defined at %d=%s"
+                        ")\n",
+                        value.c_str(), i, stringIndex, options[stringIndex + 1].c_str());
+                return;
+            }
+            stringIndex = i;
+        } else if (EqualsIgnoreCase(type, "a")) {
+            if (areaIndex != 0) {
+                dprintf(fd,
+                        "defining area value (%s) again at index %d (already defined at %d=%s"
+                        ")\n",
+                        value.c_str(), i, areaIndex, options[areaIndex + 1].c_str());
+                return;
+            }
+            areaIndex = i;
+        } else {
+            dprintf(fd, "invalid (%s) type at index %d\n", type.c_str(), i);
+            return;
+        }
+        i += 2;
+    }
+    prop.value.int32Values.resize(sizeInt32);
+
+    // Second pass: populate it
+    int indexInt32 = 0;
+    for (int i = 2, kv = 1; kv <= numberValues; kv++) {
+        // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step
+        int valueIndex = i + 1;
+        std::string type = options[i];
+        std::string value = options[valueIndex];
+        if (EqualsIgnoreCase(type, "i")) {
+            int safeInt;
+            if (!safelyParseInt(fd, valueIndex, value, &safeInt)) return;
+            prop.value.int32Values[indexInt32++] = safeInt;
+        } else if (EqualsIgnoreCase(type, "s")) {
+            prop.value.stringValue = value;
+        } else if (EqualsIgnoreCase(type, "a")) {
+            if (!safelyParseInt(fd, valueIndex, value, &prop.areaId)) return;
+        }
+        i += 2;
+    }
+    ALOGD("Setting prop %s", toString(prop).c_str());
+    auto status = set(prop);
+    if (status == StatusCode::OK) {
+        dprintf(fd, "Set property %s\n", toString(prop).c_str());
+    } else {
+        dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(),
+                toString(status).c_str());
+    }
+}
+
 void VehicleHalManager::init() {
     ALOGI("VehicleHalManager::init");
 
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 bf85da2..785f0e0 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
@@ -76,6 +76,7 @@
 constexpr int WHEEL_FRONT_RIGHT = (int)VehicleAreaWheel::RIGHT_FRONT;
 constexpr int WHEEL_REAR_LEFT = (int)VehicleAreaWheel::LEFT_REAR;
 constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR;
+constexpr int INITIAL_USER_INFO = (int)VehicleProperty::INITIAL_USER_INFO;
 
 /**
  * This property is used for test purpose to generate fake events. Here is the test package that
@@ -87,23 +88,23 @@
 /**
  * This property is used for test purpose to set properties' value from vehicle.
  * For example: Mocking hard button press triggering a HVAC fan speed change.
- * Android set kSetPropertyFromVehcileForTest with an array of integer {HVAC_FAN_SPEED, value of
+ * Android set kSetPropertyFromVehicleForTest with an array of integer {HVAC_FAN_SPEED, value of
  * fan speed} and a long value indicates the timestamp of the events .
  * It only works with integer type properties.
  */
-const int32_t kSetIntPropertyFromVehcileForTest =
+const int32_t kSetIntPropertyFromVehicleForTest =
         0x1112 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
 /**
  * This property is used for test purpose to set properties' value from vehicle.
  * It only works with float type properties.
  */
-const int32_t kSetFloatPropertyFromVehcileForTest =
+const int32_t kSetFloatPropertyFromVehicleForTest =
         0x1113 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
 /**
  * This property is used for test purpose to set properties' value from vehicle.
  * It only works with boolean type properties.
  */
-const int32_t kSetBooleanPropertyFromVehcileForTest =
+const int32_t kSetBooleanPropertyFromVehicleForTest =
         0x1114 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
 
 /**
@@ -695,7 +696,7 @@
         {
                 .config =
                         {
-                                .prop = kSetIntPropertyFromVehcileForTest,
+                                .prop = kSetIntPropertyFromVehicleForTest,
                                 .access = VehiclePropertyAccess::WRITE,
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                                 .configArray = {0, 0, 0, 2, 1, 0, 0, 0, 0},
@@ -705,7 +706,7 @@
         {
                 .config =
                         {
-                                .prop = kSetFloatPropertyFromVehcileForTest,
+                                .prop = kSetFloatPropertyFromVehicleForTest,
                                 .access = VehiclePropertyAccess::WRITE,
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                                 .configArray = {0, 0, 1, 0, 1, 0, 1, 0, 0},
@@ -715,7 +716,7 @@
         {
                 .config =
                         {
-                                .prop = kSetBooleanPropertyFromVehcileForTest,
+                                .prop = kSetBooleanPropertyFromVehicleForTest,
                                 .access = VehiclePropertyAccess::WRITE,
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                                 .configArray = {0, 1, 1, 0, 1, 0, 0, 0, 0},
@@ -990,6 +991,16 @@
                                   (int)VehicleVendorPermission::PERMISSION_DEFAULT},
                  },
          .initialValue = {.int32Values = {1}}},
+
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+                                .access = VehiclePropertyAccess::READ_WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
index 222fe5e..7f90914 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
@@ -13,6 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#define LOG_TAG "automotive.vehicle@2.0-connector"
+
+#include <fstream>
+
 #include <android-base/logging.h>
 #include <utils/SystemClock.h>
 
@@ -202,8 +207,8 @@
         case kGenerateFakeDataControllingProperty:
             return handleGenerateFakeDataRequest(value);
 
-        // set the value from vehcile side, used in end to end test.
-        case kSetIntPropertyFromVehcileForTest: {
+        // set the value from vehicle side, used in end to end test.
+        case kSetIntPropertyFromVehicleForTest: {
             auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
             updatedPropValue->prop = value.value.int32Values[0];
             updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
@@ -212,7 +217,7 @@
             onPropertyValueFromCar(*updatedPropValue, updateStatus);
             return StatusCode::OK;
         }
-        case kSetFloatPropertyFromVehcileForTest: {
+        case kSetFloatPropertyFromVehicleForTest: {
             auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
             updatedPropValue->prop = value.value.int32Values[0];
             updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
@@ -221,7 +226,7 @@
             onPropertyValueFromCar(*updatedPropValue, updateStatus);
             return StatusCode::OK;
         }
-        case kSetBooleanPropertyFromVehcileForTest: {
+        case kSetBooleanPropertyFromVehicleForTest: {
             auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
             updatedPropValue->prop = value.value.int32Values[1];
             updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
@@ -261,6 +266,8 @@
                     break;
             }
             break;
+        case INITIAL_USER_INFO:
+            return onSetInitialUserInfo(value, updateStatus);
         default:
             break;
     }
@@ -274,6 +281,135 @@
     return StatusCode::OK;
 }
 
+/**
+ * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change
+ * indicating what the initial user should be.
+ *
+ * During normal circumstances, the emulator will reply right away, passing a response if
+ * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user
+ * to boot).
+ *
+ * But during development / testing, the behavior can be changed using lshal dump, which must use
+ * the areaId to indicate what should happen next.
+ *
+ * So, the behavior of set(INITIAL_USER_INFO) is:
+ *
+ * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by
+ *   lshal).
+ * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and
+ *   InitialUserInfoResponseAction::DEFAULT
+ * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd:
+ * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id
+ * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test
+ *   this error scenario)
+ * - if it's 3, then don't send a property change (so Android can emulate a timeout)
+ *
+ */
+StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& value,
+                                                       bool updateStatus) {
+    // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged
+    // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of
+    // LOG, it's not worth investigating why...
+
+    if (value.value.int32Values.size() == 0) {
+        LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value);
+        return StatusCode::INVALID_ARG;
+    }
+
+    if (value.areaId != 0) {
+        LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value);
+        mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
+        return StatusCode::OK;
+    }
+    LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value);
+
+    int32_t requestId = value.value.int32Values[0];
+
+    // Create the update property and set common values
+    auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
+    updatedValue->prop = INITIAL_USER_INFO;
+    updatedValue->timestamp = elapsedRealtimeNano();
+
+    if (mInitialUserResponseFromCmd == nullptr) {
+        updatedValue->value.int32Values.resize(2);
+        updatedValue->value.int32Values[0] = requestId;
+        updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;
+        LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: "
+                  << toString(*updatedValue);
+        onPropertyValueFromCar(*updatedValue, updateStatus);
+        return StatusCode::OK;
+    }
+
+    // mInitialUserResponseFromCmd is used for just one request
+    std::unique_ptr<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd);
+
+    // TODO(b/138709788): rather than populate the raw values directly, it should use the
+    // libraries that convert a InitialUserInfoResponse into a VehiclePropValue)
+
+    switch (response->areaId) {
+        case 1:
+            LOG(INFO) << "returning response with right request id";
+            *updatedValue = *response;
+            updatedValue->areaId = 0;
+            updatedValue->value.int32Values[0] = requestId;
+            break;
+        case 2:
+            LOG(INFO) << "returning response with wrong request id";
+            *updatedValue = *response;
+            updatedValue->areaId = 0;
+            updatedValue->value.int32Values[0] = -requestId;
+            break;
+        case 3:
+            LOG(INFO) << "not generating a property change event because of lshal prop: "
+                      << toString(*response);
+            return StatusCode::OK;
+        default:
+            LOG(ERROR) << "invalid action on lshal response: " << toString(*response);
+            return StatusCode::INTERNAL_ERROR;
+    }
+
+    LOG(INFO) << "updating property to: " << toString(*updatedValue);
+    onPropertyValueFromCar(*updatedValue, updateStatus);
+    return StatusCode::OK;
+}
+
+bool EmulatedVehicleServer::onDump(const hidl_handle& handle,
+                                   const hidl_vec<hidl_string>& options) {
+    int fd = handle->data[0];
+
+    if (options.size() > 0) {
+        if (options[0] == "--help") {
+            dprintf(fd, "Emulator-specific usage:\n");
+            dprintf(fd, "--user-hal: dumps state used for user management \n");
+            dprintf(fd, "\n");
+            // Include caller's help options
+            return true;
+        } else if (options[0] == "--user-hal") {
+            dumpUserHal(fd, "");
+            return false;
+
+        } else {
+            // Let caller handle the options...
+            return true;
+        }
+    }
+
+    dprintf(fd, "Emulator-specific state:\n");
+    dumpUserHal(fd, "  ");
+    dprintf(fd, "\n");
+
+    return true;
+}
+
+void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) {
+    if (mInitialUserResponseFromCmd != nullptr) {
+        dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(),
+                toString(*mInitialUserResponseFromCmd).c_str());
+    } else {
+        dprintf(fd, "%sNo Initial User Info\n", indent.c_str());
+    }
+}
+
 EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() {
     return std::make_unique<EmulatedPassthroughConnector>();
 }
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
index 5fc6493..4850d32 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
@@ -54,6 +54,8 @@
 
     StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
 
+    bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
+
     // Set the Property Value Pool used in this server
     void setValuePool(VehiclePropValuePool* valuePool);
 
@@ -77,6 +79,11 @@
             std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)};
 
     VehiclePropValuePool* mValuePool{nullptr};
+
+    // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class
+    std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
+    StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus);
+    void dumpUserHal(int fd, std::string indent);
 };
 
 // Helper functions
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 5c16bf7..692c7f7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -131,6 +131,10 @@
     return v;
 }
 
+bool EmulatedVehicleHal::dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+    return mVehicleClient->dump(fd, options);
+}
+
 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
     constexpr bool updateStatus = false;
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index a8378da..ebc405e 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -57,6 +57,7 @@
     StatusCode set(const VehiclePropValue& propValue) override;
     StatusCode subscribe(int32_t property, float sampleRate) override;
     StatusCode unsubscribe(int32_t property) override;
+    bool dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
     //  Methods from EmulatedVehicleHalIface
     bool setPropertyFromVehicle(const VehiclePropValue& propValue) override;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp
deleted file mode 100644
index e329c5b..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "GrpcVehicleClient.h"
-
-#include <condition_variable>
-#include <mutex>
-
-#include <android-base/logging.h>
-#include <grpc++/grpc++.h>
-
-#include "VehicleServer.grpc.pb.h"
-#include "VehicleServer.pb.h"
-#include "vhal_v2_0/ProtoMessageConverter.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-
-namespace impl {
-
-static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
-    // TODO(chenhaosjtuacm): get secured credentials here
-    return ::grpc::InsecureChannelCredentials();
-}
-
-class GrpcVehicleClientImpl : public EmulatedVehicleClient {
-  public:
-    GrpcVehicleClientImpl(const std::string& addr)
-        : mServiceAddr(addr),
-          mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())),
-          mGrpcStub(vhal_proto::VehicleServer::NewStub(mGrpcChannel)) {
-        StartValuePollingThread();
-    }
-
-    ~GrpcVehicleClientImpl() {
-        mShuttingDownFlag.store(true);
-        mShutdownCV.notify_all();
-        if (mPollingThread.joinable()) {
-            mPollingThread.join();
-        }
-    }
-
-    // methods from IVehicleClient
-
-    std::vector<VehiclePropConfig> getAllPropertyConfig() const override;
-
-    StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override;
-
-  private:
-    void StartValuePollingThread();
-
-    // private data members
-
-    std::string mServiceAddr;
-    std::shared_ptr<::grpc::Channel> mGrpcChannel;
-    std::unique_ptr<vhal_proto::VehicleServer::Stub> mGrpcStub;
-    std::thread mPollingThread;
-
-    std::mutex mShutdownMutex;
-    std::condition_variable mShutdownCV;
-    std::atomic<bool> mShuttingDownFlag{false};
-};
-
-std::unique_ptr<EmulatedVehicleClient> makeGrpcVehicleClient(const std::string& addr) {
-    return std::make_unique<GrpcVehicleClientImpl>(addr);
-}
-
-std::vector<VehiclePropConfig> GrpcVehicleClientImpl::getAllPropertyConfig() const {
-    std::vector<VehiclePropConfig> configs;
-    ::grpc::ClientContext context;
-    auto config_stream = mGrpcStub->GetAllPropertyConfig(&context, ::google::protobuf::Empty());
-    vhal_proto::VehiclePropConfig protoConfig;
-    while (config_stream->Read(&protoConfig)) {
-        VehiclePropConfig config;
-        proto_msg_converter::fromProto(&config, protoConfig);
-        configs.emplace_back(std::move(config));
-    }
-    auto grpc_status = config_stream->Finish();
-    if (!grpc_status.ok()) {
-        LOG(ERROR) << __func__
-                   << ": GRPC GetAllPropertyConfig Failed: " << grpc_status.error_message();
-        configs.clear();
-    }
-
-    return configs;
-}
-
-StatusCode GrpcVehicleClientImpl::setProperty(const VehiclePropValue& value, bool updateStatus) {
-    ::grpc::ClientContext context;
-    vhal_proto::WrappedVehiclePropValue wrappedProtoValue;
-    vhal_proto::VehicleHalCallStatus vhal_status;
-    proto_msg_converter::toProto(wrappedProtoValue.mutable_value(), value);
-    wrappedProtoValue.set_update_status(updateStatus);
-
-    auto grpc_status = mGrpcStub->SetProperty(&context, wrappedProtoValue, &vhal_status);
-    if (!grpc_status.ok()) {
-        LOG(ERROR) << __func__ << ": GRPC SetProperty Failed: " << grpc_status.error_message();
-        return StatusCode::INTERNAL_ERROR;
-    }
-
-    return static_cast<StatusCode>(vhal_status.status_code());
-}
-
-void GrpcVehicleClientImpl::StartValuePollingThread() {
-    mPollingThread = std::thread([this]() {
-        while (!mShuttingDownFlag.load()) {
-            ::grpc::ClientContext context;
-
-            std::atomic<bool> rpc_ok{true};
-            std::thread shuttingdown_watcher([this, &rpc_ok, &context]() {
-                std::unique_lock<std::mutex> shutdownLock(mShutdownMutex);
-                mShutdownCV.wait(shutdownLock, [this, &rpc_ok]() {
-                    return !rpc_ok.load() || mShuttingDownFlag.load();
-                });
-                context.TryCancel();
-            });
-
-            auto value_stream =
-                    mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
-            vhal_proto::WrappedVehiclePropValue wrappedProtoValue;
-            while (!mShuttingDownFlag.load() && value_stream->Read(&wrappedProtoValue)) {
-                VehiclePropValue value;
-                proto_msg_converter::fromProto(&value, wrappedProtoValue.value());
-                onPropertyValue(value, wrappedProtoValue.update_status());
-            }
-
-            rpc_ok.store(false);
-            mShutdownCV.notify_all();
-            shuttingdown_watcher.join();
-
-            auto grpc_status = value_stream->Finish();
-            // never reach here until connection lost
-            LOG(ERROR) << __func__
-                       << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
-
-            // try to reconnect
-        }
-    });
-}
-
-}  // namespace impl
-
-}  // namespace V2_0
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h
deleted file mode 100644
index 14eae7f..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleClient.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_
-#define android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_
-
-#include "vhal_v2_0/EmulatedVehicleConnector.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-
-namespace impl {
-
-std::unique_ptr<EmulatedVehicleClient> makeGrpcVehicleClient(const std::string& addr);
-
-}  // namespace impl
-
-}  // namespace V2_0
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleClient_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp
deleted file mode 100644
index e30b3be..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "GrpcVehicleServer.h"
-
-#include <condition_variable>
-#include <mutex>
-#include <shared_mutex>
-
-#include <android-base/logging.h>
-#include <grpc++/grpc++.h>
-
-#include "VehicleServer.grpc.pb.h"
-#include "VehicleServer.pb.h"
-#include "vhal_v2_0/ProtoMessageConverter.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-
-namespace impl {
-
-class GrpcVehicleServerImpl : public GrpcVehicleServer, public vhal_proto::VehicleServer::Service {
-  public:
-    GrpcVehicleServerImpl(const std::string& addr) : mServiceAddr(addr) {
-        setValuePool(&mValueObjectPool);
-    }
-
-    // method from GrpcVehicleServer
-    void Start() override;
-
-    // method from IVehicleServer
-    void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override;
-
-    // methods from vhal_proto::VehicleServer::Service
-
-    ::grpc::Status GetAllPropertyConfig(
-            ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-            ::grpc::ServerWriter<vhal_proto::VehiclePropConfig>* stream) override;
-
-    ::grpc::Status SetProperty(::grpc::ServerContext* context,
-                               const vhal_proto::WrappedVehiclePropValue* wrappedPropValue,
-                               vhal_proto::VehicleHalCallStatus* status) override;
-
-    ::grpc::Status StartPropertyValuesStream(
-            ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-            ::grpc::ServerWriter<vhal_proto::WrappedVehiclePropValue>* stream) override;
-
-  private:
-    // We keep long-lasting connection for streaming the prop values.
-    // For us, each connection can be represented as a function to send the new value, and
-    // an ID to identify this connection
-    struct ConnectionDescriptor {
-        using ValueWriterType = std::function<bool(const vhal_proto::WrappedVehiclePropValue&)>;
-
-        ConnectionDescriptor(ValueWriterType&& value_writer)
-            : mValueWriter(std::move(value_writer)),
-              mConnectionID(CONNECTION_ID_COUNTER.fetch_add(1)) {}
-
-        ConnectionDescriptor(const ConnectionDescriptor&) = delete;
-
-        ConnectionDescriptor& operator=(const ConnectionDescriptor&) = delete;
-
-        // This move constructor is NOT THREAD-SAFE, which means it cannot be moved
-        // while using. Since the connection descriptors are pretected by mConnectionMutex
-        // then we are fine here
-        ConnectionDescriptor(ConnectionDescriptor&& cd)
-            : mValueWriter(std::move(cd.mValueWriter)),
-              mConnectionID(cd.mConnectionID),
-              mIsAlive(cd.mIsAlive.load()) {
-            cd.mIsAlive.store(false);
-        }
-
-        ValueWriterType mValueWriter;
-        uint64_t mConnectionID;
-        std::atomic<bool> mIsAlive{true};
-
-        static std::atomic<uint64_t> CONNECTION_ID_COUNTER;
-    };
-
-    std::string mServiceAddr;
-    VehiclePropValuePool mValueObjectPool;
-    mutable std::shared_mutex mConnectionMutex;
-    mutable std::shared_mutex mWriterMutex;
-    std::list<ConnectionDescriptor> mValueStreamingConnections;
-};
-
-std::atomic<uint64_t> GrpcVehicleServerImpl::ConnectionDescriptor::CONNECTION_ID_COUNTER = 0;
-
-static std::shared_ptr<::grpc::ServerCredentials> getServerCredentials() {
-    // TODO(chenhaosjtuacm): get secured credentials here
-    return ::grpc::InsecureServerCredentials();
-}
-
-GrpcVehicleServerPtr makeGrpcVehicleServer(const std::string& addr) {
-    return std::make_unique<GrpcVehicleServerImpl>(addr);
-}
-
-void GrpcVehicleServerImpl::Start() {
-    ::grpc::ServerBuilder builder;
-    builder.RegisterService(this);
-    builder.AddListeningPort(mServiceAddr, getServerCredentials());
-    std::unique_ptr<::grpc::Server> server(builder.BuildAndStart());
-
-    server->Wait();
-}
-
-void GrpcVehicleServerImpl::onPropertyValueFromCar(const VehiclePropValue& value,
-                                                   bool updateStatus) {
-    vhal_proto::WrappedVehiclePropValue wrappedPropValue;
-    proto_msg_converter::toProto(wrappedPropValue.mutable_value(), value);
-    wrappedPropValue.set_update_status(updateStatus);
-    std::shared_lock read_lock(mConnectionMutex);
-
-    bool has_terminated_connections = 0;
-
-    for (auto& connection : mValueStreamingConnections) {
-        auto writeOK = connection.mValueWriter(wrappedPropValue);
-        if (!writeOK) {
-            LOG(ERROR) << __func__ << ": Server Write failed, connection lost. ID: "
-                       << connection.mConnectionID;
-            has_terminated_connections = true;
-            connection.mIsAlive.store(false);
-        }
-    }
-
-    if (!has_terminated_connections) {
-        return;
-    }
-
-    read_lock.unlock();
-
-    std::unique_lock write_lock(mConnectionMutex);
-
-    for (auto itr = mValueStreamingConnections.begin(); itr != mValueStreamingConnections.end();) {
-        if (!itr->mIsAlive.load()) {
-            itr = mValueStreamingConnections.erase(itr);
-        } else {
-            ++itr;
-        }
-    }
-}
-
-::grpc::Status GrpcVehicleServerImpl::GetAllPropertyConfig(
-        ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-        ::grpc::ServerWriter<vhal_proto::VehiclePropConfig>* stream) {
-    auto configs = onGetAllPropertyConfig();
-    for (auto& config : configs) {
-        vhal_proto::VehiclePropConfig protoConfig;
-        proto_msg_converter::toProto(&protoConfig, config);
-        if (!stream->Write(protoConfig)) {
-            return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost.");
-        }
-    }
-
-    return ::grpc::Status::OK;
-}
-
-::grpc::Status GrpcVehicleServerImpl::SetProperty(
-        ::grpc::ServerContext* context, const vhal_proto::WrappedVehiclePropValue* wrappedPropValue,
-        vhal_proto::VehicleHalCallStatus* status) {
-    VehiclePropValue value;
-    proto_msg_converter::fromProto(&value, wrappedPropValue->value());
-
-    auto set_status = static_cast<int32_t>(onSetProperty(value, wrappedPropValue->update_status()));
-    if (!vhal_proto::VehicleHalStatusCode_IsValid(set_status)) {
-        return ::grpc::Status(::grpc::StatusCode::INTERNAL, "Unknown status code");
-    }
-
-    status->set_status_code(static_cast<vhal_proto::VehicleHalStatusCode>(set_status));
-
-    return ::grpc::Status::OK;
-}
-
-::grpc::Status GrpcVehicleServerImpl::StartPropertyValuesStream(
-        ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-        ::grpc::ServerWriter<vhal_proto::WrappedVehiclePropValue>* stream) {
-    std::mutex terminateMutex;
-    std::condition_variable terminateCV;
-    std::unique_lock<std::mutex> terminateLock(terminateMutex);
-    bool terminated{false};
-
-    auto callBack = [stream, &terminateMutex, &terminateCV, &terminated,
-                     this](const vhal_proto::WrappedVehiclePropValue& value) {
-        std::unique_lock lock(mWriterMutex);
-        if (!stream->Write(value)) {
-            std::unique_lock<std::mutex> terminateLock(terminateMutex);
-            terminated = true;
-            terminateLock.unlock();
-            terminateCV.notify_all();
-            return false;
-        }
-        return true;
-    };
-
-    // Register connection
-    std::unique_lock lock(mConnectionMutex);
-    auto& conn = mValueStreamingConnections.emplace_back(std::move(callBack));
-    lock.unlock();
-
-    // Never stop until connection lost
-    terminateCV.wait(terminateLock, [&terminated]() { return terminated; });
-
-    LOG(ERROR) << __func__ << ": Stream lost, ID : " << conn.mConnectionID;
-
-    return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost.");
-}
-
-}  // namespace impl
-
-}  // namespace V2_0
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h
deleted file mode 100644
index 32f4eb2..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/GrpcVehicleServer.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_
-#define android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_
-
-#include "vhal_v2_0/EmulatedVehicleConnector.h"
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-
-namespace impl {
-
-// Connect to the Vehicle Client via GRPC
-class GrpcVehicleServer : public EmulatedVehicleServer {
-  public:
-    // Start listening incoming calls, should never return if working normally
-    virtual void Start() = 0;
-};
-
-using GrpcVehicleServerPtr = std::unique_ptr<GrpcVehicleServer>;
-
-GrpcVehicleServerPtr makeGrpcVehicleServer(const std::string& addr);
-
-}  // namespace impl
-
-}  // namespace V2_0
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // android_hardware_automotive_vehicle_V2_0_impl_virtialization_GrpcVehicleServer_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp
deleted file mode 100644
index 41d4827..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Utils.h"
-
-#include <sstream>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-namespace impl {
-
-std::string getVsockUri(const VsockServerInfo& serverInfo) {
-    std::stringstream uri_stream;
-    uri_stream << "vsock:" << serverInfo.serverCid << ":" << serverInfo.serverPort;
-    return uri_stream.str();
-}
-
-}  // namespace impl
-}  // namespace V2_0
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h
deleted file mode 100644
index 6b1049c..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
-#define android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
-
-#include <string>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-namespace impl {
-
-struct VsockServerInfo {
-    unsigned int serverCid{0};
-    unsigned int serverPort{0};
-};
-
-std::string getVsockUri(const VsockServerInfo& serverInfo);
-
-}  // namespace impl
-}  // namespace V2_0
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-#endif  // android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 6145ea2..cbd9e28 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -65,8 +65,8 @@
  * particular door, thus this property must be marked with
  * VehicleArea:DOOR flag.
  *
- * Other properties may not be associated with particular vehicle area,
- * these kind of properties must have VehicleArea:GLOBAL flag.
+ * Other properties may not be associated with particular vehicle area.
+ * These kinds of properties must have VehicleArea:GLOBAL flag.
  *
  * [Definition] Area: An area represents a unique element of an AreaType.
  *   For instance, if AreaType is WINDOW, then an area may be FRONT_WINDSHIELD.
@@ -79,9 +79,9 @@
  * Rules for mapping a zoned property to AreaIDs:
  *  - A property must be mapped to an array of AreaIDs that are impacted when
  *    the property value changes.
- *  - Each element in the array must represent an AreaID, in which, the
+ *  - Each element in the array must represent an AreaID, in which the
  *    property value can only be changed together in all the areas within
- *    an AreaID and never independently. That is, when the property value
+ *    the AreaID and never independently. That is, when the property value
  *    changes in one of the areas in an AreaID in the array, then it must
  *    automatically change in all other areas in the AreaID.
  *  - The property value must be independently controllable in any two
@@ -140,7 +140,7 @@
  *  - vehicle area (VehicleArea)
  *
  * Vendors are allowed to extend this enum with their own properties. In this
- * case they must use VehiclePropertyGroup:VENDOR flag when property is
+ * case they must use VehiclePropertyGroup:VENDOR flag when the property is
  * declared.
  *
  * When a property's status field is not set to AVAILABLE:
@@ -2438,6 +2438,373 @@
         | VehiclePropertyType:STRING
         | VehicleArea:GLOBAL),
 
+    /**
+     * Defines the initial Android user to be used during initialization.
+     *
+     * This property is called by the Android system when it initializes and it lets the HAL
+     * define which Android user should be started.
+     *
+     * This request is made by setting a VehiclePropValue (defined by InitialUserInfoRequest),
+     * and the HAL must respond with a property change event (defined by InitialUserInfoResponse).
+     * If the HAL doesn't respond after some time (defined by the Android system), the Android
+     * system will proceed as if HAL returned a response of action
+     * InitialUserInfoResponseAction:DEFAULT.
+     *
+     * For example, on first boot, the request could be:
+     *
+     * int32[0]: 42  // request id (arbitrary number set by Android system)
+     * int32[1]: 1   // InitialUserInfoRequestType::FIRST_BOOT
+     * int32[2]: 0   // id of current user (usersInfo.currentUser.userId)
+     * int32[3]: 1   // flag of current user (usersInfo.currentUser.flags = SYSTEM)
+     * int32[4]: 1   // number of existing users (usersInfo.numberUsers);
+     * int32[5]: 0   // user #0  (usersInfo.existingUsers[0].userId)
+     * int32[6]: 1   // flags of user #0  (usersInfo.existingUsers[0].flags)
+     *
+     * And if the HAL want to respond with the creation of an admin user called "Admin", the
+     * response would be:
+     *
+     * int32[0]: 42    // must match the request id from the request
+     * int32[1]:  2    // action = InitialUserInfoResponseAction::CREATE
+     * int32[2]: -1    // userToSwitchOrCreate.userId (not used as user will be created)
+     * int32[3]:  8    // userToSwitchOrCreate.flags = ADMIN
+     * string: "Admin" // userNameToCreate
+     *
+     * NOTE: if the HAL doesn't support user management, then it should not define this property,
+     * which in turn would disable the other user-related properties (for example, the Android
+     * system would never issue them and user-related requests from the HAL layer would be ignored
+     * by the Android System). But if it supports user management, then it must support all
+     * user-related properties (INITIAL_USER_INFO, SWITCH_USER, CREATE_USER, REMOVE_USER,
+     *       and USER_IDENTIFICATION_ASSOCIATION).
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    INITIAL_USER_INFO = (
+        0x0F07
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Defines a request to switch the foreground Android user.
+     *
+     * This property is used primarily by the Android System to inform the HAL that the
+     * current foreground Android user is switching, but it could also be used by the HAL to request
+     * the Android system to switch users - the
+     *
+     * When the request is made by Android, it sets a VehiclePropValue and the HAL must responde
+     * with a property change event; when the HAL is making the request, it must also do it through
+     * a property change event (the main difference is that the request id will be positive in the
+     * former case, and negative in the latter; the SwitchUserMessageType will also be different).
+     *
+     * The format of both request is defined by SwitchUserRequest and the format of the response
+     * (when needed) is defined by SwitchUserResponse. How the HAL (or Android System) should
+     * proceed depends on the message type (which is defined by the SwitchUserMessageType
+     * parameter), as defined below.
+     *
+     * 1.LEGACY_ANDROID_SWITCH
+     * -----------------------
+     *
+     * Called by the Android System to indicate the Android user is about to change, when the change
+     * request was made in a way that is not integrated with the HAL (for example, through
+     * adb shell am switch-user).
+     *
+     * The HAL can switch its internal user once it receives this request, but it doesn't need to
+     * reply back to the Android System. If its internal user cannot be changed for some reason,
+     * then it must wait for the SWITCH_USER(type=ANDROID_POST_SWITCH) call to recover
+     * (for example, it could issue a SWITCH_USER(type=VEHICLE_REQUEST) to switch back to
+     * the previous user), but ideally it should never fail (as switching back could result in a
+     * confusing experience for the end user).
+     *
+     * For example, if the system have users (0, 10, 11) and it's switching from 0 to 11 (where none
+     * of them have any special flag), the request would be:
+     *
+     * int32[0]:  42  // request id
+     * int32[1]:  1   // SwitchUserMessageType::LEGACY_ANDROID_SWITCH
+     * int32[2]:  11  // target user id
+     * int32[3]:  0   // target user flags (none)
+     * int32[4]:  10  // current user
+     * int32[5]:  0   // current user flags (none)
+     * int32[6]:  3   // number of users
+     * int32[7]:  0   // user #0 (Android user id 0)
+     * int32[8]:  0   // flags of user #0 (none)
+     * int32[9]:  10  // user #1 (Android user id 10)
+     * int32[10]: 0   // flags of user #1 (none)
+     * int32[11]: 11  // user #2 (Android user id 11)
+     * int32[12]: 0   // flags of user #2 (none)
+     *
+     * 2.ANDROID_SWITCH
+     * ----------------
+     * Called by the Android System to indicate the Android user is about to change, but Android
+     * will wait for the HAL's response (up to some time) before proceeding.
+     *
+     * The HAL must switch its internal user once it receives this request, then respond back to
+     * Android with a SWITCH_USER(type=VEHICLE_RESPONSE) indicating whether its internal
+     * user was switched or not (through the SwitchUserStatus enum).
+     *
+     * For example, if Android has users (0, 10, 11) and it's switching from 10 to 11 (where
+     * none of them have any special flag), the request would be:
+     *
+     * int32[0]:  42  // request id
+     * int32[1]:  2   // SwitchUserMessageType::ANDROID_SWITCH
+     * int32[2]:  11  // target user id
+     * int32[3]:  0   // target user flags (none)
+     * int32[4]:  10  // current user
+     * int32[5]:  0   // current user flags (none)
+     * int32[6]:  3   // number of users
+     * int32[7]:  0   // 1st user (user 0)
+     * int32[8]:  0   // 1st user flags (none)
+     * int32[9]:  10  // 2nd user (user 10)
+     * int32[10]: 0   // 2nd user flags (none)
+     * int32[11]: 11  // 3rd user (user 11)
+     * int32[12]: 0   // 3rd user flags (none)
+     *
+     * If the request succeeded, the HAL must update the propery with:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 3   // messageType = SwitchUserMessageType::VEHICLE_RESPONSE
+     * int32[2]: 1   // status = SwitchUserStatus::SUCCESS
+     *
+     * But if it failed, the response would be something like:
+     *
+     * int32[0]: 42   // request id
+     * int32[1]: 3    // messageType = SwitchUserMessageType::VEHICLE_RESPONSE
+     * int32[2]: 2    // status = SwitchUserStatus::FAILURE
+     * string: "108-D'OH!" // OEM-spefic error message
+     *
+     * 3.VEHICLE_RESPONSE
+     * ------------------
+     * Called by the HAL to indicate whether a request of type ANDROID_SWITCH should proceed or
+     * abort - see the ANDROID_SWITCH section above for more info.
+     *
+     * 4.VEHICLE_REQUEST
+     * ------------------
+     * Called by the HAL to request that the current foreground Android user is switched.
+     *
+     * This is useful in situations where Android started as one user, but the vehicle identified
+     * the driver as another user. For example, user A unlocked the car using the key fob of user B;
+     * the INITIAL_USER_INFO request returned user B, but then a face recognition subsubsystem
+     * identified the user as A.
+     *
+     * The HAL makes this request by a property change event (passing a negative request id), and
+     * the Android system will response by issuye an ANDROID_POST_SWITCH call which the same
+     * request id.
+     *
+     * For example, if the current foreground Android user is 10 and the HAL asked it to switch to
+     * 11, the request would be:
+     *
+     * int32[0]: -108  // request id
+     * int32[1]: 4     // messageType = SwitchUserMessageType::VEHICLE_REQUEST
+     * int32[2]: 11    // Android user id
+     *
+     * If the request succeeded and Android has 3 users (0, 10, 11), the response would be:
+     *
+     * int32[0]: -108 // request id
+     * int32[1]:  5   // messageType = SwitchUserMessageType::ANDROID_SWITCH
+     * int32[2]:  11  // target user id
+     * int32[3]:  11  // target user id flags (none)
+     * int32[4]:  11  // current user
+     * int32[5]:  0   // current user flags (none)
+     * int32[6]:  3   // number of users
+     * int32[7]:  0   // 1st user (user 0)
+     * int32[8]:  0   // 1st user flags (none)
+     * int32[9]:  10  // 2nd user (user 10)
+     * int32[10]: 4   // 2nd user flags (none)
+     * int32[11]: 11  // 3rd user (user 11)
+     * int32[12]: 3   // 3rd user flags (none)
+     *
+     * Notice that both the current and target user ids are the same - if the request failed, then
+     * they would be different (i.e, target user would be 11, but current user would still be 10).
+     *
+     * 5.ANDROID_POST_SWITCH
+     * ---------------------
+     * Called by the Android System after a request to switch a user was made
+     *
+     * This property is called after switch requests of any type (i.e., LEGACY_ANDROID_SWITCH,
+     * ANDROID_SWITCH, or VEHICLE_REQUEST) and can be used to determine if the request succeeded or
+     * failed:
+     *
+     * 1. When it succeeded, it's called when the Android user is in the boot locked state and the
+     *    value of the current and target users ids in the response are different. This would be
+     *    equivalent to receiving an Intent.ACTION_LOCKED_BOOT_COMPLETED in an Android app.
+     * 2. When it failed it's called right away and the value of the current and target users ids
+     *    in the response are the same.
+     *
+     * The HAL can update its internal state once it receives this request, but it doesn't need to
+     * reply back to the Android System.
+     *
+     * Request: the first N values as defined by INITIAL_USER_INFO (where the request-specific
+     * value at index 1 is SwitchUserMessageType::ANDROID_POST_SWITCH), then 2 more values for the
+     * target user id (i.e., the Android user id that was requested to be switched to) and its flags
+     * (as defined by  UserFlags).
+     *
+     * Response: none.
+     *
+     * Example: see VEHICLE_REQUEST section above.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    SWITCH_USER = (
+        0x0F08
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Called by the Android System after an Android user was created.
+     *
+     * The HAL can use this property to create its equivalent user.
+     *
+     * This is an async request: Android makes the request by setting a VehiclePropValue, and HAL
+     * must respond with a property change indicating whether the request succeeded or failed. If
+     * it failed, the Android system will remove the user.
+     *
+     * The format of the request is defined by CreateUserRequest and the format of the response by
+     * CreateUserResponse.
+     *
+     * For example, if system had 2 users (0 and 10) and a 3rd one (which is an ephemeral guest) was
+     * created, the request would be:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 11  // Android id of the created user
+     * int32[2]: 3   // Android flags (ephemeral guest) of the created user
+     * int32[3]: 10  // current user
+     * int32[4]: 0   // current user flags (none)
+     * int32[5]: 3   // number of users
+     * int32[6]: 0   // 1st user (user 0)
+     * int32[7]: 0   // 1st user flags (none)
+     * int32[8]: 10  // 2nd user (user 10)
+     * int32[9]: 0   // 2nd user flags (none)
+     * int32[19]: 11 // 3rd user (user 11)
+     * int32[11]: 3  // 3rd user flags (ephemeral guest)
+     * string: "ElGuesto" // name of the new user
+     *
+     * Then if the request succeeded, the HAL would return:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 1   // CreateUserStatus::SUCCESS
+     *
+     * But if it failed:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 2   // CreateUserStatus::FAILURE
+     * string: "D'OH!" // The meaning is a blackbox - it's passed to the caller (like Settings UI),
+     *                 // which in turn can take the proper action.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    CREATE_USER = (
+        0x0F09
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Called by the Android System after an Android user was removed.
+     *
+     * The HAL can use this property to remove its equivalent user.
+     *
+     * This is write-only call - the Android System is not expecting a reply from the HAL. Hence,
+     * this request should not fail - if the equivalent HAL user cannot be removed, then HAL should
+     * mark it as inactive or recover in some other way.
+     *
+     * The request is made by setting the VehiclePropValue with the contents defined by
+     * RemoveUserRequest.
+     *
+     * For example, if system had 3 users (0, 10, and 11) and user 11 was removed, the request
+     * would be:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 11  // (Android user id of the removed user)
+     * int32[2]: 0   // (Android user flags of the removed user)
+     * int32[3]: 10  // current user
+     * int32[4]: 0   // current user flags (none)
+     * int32[5]: 2   // number of users
+     * int32[6]: 0   // 1st user (user 0)
+     * int32[7]: 0   // 1st user flags (none)
+     * int32[8]: 10  // 2nd user (user 10)
+     * int32[9]: 0   // 2nd user flags (none)
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:WRITE
+     */
+    REMOVE_USER = (
+        0x0F0A
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Property used to associate (or query the association) the current user with vehicle-specific
+     * identification mechanisms (such as key FOB).
+     *
+     * To query the association, the Android system gets the property, passing a VehiclePropValue
+     * containing the types of associations are being queried, as defined by
+     * UserIdentificationGetRequest. The HAL must return right away, updating the VehiclePropValue
+     * with a UserIdentificationResponse. Notice that user identification should have already
+     * happened while system is booting up and the VHAL implementation should only return the
+     * already identified association (like the key FOB used to unlock the car), instead of starting
+     * a new association from the get call.
+     *
+     * To associate types, the Android system sets the property, passing a VehiclePropValue
+     * containing the types and values of associations being set, as defined by the
+     * UserIdentificationSetRequest. The HAL will then use a property change event (whose
+     * VehiclePropValue is defined by UserIdentificationResponse) indicating the current status of
+     * the types after the request.
+     *
+     * For example, to query if the current user (10) is associated with the FOB that unlocked the
+     * car and a custom mechanism provided by the OEM, the request would be:
+     *
+     * int32[0]: 10  (Android user id)
+     * int32[1]: 0   (Android user flags)
+     * int32[2]: 2   (number of types queried)
+     * int32[3]: 1   (1st type queried, UserIdentificationAssociationType::KEY_FOB)
+     * int32[4]: 101 (2nd type queried, UserIdentificationAssociationType::CUSTOM_1)
+     *
+     * If the user is associated with the FOB but not with the custom mechanism, the response would
+     * be:
+     *
+     * int32[9]: 2   (number of associations in the response)
+     * int32[1]: 1   (1st type: UserIdentificationAssociationType::KEY_FOB)
+     * int32[2]: 2   (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER)
+     * int32[3]: 101 (2st type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[4]: 4   (2nd value: UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER)
+     *
+     * Then to associate the user with the custom mechanism, a set request would be made:
+     *
+     * int32[0]: 10  (Android user id)
+     * int32[0]: 0   (Android user flags)
+     * int32[1]: 1   (number of associations being set)
+     * int32[2]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[3]: 1   (1st value: UserIdentificationAssociationSETValue::ASSOCIATE_CURRENT_USER)
+     *
+     * If the request succeeded, the response would be simply:
+     *
+     * int32[0]: 2   (number of associations in the response)
+     * int32[1]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[2]: 1   (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER)
+     *
+     * Notice that the set request adds associations, but doesn't remove the existing ones. In the
+     * example above, the end state would be 2 associations (FOB and CUSTOM_1). If we wanted to
+     * associate the user with just CUSTOM_1 but not FOB, then the request should have been:
+     *
+     * int32[0]: 10  (Android user id)
+     * int32[1]: 2   (number of types set)
+     * int32[2]: 1   (1st type: UserIdentificationAssociationType::KEY_FOB)
+     * int32[3]: 2   (1st value: UserIdentificationAssociationValue::DISASSOCIATE_CURRENT_USER)
+     * int32[3]: 101 (2nd type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[5]: 1   (2nd value: UserIdentificationAssociationValue::ASSOCIATE_CURRENT_USER)
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    USER_IDENTIFICATION_ASSOCIATION = (
+        0x0F0B
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
 };
 
 /**
@@ -2674,26 +3041,52 @@
 };
 
 enum VehicleApPowerStateReq : int32_t {
-    /** Transition Android from WAIT_FOR_VHAL to ON state */
+    /**
+     * This requests Android to enter its normal operating state.
+     * This may be sent after the AP has reported
+     * VehicleApPowerStateReport#DEEP_SLEEP_EXIT,
+     * VehicleApPowerStateReport#SHUTDOWN_CANCELLED, or
+     * VehicleApPowerStateReport#WAIT_FOR_VHAL.
+     */
     ON = 0,
 
     /**
-     * The power controller has requested AP to shutdown. AP can either enter
-     * sleep state or start full shutdown. AP can also request postponing
-     * shutdown by sending VehicleApPowerSetState#SHUTDOWN_POSTPONE message. The
-     * power controller must change power state to this state to shutdown
-     * system.
+     * The power controller issues this request to shutdown the system.
+     * This may be sent after the AP has reported
+     * VehicleApPowerStateReport#DEEP_SLEEP_EXIT,
+     * VehicleApPowerStateReport#ON,
+     * VehicleApPowerStateReport#SHUTDOWN_CANCELLED,
+     * VehicleApPowerStateReport#SHUTDOWN_POSTPONE,
+     * VehicleApPowerStateReport#SHUTDOWN_PREPARE, or
+     * VehicleApPowerStateReport#WAIT_FOR_VHAL.
      *
-     * int32Values[1] : one of VehicleApPowerStateShutdownParam
-     *
-     * SHUTDOWN_PRPARE may be requested from either WAIT_FOR_VHAL or ON states.
+     * int32Values[1] : One of VehicleApPowerStateShutdownParam.
+     *                  This parameter indicates if the AP should shut
+     *                  down fully or sleep. This parameter also
+     *                  indicates if the shutdown should be immediate
+     *                  or if it can be postponed. If the shutdown can
+     *                  be postponed, AP requests postponing by sending
+     *                  VehicleApPowerStateReport#SHUTDOWN_POSTPONE.
      */
     SHUTDOWN_PREPARE = 1,
 
-    /** Cancel the shutdown and transition from SHUTDOWN_PREPARE to WAIT_FOR_VHAL state */
+    /**
+     * Cancel the shutdown.
+     * This may be sent after the AP has reported
+     * VehicleApPowerStateReport#SHUTDOWN_POSTPONE or
+     * VehicleApPowerStateReport#SHUTDOWN_PREPARE.
+     * After receiving this request, the AP will report
+     * VehicleApPowerStateReport#WAIT_FOR_VHAL in preparation to going ON.
+     */
     CANCEL_SHUTDOWN = 2,
 
-    /** VHAL is finished with shutdown procedures and ready for Android to suspend/shutdown */
+    /**
+     * Completes the shutdown process.
+     * This may be sent after the AP has reported
+     * VehicleApPowerStateReport#DEEP_SLEEP_ENTRY or
+     * VehicleApPowerStateReport#SHUTDOWN_START. The AP will not report new
+     * state information after receiving this request.
+     */
     FINISHED = 3,
 };
 
@@ -2725,61 +3118,80 @@
 
 enum VehicleApPowerStateReport : int32_t {
     /**
-     * Device has booted, CarService has initialized and is ready to accept commands from VHAL.
-     * Device starts in WAIT_FOR_VHAL state.  The user is not logged in, and vendor apps/services
-     * are expected to control the display and audio.
+     * The device has booted. CarService has initialized and is ready to accept commands
+     * from VHAL. The user is not logged in, and vendor apps and services are expected to
+     * control the display and audio.
+     * After reporting this state, AP will accept VehicleApPowerStateReq#ON or
+     * VehicleApPowerStateReq#SHUTDOWN_PREPARE. Other power state requests are ignored.
      */
     WAIT_FOR_VHAL = 0x1,
 
     /**
-     * AP is ready to suspend and has entered WAIT_FOR_FINISHED state.
+     * AP is ready to suspend.
+     * The AP will not send any more state reports after this.
+     * After reporting this state, AP will accept VehicleApPowerStateReq#FINISHED.
+     * Other power state requests are ignored.
      *
-     * int32Values[1]: Time to turn on AP in secs. Power controller may turn on
-     *                 AP after specified time so that AP can run tasks like
-     *                 update. If it is set to 0, there is no wake up, and power
-     *                 controller may not necessarily support wake-up.
+     * int32Values[1]: Time to turn AP back on, in seconds. Power controller should turn on
+     *                 AP after the specified time has elapsed, so AP can run tasks like
+     *                 update. If this value is 0, no wake up is requested. The power
+     *                 controller may not necessarily support timed wake-up.
      */
     DEEP_SLEEP_ENTRY = 0x2,
 
     /**
-     * AP is exiting from deep sleep state, and is in WAIT_FOR_VHAL state.
+     * AP is exiting from deep sleep state.
+     * After reporting this state, AP will accept VehicleApPowerStateReq#ON or
+     * VehicleApPowerStateReq#SHUTDOWN_PREPARE. Other power state requests are ignored.
      */
     DEEP_SLEEP_EXIT = 0x3,
 
     /**
-     * AP remains in SHUTDOWN_PREPARE state as idle and cleanup tasks execute.
+     * AP sends this message repeatedly while cleanup and idle tasks execute.
+     * After reporting this state, AP will accept VehicleApPowerStateReq#SHUTDOWN_PREPARE
+     * requesting immediate shutdown or VehicleApPowerStateReq#CANCEL_SHUTDOWN. Other
+     * power state requests are ignored.
      *
-     * int32Values[1]: Time to postpone shutdown in ms. Maximum value can be
+     * int32Values[1]: Time to postpone shutdown in ms. Maximum value is
      *                 5000 ms.
-     *                 If AP needs more time, it will send another POSTPONE
+     *                 If AP needs more time, it will send another SHUTDOWN_POSTPONE
      *                 message before the previous one expires.
      */
     SHUTDOWN_POSTPONE = 0x4,
 
     /**
-     * AP is ready to shutdown and has entered WAIT_FOR_FINISHED state.
+     * AP is ready to shutdown.
+     * The AP will not send any more state reports after this.
+     * After reporting this state, AP will accept VehicleApPowerStateReq#FINISHED.
+     * Other power state requests are ignored.
      *
-     * int32Values[1]: Time to turn on AP in secs. Power controller may turn on
-     *                 AP after specified time so that AP can run tasks like
-     *                 update. If it is set to 0, there is no wake up, and power
-     *                 controller may not necessarily support wake-up.
+     * int32Values[1]: Time to turn AP back on, in seconds. Power controller should turn on
+     *                 AP after the specified time has elapsed so AP can run tasks like
+     *                 update. If this value is 0, no wake up is specified. The power
+     *                 controller may not necessarily support timed wake-up.
      */
     SHUTDOWN_START = 0x5,
 
     /**
-     * AP has transitioned from WAIT_FOR_VHAL state to ON.
+     * AP is entering its normal operating state.
+     * After reporting this state, AP will accept VehicleApPowerStateReq#SHUTDOWN_PREPARE.
+     * Other power state requests are ignored.
      */
     ON = 0x6,
 
     /**
-     * AP has transitions to SHUTDOWN_PREPARE state.  In this state, Garage Mode will execute idle
-     * tasks, and other services that have registered for this state transition may execute
-     * cleanup activities.
+     * AP is preparing to shut down. In this state, Garage Mode is active and idle
+     * tasks are allowed to run.
+     * After reporting this state, AP will accept VehicleApPowerStateReq#SHUTDOWN_PREPARE
+     * requesting immediate shutdown or VehicleApPowerStateReq#CANCEL_SHUTDOWN. Other
+     * power state requests are ignored.
      */
     SHUTDOWN_PREPARE = 0x7,
 
     /**
-     * AP has transitioned from SHUTDOWN_PREPARE state to WAIT_FOR_VHAL.
+     * AP has stopped preparing to shut down.
+     * After reporting this state, AP will accept VehicleApPowerStateReq#ON or
+     * VehicleApPowerStateReq#SHUTDOWN_PREPARE. Other power state requests are ignored.
      */
     SHUTDOWN_CANCELLED = 0x8,
 };
@@ -3733,3 +4145,509 @@
 enum VmsPublisherInformationIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex {
     PUBLISHER_ID = 1,
 };
+
+/**
+ * Information about a specific Android user.
+ */
+struct UserInfo {
+
+    UserId userId;
+
+    UserFlags flags;
+};
+
+/**
+ * Id of an Android user.
+ *
+ * Must be > 0 for valid ids, or -10000 (which is the same as Android.UserHandle.USER_NULL) when
+ * it's not used.
+ */
+typedef int32_t UserId;
+
+/**
+ * Flags used to define the characteristics of an Android user.
+ */
+enum UserFlags: int32_t {
+    /**
+     * No flags.
+     */
+    NONE = 0x0,
+
+    /**
+     * System user.
+     * On automotive, that user is always running, although never on foreground (except during
+     * boot or exceptional circumstances).
+     */
+    SYSTEM = 0x01,
+
+    /**
+     * Guest users have restrictions.
+     */
+    GUEST = 0x02,
+
+    /**
+     * Ephemeral users have non-persistent state.
+     */
+    EPHEMERAL = 0x04,
+
+    /**
+     * Admin users have additional privileges such as permission to create other users.
+     */
+    ADMIN = 0x08,
+};
+
+/**
+ * Information about all Android users.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it's part of other structs, which
+ * in turn are converted to a VehiclePropValue.RawValue through libraries provided by the default
+ * Vehicle HAL implementation.
+ */
+struct UsersInfo {
+
+    /** The current foreground user. */
+    UserInfo currentUser;
+
+    /** Number of existing users (includes the current user). */
+    int32_t numberUsers;
+
+    /** List of existing users (includes the current user). */
+    vec<UserInfo> existingUsers;
+ };
+
+/**
+ * Id of a request related to user management.
+ *
+ * This id can be used by the Android system to map responses sent by the HAL, and vice-versa.
+ *
+ * For requests originated by Android, the value is positive (> 0), while for requests originated by
+ * the HAL it must be negative (< 0).
+ */
+typedef int32_t UserRequestId;
+
+/**
+ * Defines the format of a INITIAL_USER_INFO request made by the Android system.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct InitialUserInfoRequest {
+    /**
+     * Arbitrary id used to map the HAL response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Type of request.
+     */
+    InitialUserInfoRequestType requestType;
+
+    /**
+     * Information about the current state of the Android system.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+ * Defines when a INITIAL_USER_INFO request was made.
+ */
+enum InitialUserInfoRequestType : int32_t {
+  /** At the first time Android was booted (or after a factory reset). */
+  FIRST_BOOT = 1,
+
+  /** At the first time Android was booted after the system was updated. */
+  FIRST_BOOT_AFTER_OTA = 2,
+
+  /** When Android was booted "from scratch". */
+  COLD_BOOT = 3,
+
+  /** When Android was resumed after the system was suspended to memory. */
+  RESUME = 4,
+};
+
+/**
+ * Defines the format of a HAL response to a INITIAL_USER_INFO request.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct InitialUserInfoResponse {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * which action the Android system should take.
+     */
+    InitialUserInfoResponseAction action;
+
+    /**
+     * Information about the user that should be switched to or created.
+     */
+    UserInfo userToSwitchOrCreate;
+
+    /**
+     * Name of the user that should be created.
+     */
+    string userNameToCreate;
+};
+
+/**
+ * Defines which action the Android system should take in an INITIAL_USER_INFO request.
+ */
+enum InitialUserInfoResponseAction : int32_t {
+   /**
+    * Let the Android System decide what to do.
+    *
+    * For example, it might create a new user on first boot, and switch to the last
+    * active user afterwards.
+    */
+   DEFAULT = 0,
+
+   /**
+    * Switch to an existing Android user.
+    */
+   SWITCH = 1,
+
+   /**
+    * Create a new Android user (and switch to it).
+    */
+   CREATE = 2,
+};
+
+/**
+ * Defines the format of a SWITCH_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct SwitchUserRequest {
+    /**
+     * Arbitrary id used to map the response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Type of message.
+     */
+    SwitchUserMessageType messageType;
+
+    /**
+     * Information about the Android user being switched to.
+     *
+     * Only the user id (but not the flags) should be set when the request is made by HAL.
+     */
+    UserInfo targetUser;
+
+    /**
+     * Information about the current state of the Android system.
+     *
+     * Should not be set when the request is made by HAL.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+ * Defines the reason a SWITCH_USER call was made.
+ *
+ * The meaning of each constant is explained in that property.
+ */
+enum SwitchUserMessageType: int32_t {
+   LEGACY_ANDROID_SWITCH = 1,
+   ANDROID_SWITCH = 2,
+   VEHICLE_RESPONSE = 3,
+   VEHICLE_REQUEST = 4,
+   ANDROID_POST_SWITCH = 5,
+};
+
+/**
+ * Defines the result of a SwitchUserRequest.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct SwitchUserResponse {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Type of message.
+     */
+    SwitchUserMessageType messageType;
+
+    /**
+     * Status of the request.
+     */
+    SwitchUserStatus status;
+
+    /**
+     * HAL-specific error message.
+     *
+     * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be
+     * used to show custom error messages to the end user.
+     */
+    string errorMessage;
+};
+
+/**
+ * Status of the response to a SwitchUserRequest.
+ */
+enum SwitchUserStatus : int32_t {
+   /** The request succeeded and the HAL user was switched. */
+   SUCCESS = 1,
+   /** The request failed and the HAL user remained the same. */
+   FAILURE = 2,
+};
+
+/**
+ * Defines the format of a CREATE_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct CreateUserRequest {
+    /**
+     * Arbitrary id used to map the response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Basic information about Android user that was created.
+     */
+    UserInfo newUserInfo;
+
+    /**
+     * Name of the new Android user.
+     */
+     string newUserName;
+
+    /**
+     * Information about the current state of the Android system.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+ * Defines the result of a CreateUserRequest.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct CreateUserResponse {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Status of the request.
+     */
+    CreateUserStatus status;
+
+    /**
+     * HAL-specific error message.
+     *
+     * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be
+     * used to show custom error messages to the end user.
+     */
+    string errorMessage;
+};
+
+/**
+ * Status of the response to a CreateUserRequest.
+ */
+enum CreateUserStatus : int32_t {
+   /**
+    * The request succeeded (for example, HAL created a new internal user, or associated the
+    * Android user to an existing internal user).
+    */
+   SUCCESS = 1,
+
+   /**
+     * The request failed (and Android will remove the Android user).
+     */
+   FAILURE = 2,
+};
+
+/**
+ * Defines the format of a REMOVE_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct RemoveUserRequest {
+    /**
+     * Arbitrary id used to map the response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Information about the Android user that was removed.
+     */
+    UserInfo removedUserInfo;
+
+    /**
+     * Information about the current state of the Android system.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+  * Types of mechanisms used to identify an Android user.
+  *
+  * See USER_IDENTIFICATION_ASSOCIATION for more details and example.
+  */
+enum UserIdentificationAssociationType: int32_t {
+   /** Key used to unlock the car. */
+   KEY_FOB = 1,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_1 = 101,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_2 = 102,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_3 = 103,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_4 = 104,
+};
+
+/**
+ * Whether a UserIdentificationAssociationType is associate with an Android user.
+ */
+enum UserIdentificationAssociationValue : int32_t {
+   /**
+    * Used when the status of an association could not be determined.
+    *
+    * For example, in a set() request, it would indicate a failure to set the given type.
+    */
+   UNKNOWN = 1,
+
+   /**
+    * The identification type is associated with the current foreground Android user.
+    */
+   ASSOCIATED_CURRENT_USER = 2,
+
+   /**
+    * The identification type is associated with another Android user.
+    */
+   ASSOCIATED_ANOTHER_USER = 3,
+
+   /**
+    * The identification type is not associated with any Android user.
+    */
+   NOT_ASSOCIATED_ANY_USER = 4,
+};
+
+/**
+ * Used to set a UserIdentificationAssociationType with an Android user.
+ */
+enum UserIdentificationAssociationSetValue : int32_t {
+   /**
+    * Associate the identification type with the current foreground Android user.
+    */
+   ASSOCIATE_CURRENT_USER = 1,
+
+   /**
+    * Disassociate the identification type from the current foreground Android user.
+    */
+   DISASSOCIATE_CURRENT_USER = 2,
+
+   /**
+    * Disassociate the identification type from all Android users.
+    */
+   DISASSOCIATE_ALL_USERS = 3,
+};
+
+/**
+ * Defines the format of a get() call to USER_IDENTIFICATION_ASSOCIATION.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct UserIdentificationGetRequest {
+    /**
+     * Information about the current foreground Android user.
+     */
+    UserInfo userInfo;
+
+    /**
+     * Number of association being queried.
+     */
+    int32_t numberAssociationTypes;
+
+    /**
+     * Types of association being queried.
+     */
+    vec<UserIdentificationAssociationType> associationTypes;
+};
+
+/**
+ * Defines the format of a set() call to USER_IDENTIFICATION_ASSOCIATION.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct UserIdentificationSetRequest {
+    /**
+     * Information about the current foreground Android user.
+     */
+    UserInfo userInfo;
+
+    /**
+     * Number of association being set.
+     */
+    int32_t numberAssociations;
+
+    /**
+     * Associations being set.
+     */
+    vec<UserIdentificationAssociationSetValue> associations;
+};
+
+/**
+ * Defines the result of a USER_IDENTIFICATION_ASSOCIATION - both for get() and set().
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct UserIdentificationResponse {
+    /**
+     * Number of associations being returned.
+     */
+    int32_t numberAssociation;
+
+    /**
+     * Values associated with the user.
+     */
+    vec<UserIdentificationAssociation> associations;
+
+    /**
+     * HAL-specific error message.
+     *
+     * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be
+     * used to show custom error messages to the end user.
+     */
+    string errorMessage;
+};
+
+/**
+ * Helper struct used when getting a user/identification association type.
+ */
+struct UserIdentificationAssociation {
+
+    UserIdentificationAssociationType type;
+
+    UserIdentificationAssociationValue value;
+};
+
+/**
+ * Helper struct used when setting a user/identification association type.
+ */
+struct UserIdentificationSetAssociation {
+
+    UserIdentificationAssociationType type;
+
+    UserIdentificationAssociationSetValue value;
+};
diff --git a/bluetooth/1.0/vts/functional/Android.bp b/bluetooth/1.0/vts/functional/Android.bp
index 54039e5..cf25cc8 100644
--- a/bluetooth/1.0/vts/functional/Android.bp
+++ b/bluetooth/1.0/vts/functional/Android.bp
@@ -22,5 +22,8 @@
         "android.hardware.bluetooth@1.0",
         "libbluetooth-types",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h
index f6cd6ae..8ab2b43 100644
--- a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h
+++ b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h
@@ -82,33 +82,44 @@
     };                                                                \
     return EGMockFlippedComma_<decltype(invokeMock())>(invokeMock, notify);
 
+// We define this as a variadic macro in case F contains unprotected
+// commas (the same reason that we use variadic macros in other places
+// in this file).
+#define EGMOCK_RESULT_(tn, ...) \
+    tn ::testing::internal::Function<__VA_ARGS__>::Result
+
+// The type of argument N of the given function type.
+// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
+#define EGMOCK_ARG_(tn, N, ...) \
+    tn ::testing::internal::Function<__VA_ARGS__>::template Arg<N-1>::type
+
 /**
  * Gmock MOCK_METHOD0 timeout-capable extension.
  */
 #define MOCK_TIMEOUT_METHOD0(Method, ...)       \
     MOCK_METHOD0(egmock_##Method, __VA_ARGS__); \
     EGMOCK_TIMEOUT_METHOD_DEF_(Method);         \
-    virtual GMOCK_RESULT_(, __VA_ARGS__) Method() { EGMOCK_TIMEOUT_METHOD_BODY_(Method); }
+    virtual EGMOCK_RESULT_(, __VA_ARGS__) Method() { EGMOCK_TIMEOUT_METHOD_BODY_(Method); }
 
 /**
  * Gmock MOCK_METHOD1 timeout-capable extension.
  */
-#define MOCK_TIMEOUT_METHOD1(Method, ...)                                                 \
-    MOCK_METHOD1(egmock_##Method, __VA_ARGS__);                                           \
-    EGMOCK_TIMEOUT_METHOD_DEF_(Method);                                                   \
-    virtual GMOCK_RESULT_(, __VA_ARGS__) Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1) { \
-        EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1);                                   \
+#define MOCK_TIMEOUT_METHOD1(Method, ...)                                                   \
+    MOCK_METHOD1(egmock_##Method, __VA_ARGS__);                                             \
+    EGMOCK_TIMEOUT_METHOD_DEF_(Method);                                                     \
+    virtual EGMOCK_RESULT_(, __VA_ARGS__) Method(EGMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1) { \
+        EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1);                                     \
     }
 
 /**
  * Gmock MOCK_METHOD2 timeout-capable extension.
  */
-#define MOCK_TIMEOUT_METHOD2(Method, ...)                                                        \
-    MOCK_METHOD2(egmock_##Method, __VA_ARGS__);                                                  \
-    EGMOCK_TIMEOUT_METHOD_DEF_(Method);                                                          \
-    virtual GMOCK_RESULT_(, __VA_ARGS__)                                                         \
-        Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1, GMOCK_ARG_(, 2, __VA_ARGS__) egmock_a2) { \
-        EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1, egmock_a2);                               \
+#define MOCK_TIMEOUT_METHOD2(Method, ...)                                                          \
+    MOCK_METHOD2(egmock_##Method, __VA_ARGS__);                                                    \
+    EGMOCK_TIMEOUT_METHOD_DEF_(Method);                                                            \
+    virtual EGMOCK_RESULT_(, __VA_ARGS__)                                                          \
+        Method(EGMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1, EGMOCK_ARG_(, 2, __VA_ARGS__) egmock_a2) { \
+        EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1, egmock_a2);                                 \
     }
 
 /**
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index ac32c95..7792b31 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -182,9 +182,8 @@
     }
 
     Mutex::Autolock lock(mLock);
-    if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
-        ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
-        return;
+    if (!mInitialized) {
+        initializeLocked();
     }
 
     if (mMapperV4 != nullptr) {
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 9ff0d74..5f86742 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -81,8 +81,6 @@
     return locked;
 }
 
-buffer_handle_t sEmptyBuffer = nullptr;
-
 } // Anonymous namespace
 
 // Static instances
@@ -119,8 +117,8 @@
     std::string make, model;
     if (ret < 0) {
         ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__);
-        make = "Generic UVC webcam";
-        model = "Generic UVC webcam";
+        mExifMake = "Generic UVC webcam";
+        mExifModel = "Generic UVC webcam";
     } else {
         // capability.card is UTF-8 encoded
         char card[32];
@@ -134,11 +132,11 @@
             }
         }
         if (j == 0 || card[j - 1] != '\0') {
-            make = "Generic UVC webcam";
-            model = "Generic UVC webcam";
+            mExifMake = "Generic UVC webcam";
+            mExifModel = "Generic UVC webcam";
         } else {
-            make = card;
-            model = card;
+            mExifMake = card;
+            mExifModel = card;
         }
     }
 
@@ -147,7 +145,7 @@
         ALOGE("%s: init OutputThread failed!", __FUNCTION__);
         return true;
     }
-    mOutputThread->setExifMakeModel(make, model);
+    mOutputThread->setExifMakeModel(mExifMake, mExifModel);
 
     status_t status = initDefaultRequests();
     if (status != OK) {
@@ -161,7 +159,7 @@
         ALOGE("%s: invalid request fmq", __FUNCTION__);
         return true;
     }
-    mResultMetadataQueue = std::make_shared<RequestMetadataQueue>(
+    mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
             kMetadataMsgQueueSize, false /* non blocking */);
     if (!mResultMetadataQueue->isValid()) {
         ALOGE("%s: invalid result fmq", __FUNCTION__);
@@ -183,7 +181,7 @@
 }
 
 void ExternalCameraDeviceSession::initOutputThread() {
-    mOutputThread = new OutputThread(this, mCroppingType);
+    mOutputThread = new OutputThread(this, mCroppingType, mCameraCharacteristics);
 }
 
 void ExternalCameraDeviceSession::closeOutputThread() {
@@ -518,35 +516,9 @@
         uint64_t bufId, buffer_handle_t buf,
         /*out*/buffer_handle_t** outBufPtr,
         bool allowEmptyBuf) {
-
-    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
-        if (allowEmptyBuf) {
-            *outBufPtr = &sEmptyBuffer;
-            return Status::OK;
-        } else {
-            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
-            return Status::ILLEGAL_ARGUMENT;
-        }
-    }
-
-    CirculatingBuffers& cbs = mCirculatingBuffers[streamId];
-    if (cbs.count(bufId) == 0) {
-        if (buf == nullptr) {
-            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
-            return Status::ILLEGAL_ARGUMENT;
-        }
-        // Register a newly seen buffer
-        buffer_handle_t importedBuf = buf;
-        sHandleImporter.importBuffer(importedBuf);
-        if (importedBuf == nullptr) {
-            ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
-            return Status::INTERNAL_ERROR;
-        } else {
-            cbs[bufId] = importedBuf;
-        }
-    }
-    *outBufPtr = &cbs[bufId];
-    return Status::OK;
+    return importBufferImpl(
+            mCirculatingBuffers, sHandleImporter, streamId,
+            bufId, buf, outBufPtr, allowEmptyBuf);
 }
 
 Status ExternalCameraDeviceSession::importRequestLockedImpl(
@@ -791,15 +763,32 @@
 
 //TODO: refactor with processCaptureResult
 Status ExternalCameraDeviceSession::processCaptureRequestError(
-        const std::shared_ptr<HalRequest>& req) {
+        const std::shared_ptr<HalRequest>& req,
+        /*out*/std::vector<NotifyMsg>* outMsgs,
+        /*out*/std::vector<CaptureResult>* outResults) {
     ATRACE_CALL();
     // Return V4L2 buffer to V4L2 buffer queue
-    enqueueV4l2Frame(req->frameIn);
+    sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+            static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+    enqueueV4l2Frame(v4l2Frame);
 
-    // NotifyShutter
-    notifyShutter(req->frameNumber, req->shutterTs);
+    if (outMsgs == nullptr) {
+        notifyShutter(req->frameNumber, req->shutterTs);
+        notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+    } else {
+        NotifyMsg shutter;
+        shutter.type = MsgType::SHUTTER;
+        shutter.msg.shutter.frameNumber = req->frameNumber;
+        shutter.msg.shutter.timestamp = req->shutterTs;
 
-    notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+        NotifyMsg error;
+        error.type = MsgType::ERROR;
+        error.msg.error.frameNumber = req->frameNumber;
+        error.msg.error.errorStreamId = -1;
+        error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+        outMsgs->push_back(shutter);
+        outMsgs->push_back(error);
+    }
 
     // Fill output buffers
     hidl_vec<CaptureResult> results;
@@ -826,16 +815,22 @@
         mInflightFrames.erase(req->frameNumber);
     }
 
-    // Callback into framework
-    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
-    freeReleaseFences(results);
+    if (outResults == nullptr) {
+        // Callback into framework
+        invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+        freeReleaseFences(results);
+    } else {
+        outResults->push_back(result);
+    }
     return Status::OK;
 }
 
 Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
     ATRACE_CALL();
     // Return V4L2 buffer to V4L2 buffer queue
-    enqueueV4l2Frame(req->frameIn);
+    sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+            static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+    enqueueV4l2Frame(v4l2Frame);
 
     // NotifyShutter
     notifyShutter(req->frameNumber, req->shutterTs);
@@ -923,29 +918,10 @@
     mProcessCaptureResultLock.unlock();
 }
 
-void ExternalCameraDeviceSession::freeReleaseFences(hidl_vec<CaptureResult>& results) {
-    for (auto& result : results) {
-        if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
-            native_handle_t* handle = const_cast<native_handle_t*>(
-                    result.inputBuffer.releaseFence.getNativeHandle());
-            native_handle_close(handle);
-            native_handle_delete(handle);
-        }
-        for (auto& buf : result.outputBuffers) {
-            if (buf.releaseFence.getNativeHandle() != nullptr) {
-                native_handle_t* handle = const_cast<native_handle_t*>(
-                        buf.releaseFence.getNativeHandle());
-                native_handle_close(handle);
-                native_handle_delete(handle);
-            }
-        }
-    }
-    return;
-}
-
 ExternalCameraDeviceSession::OutputThread::OutputThread(
-        wp<ExternalCameraDeviceSession> parent,
-        CroppingType ct) : mParent(parent), mCroppingType(ct) {}
+        wp<OutputThreadInterface> parent, CroppingType ct,
+        const common::V1_0::helper::CameraMetadata& chars) :
+        mParent(parent), mCroppingType(ct), mCameraCharacteristics(chars) {}
 
 ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
 
@@ -955,88 +931,6 @@
     mExifModel = model;
 }
 
-uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout(
-        const YCbCrLayout& layout) {
-    intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
-    intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
-    if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
-        // Interleaved format
-        if (layout.cb > layout.cr) {
-            return V4L2_PIX_FMT_NV21;
-        } else {
-            return V4L2_PIX_FMT_NV12;
-        }
-    } else if (layout.chromaStep == 1) {
-        // Planar format
-        if (layout.cb > layout.cr) {
-            return V4L2_PIX_FMT_YVU420; // YV12
-        } else {
-            return V4L2_PIX_FMT_YUV420; // YU12
-        }
-    } else {
-        return FLEX_YUV_GENERIC;
-    }
-}
-
-int ExternalCameraDeviceSession::OutputThread::getCropRect(
-        CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
-    if (out == nullptr) {
-        ALOGE("%s: out is null", __FUNCTION__);
-        return -1;
-    }
-
-    uint32_t inW = inSize.width;
-    uint32_t inH = inSize.height;
-    uint32_t outW = outSize.width;
-    uint32_t outH = outSize.height;
-
-    // Handle special case where aspect ratio is close to input but scaled
-    // dimension is slightly larger than input
-    float arIn = ASPECT_RATIO(inSize);
-    float arOut = ASPECT_RATIO(outSize);
-    if (isAspectRatioClose(arIn, arOut)) {
-        out->left = 0;
-        out->top = 0;
-        out->width = inW;
-        out->height = inH;
-        return 0;
-    }
-
-    if (ct == VERTICAL) {
-        uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
-        if (scaledOutH > inH) {
-            ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
-                    __FUNCTION__, outW, outH, inW, inH);
-            return -1;
-        }
-        scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
-
-        out->left = 0;
-        out->top = ((inH - scaledOutH) / 2) & ~0x1;
-        out->width = inW;
-        out->height = static_cast<int32_t>(scaledOutH);
-        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
-                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
-    } else {
-        uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
-        if (scaledOutW > inW) {
-            ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
-                    __FUNCTION__, outW, outH, inW, inH);
-            return -1;
-        }
-        scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
-
-        out->left = ((inW - scaledOutW) / 2) & ~0x1;
-        out->top = 0;
-        out->width = static_cast<int32_t>(scaledOutW);
-        out->height = inH;
-        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
-                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
-    }
-
-    return 0;
-}
-
 int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
         sp<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
     Size inSz = {in->mWidth, in->mHeight};
@@ -1274,265 +1168,6 @@
     return 0;
 }
 
-int ExternalCameraDeviceSession::OutputThread::formatConvertLocked(
-        const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
-    int ret = 0;
-    switch (format) {
-        case V4L2_PIX_FMT_NV21:
-            ret = libyuv::I420ToNV21(
-                    static_cast<uint8_t*>(in.y),
-                    in.yStride,
-                    static_cast<uint8_t*>(in.cb),
-                    in.cStride,
-                    static_cast<uint8_t*>(in.cr),
-                    in.cStride,
-                    static_cast<uint8_t*>(out.y),
-                    out.yStride,
-                    static_cast<uint8_t*>(out.cr),
-                    out.cStride,
-                    sz.width,
-                    sz.height);
-            if (ret != 0) {
-                ALOGE("%s: convert to NV21 buffer failed! ret %d",
-                            __FUNCTION__, ret);
-                return ret;
-            }
-            break;
-        case V4L2_PIX_FMT_NV12:
-            ret = libyuv::I420ToNV12(
-                    static_cast<uint8_t*>(in.y),
-                    in.yStride,
-                    static_cast<uint8_t*>(in.cb),
-                    in.cStride,
-                    static_cast<uint8_t*>(in.cr),
-                    in.cStride,
-                    static_cast<uint8_t*>(out.y),
-                    out.yStride,
-                    static_cast<uint8_t*>(out.cb),
-                    out.cStride,
-                    sz.width,
-                    sz.height);
-            if (ret != 0) {
-                ALOGE("%s: convert to NV12 buffer failed! ret %d",
-                            __FUNCTION__, ret);
-                return ret;
-            }
-            break;
-        case V4L2_PIX_FMT_YVU420: // YV12
-        case V4L2_PIX_FMT_YUV420: // YU12
-            // TODO: maybe we can speed up here by somehow save this copy?
-            ret = libyuv::I420Copy(
-                    static_cast<uint8_t*>(in.y),
-                    in.yStride,
-                    static_cast<uint8_t*>(in.cb),
-                    in.cStride,
-                    static_cast<uint8_t*>(in.cr),
-                    in.cStride,
-                    static_cast<uint8_t*>(out.y),
-                    out.yStride,
-                    static_cast<uint8_t*>(out.cb),
-                    out.cStride,
-                    static_cast<uint8_t*>(out.cr),
-                    out.cStride,
-                    sz.width,
-                    sz.height);
-            if (ret != 0) {
-                ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
-                            __FUNCTION__, ret);
-                return ret;
-            }
-            break;
-        case FLEX_YUV_GENERIC:
-            // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
-            ALOGE("%s: unsupported flexible yuv layout"
-                    " y %p cb %p cr %p y_str %d c_str %d c_step %d",
-                    __FUNCTION__, out.y, out.cb, out.cr,
-                    out.yStride, out.cStride, out.chromaStep);
-            return -1;
-        default:
-            ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
-            return -1;
-    }
-    return 0;
-}
-
-int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12(
-        const Size & inSz, const YCbCrLayout& inLayout,
-        int jpegQuality, const void *app1Buffer, size_t app1Size,
-        void *out, const size_t maxOutSize, size_t &actualCodeSize)
-{
-    /* libjpeg is a C library so we use C-style "inheritance" by
-     * putting libjpeg's jpeg_destination_mgr first in our custom
-     * struct. This allows us to cast jpeg_destination_mgr* to
-     * CustomJpegDestMgr* when we get it passed to us in a callback */
-    struct CustomJpegDestMgr {
-        struct jpeg_destination_mgr mgr;
-        JOCTET *mBuffer;
-        size_t mBufferSize;
-        size_t mEncodedSize;
-        bool mSuccess;
-    } dmgr;
-
-    jpeg_compress_struct cinfo = {};
-    jpeg_error_mgr jerr;
-
-    /* Initialize error handling with standard callbacks, but
-     * then override output_message (to print to ALOG) and
-     * error_exit to set a flag and print a message instead
-     * of killing the whole process */
-    cinfo.err = jpeg_std_error(&jerr);
-
-    cinfo.err->output_message = [](j_common_ptr cinfo) {
-        char buffer[JMSG_LENGTH_MAX];
-
-        /* Create the message */
-        (*cinfo->err->format_message)(cinfo, buffer);
-        ALOGE("libjpeg error: %s", buffer);
-    };
-    cinfo.err->error_exit = [](j_common_ptr cinfo) {
-        (*cinfo->err->output_message)(cinfo);
-        if(cinfo->client_data) {
-            auto & dmgr =
-                *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
-            dmgr.mSuccess = false;
-        }
-    };
-    /* Now that we initialized some callbacks, let's create our compressor */
-    jpeg_create_compress(&cinfo);
-
-    /* Initialize our destination manager */
-    dmgr.mBuffer = static_cast<JOCTET*>(out);
-    dmgr.mBufferSize = maxOutSize;
-    dmgr.mEncodedSize = 0;
-    dmgr.mSuccess = true;
-    cinfo.client_data = static_cast<void*>(&dmgr);
-
-    /* These lambdas become C-style function pointers and as per C++11 spec
-     * may not capture anything */
-    dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
-        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
-        dmgr.mgr.next_output_byte = dmgr.mBuffer;
-        dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
-        ALOGV("%s:%d jpeg start: %p [%zu]",
-              __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
-    };
-
-    dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
-        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
-        return 0;
-    };
-
-    dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
-        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
-        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
-        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
-    };
-    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
-
-    /* We are going to be using JPEG in raw data mode, so we are passing
-     * straight subsampled planar YCbCr and it will not touch our pixel
-     * data or do any scaling or anything */
-    cinfo.image_width = inSz.width;
-    cinfo.image_height = inSz.height;
-    cinfo.input_components = 3;
-    cinfo.in_color_space = JCS_YCbCr;
-
-    /* Initialize defaults and then override what we want */
-    jpeg_set_defaults(&cinfo);
-
-    jpeg_set_quality(&cinfo, jpegQuality, 1);
-    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
-    cinfo.raw_data_in = 1;
-    cinfo.dct_method = JDCT_IFAST;
-
-    /* Configure sampling factors. The sampling factor is JPEG subsampling 420
-     * because the source format is YUV420. Note that libjpeg sampling factors
-     * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
-     * 1 V value for each 2 Y values */
-    cinfo.comp_info[0].h_samp_factor = 2;
-    cinfo.comp_info[0].v_samp_factor = 2;
-    cinfo.comp_info[1].h_samp_factor = 1;
-    cinfo.comp_info[1].v_samp_factor = 1;
-    cinfo.comp_info[2].h_samp_factor = 1;
-    cinfo.comp_info[2].v_samp_factor = 1;
-
-    /* Let's not hardcode YUV420 in 6 places... 5 was enough */
-    int maxVSampFactor = std::max( {
-        cinfo.comp_info[0].v_samp_factor,
-        cinfo.comp_info[1].v_samp_factor,
-        cinfo.comp_info[2].v_samp_factor
-    });
-    int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
-                        cinfo.comp_info[1].v_samp_factor;
-
-    /* Start the compressor */
-    jpeg_start_compress(&cinfo, TRUE);
-
-    /* Compute our macroblock height, so we can pad our input to be vertically
-     * macroblock aligned.
-     * TODO: Does it need to be horizontally MCU aligned too? */
-
-    size_t mcuV = DCTSIZE*maxVSampFactor;
-    size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
-
-    /* libjpeg uses arrays of row pointers, which makes it really easy to pad
-     * data vertically (unfortunately doesn't help horizontally) */
-    std::vector<JSAMPROW> yLines (paddedHeight);
-    std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
-    std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
-
-    uint8_t *py = static_cast<uint8_t*>(inLayout.y);
-    uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
-    uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
-
-    for(uint32_t i = 0; i < paddedHeight; i++)
-    {
-        /* Once we are in the padding territory we still point to the last line
-         * effectively replicating it several times ~ CLAMP_TO_EDGE */
-        int li = std::min(i, inSz.height - 1);
-        yLines[i]  = static_cast<JSAMPROW>(py + li * inLayout.yStride);
-        if(i < paddedHeight / cVSubSampling)
-        {
-            crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
-            cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
-        }
-    }
-
-    /* If APP1 data was passed in, use it */
-    if(app1Buffer && app1Size)
-    {
-        jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
-             static_cast<const JOCTET*>(app1Buffer), app1Size);
-    }
-
-    /* While we still have padded height left to go, keep giving it one
-     * macroblock at a time. */
-    while (cinfo.next_scanline < cinfo.image_height) {
-        const uint32_t batchSize = DCTSIZE * maxVSampFactor;
-        const uint32_t nl = cinfo.next_scanline;
-        JSAMPARRAY planes[3]{ &yLines[nl],
-                              &cbLines[nl/cVSubSampling],
-                              &crLines[nl/cVSubSampling] };
-
-        uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
-
-        if (done != batchSize) {
-            ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
-              __FUNCTION__, done, batchSize, cinfo.next_scanline,
-              cinfo.image_height);
-            return -1;
-        }
-    }
-
-    /* This will flush everything */
-    jpeg_finish_compress(&cinfo);
-
-    /* Grab the actual code size and set it */
-    actualCodeSize = dmgr.mEncodedSize;
-
-    return 0;
-}
-
 /*
  * TODO: There needs to be a mechanism to discover allocated buffer size
  * in the HAL.
@@ -1555,25 +1190,9 @@
 }
 
 Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
-    Size thumbSize { 0, 0 };
-    camera_metadata_ro_entry entry =
-        mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
-    for(uint32_t i = 0; i < entry.count; i += 2) {
-        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
-                  static_cast<uint32_t>(entry.data.i32[i+1]) };
-        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
-            thumbSize = sz;
-        }
-    }
-
-    if (thumbSize.width * thumbSize.height == 0) {
-        ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
-    }
-
-    return thumbSize;
+    return getMaxThumbnailResolution(mCameraCharacteristics);
 }
 
-
 ssize_t ExternalCameraDeviceSession::getJpegBufferSize(
         uint32_t width, uint32_t height) const {
     // Constant from camera3.h
@@ -1616,7 +1235,7 @@
 
 int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
         HalStreamBuffer &halBuf,
-        const std::shared_ptr<HalRequest>& req)
+        const common::V1_0::helper::CameraMetadata& setting)
 {
     ATRACE_CALL();
     int ret;
@@ -1645,17 +1264,17 @@
     Size thumbSize;
     bool outputThumbnail = true;
 
-    if (req->setting.exists(ANDROID_JPEG_QUALITY)) {
-        camera_metadata_entry entry =
-            req->setting.find(ANDROID_JPEG_QUALITY);
+    if (setting.exists(ANDROID_JPEG_QUALITY)) {
+        camera_metadata_ro_entry entry =
+            setting.find(ANDROID_JPEG_QUALITY);
         jpegQuality = entry.data.u8[0];
     } else {
         return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__);
     }
 
-    if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
-        camera_metadata_entry entry =
-            req->setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+    if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+        camera_metadata_ro_entry entry =
+            setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
         thumbQuality = entry.data.u8[0];
     } else {
         return lfail(
@@ -1663,9 +1282,9 @@
             __FUNCTION__);
     }
 
-    if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
-        camera_metadata_entry entry =
-            req->setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+    if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+        camera_metadata_ro_entry entry =
+            setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
         thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
                            static_cast<uint32_t>(entry.data.i32[1])
         };
@@ -1732,8 +1351,8 @@
 
     /* Combine camera characteristics with request settings to form EXIF
      * metadata */
-    common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics);
-    meta.append(req->setting);
+    common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics);
+    meta.append(setting);
 
     /* Generate EXIF object */
     std::unique_ptr<ExifUtils> utils(ExifUtils::create());
@@ -1838,7 +1457,7 @@
     // TODO: see if we can save some computation by converting to YV12 here
     uint8_t* inData;
     size_t inDataSize;
-    if (req->frameIn->map(&inData, &inDataSize) != 0) {
+    if (req->frameIn->getData(&inData, &inDataSize) != 0) {
         lk.unlock();
         return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
     }
@@ -1899,7 +1518,7 @@
         // Gralloc lockYCbCr the buffer
         switch (halBuf.format) {
             case PixelFormat::BLOB: {
-                int ret = createJpegLocked(halBuf, req);
+                int ret = createJpegLocked(halBuf, req->setting);
 
                 if(ret != 0) {
                     lk.unlock();
@@ -1949,8 +1568,8 @@
                 }
 
                 Size sz {halBuf.width, halBuf.height};
-                ATRACE_BEGIN("formatConvertLocked");
-                ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc);
+                ATRACE_BEGIN("formatConvert");
+                ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
                 ATRACE_END();
                 if (ret != 0) {
                     lk.unlock();
@@ -2055,6 +1674,14 @@
     return Status::OK;
 }
 
+void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() {
+    std::lock_guard<std::mutex> lk(mBufferLock);
+    mYu12Frame.clear();
+    mYu12ThumbFrame.clear();
+    mIntermediateBuffers.clear();
+    mBlobBufferSize = 0;
+}
+
 Status ExternalCameraDeviceSession::OutputThread::submitRequest(
         const std::shared_ptr<HalRequest>& req) {
     std::unique_lock<std::mutex> lk(mRequestListLock);
@@ -2090,6 +1717,32 @@
     }
 }
 
+std::list<std::shared_ptr<HalRequest>>
+ExternalCameraDeviceSession::OutputThread::switchToOffline() {
+    ATRACE_CALL();
+    std::list<std::shared_ptr<HalRequest>> emptyList;
+    auto parent = mParent.promote();
+    if (parent == nullptr) {
+       ALOGE("%s: session has been disconnected!", __FUNCTION__);
+       return emptyList;
+    }
+
+    std::unique_lock<std::mutex> lk(mRequestListLock);
+    std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
+    mRequestList.clear();
+    if (mProcessingRequest) {
+        std::chrono::seconds timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+        auto st = mRequestDoneCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+        }
+    }
+    lk.unlock();
+    clearIntermediateBuffers();
+    ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size());
+    return reqs;
+}
+
 void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(
         std::shared_ptr<HalRequest>* out) {
     ATRACE_CALL();
@@ -2733,6 +2386,7 @@
         return Status::INTERNAL_ERROR;
     }
 
+    mBlobBufferSize = blobBufferSize;
     status = mOutputThread->allocateIntermediateBuffers(v4lSize,
                 mMaxThumbResolution, config.streams, blobBufferSize);
     if (status != Status::OK) {
@@ -2916,16 +2570,6 @@
 
 status_t ExternalCameraDeviceSession::fillCaptureResult(
         common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
-    // android.control
-    // For USB camera, we don't know the AE state. Set the state to converged to
-    // indicate the frame should be good to use. Then apps don't have to wait the
-    // AE state.
-    const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
-    UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
-
-    const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
-    UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
-
     bool afTrigger = false;
     {
         std::lock_guard<std::mutex> lk(mAfTriggerLock);
@@ -2951,46 +2595,10 @@
     }
     UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
 
-    // Set AWB state to converged to indicate the frame should be good to use.
-    const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
-    UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+    camera_metadata_ro_entry activeArraySize =
+            mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
 
-    const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
-    UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
-
-    camera_metadata_ro_entry active_array_size =
-        mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
-
-    if (active_array_size.count == 0) {
-        ALOGE("%s: cannot find active array size!", __FUNCTION__);
-        return -EINVAL;
-    }
-
-    const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
-    UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
-
-    // This means pipeline latency of X frame intervals. The maximum number is 4.
-    const uint8_t requestPipelineMaxDepth = 4;
-    UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
-
-    // android.scaler
-    const int32_t crop_region[] = {
-          active_array_size.data.i32[0], active_array_size.data.i32[1],
-          active_array_size.data.i32[2], active_array_size.data.i32[3],
-    };
-    UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
-
-    // android.sensor
-    UPDATE(md, ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
-
-    // android.statistics
-    const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
-    UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
-
-    const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
-    UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
-
-    return OK;
+    return fillCaptureResultCommon(md, timestamp, activeArraySize);
 }
 
 #undef ARRAY_SIZE
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index e25deff..62a4c87 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -18,10 +18,23 @@
 #include <log/log.h>
 
 #include <cmath>
+#include <cstring>
 #include <sys/mman.h>
 #include <linux/videodev2.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <jpeglib.h>
+
 #include "ExternalCameraUtils.h"
 
+namespace {
+
+buffer_handle_t sEmptyBuffer = nullptr;
+
+} // Anonymous namespace
+
 namespace android {
 namespace hardware {
 namespace camera {
@@ -29,10 +42,13 @@
 namespace V3_4 {
 namespace implementation {
 
+Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc) :
+        mWidth(width), mHeight(height), mFourcc(fourcc) {}
+
 V4L2Frame::V4L2Frame(
         uint32_t w, uint32_t h, uint32_t fourcc,
         int bufIdx, int fd, uint32_t dataSize, uint64_t offset) :
-        mWidth(w), mHeight(h), mFourcc(fourcc),
+        Frame(w, h, fourcc),
         mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {}
 
 int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
@@ -75,9 +91,13 @@
     unmap();
 }
 
+int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+    return map(outData, dataSize);
+}
+
 AllocatedFrame::AllocatedFrame(
         uint32_t w, uint32_t h) :
-        mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {};
+        Frame(w, h, V4L2_PIX_FMT_YUV420) {};
 
 AllocatedFrame::~AllocatedFrame() {}
 
@@ -106,6 +126,17 @@
     return 0;
 }
 
+int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) {
+    YCbCrLayout layout;
+    int ret = allocate(&layout);
+    if (ret != 0) {
+        return ret;
+    }
+    *outData = mData.data();
+    *dataSize = mData.size();
+    return 0;
+}
+
 int AllocatedFrame::getLayout(YCbCrLayout* out) {
     IMapper::Rect noCrop = {0, 0,
             static_cast<int32_t>(mWidth),
@@ -150,8 +181,521 @@
     return durationDenominator / static_cast<double>(durationNumerator);
 }
 
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+        /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*inout*/HandleImporter& handleImporter,
+        int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf) {
+    using ::android::hardware::camera::common::V1_0::Status;
+    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+        if (allowEmptyBuf) {
+            *outBufPtr = &sEmptyBuffer;
+            return Status::OK;
+        } else {
+            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+            return Status::ILLEGAL_ARGUMENT;
+        }
+    }
+
+    CirculatingBuffers& cbs = circulatingBuffers[streamId];
+    if (cbs.count(bufId) == 0) {
+        if (buf == nullptr) {
+            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+            return Status::ILLEGAL_ARGUMENT;
+        }
+        // Register a newly seen buffer
+        buffer_handle_t importedBuf = buf;
+        handleImporter.importBuffer(importedBuf);
+        if (importedBuf == nullptr) {
+            ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
+            return Status::INTERNAL_ERROR;
+        } else {
+            cbs[bufId] = importedBuf;
+        }
+    }
+    *outBufPtr = &cbs[bufId];
+    return Status::OK;
+}
+
+uint32_t getFourCcFromLayout(const YCbCrLayout& layout) {
+    intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
+    intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
+    if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
+        // Interleaved format
+        if (layout.cb > layout.cr) {
+            return V4L2_PIX_FMT_NV21;
+        } else {
+            return V4L2_PIX_FMT_NV12;
+        }
+    } else if (layout.chromaStep == 1) {
+        // Planar format
+        if (layout.cb > layout.cr) {
+            return V4L2_PIX_FMT_YVU420; // YV12
+        } else {
+            return V4L2_PIX_FMT_YUV420; // YU12
+        }
+    } else {
+        return FLEX_YUV_GENERIC;
+    }
+}
+
+int getCropRect(
+        CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
+    if (out == nullptr) {
+        ALOGE("%s: out is null", __FUNCTION__);
+        return -1;
+    }
+
+    uint32_t inW = inSize.width;
+    uint32_t inH = inSize.height;
+    uint32_t outW = outSize.width;
+    uint32_t outH = outSize.height;
+
+    // Handle special case where aspect ratio is close to input but scaled
+    // dimension is slightly larger than input
+    float arIn = ASPECT_RATIO(inSize);
+    float arOut = ASPECT_RATIO(outSize);
+    if (isAspectRatioClose(arIn, arOut)) {
+        out->left = 0;
+        out->top = 0;
+        out->width = inW;
+        out->height = inH;
+        return 0;
+    }
+
+    if (ct == VERTICAL) {
+        uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
+        if (scaledOutH > inH) {
+            ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
+                    __FUNCTION__, outW, outH, inW, inH);
+            return -1;
+        }
+        scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
+
+        out->left = 0;
+        out->top = ((inH - scaledOutH) / 2) & ~0x1;
+        out->width = inW;
+        out->height = static_cast<int32_t>(scaledOutH);
+        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
+                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
+    } else {
+        uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
+        if (scaledOutW > inW) {
+            ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
+                    __FUNCTION__, outW, outH, inW, inH);
+            return -1;
+        }
+        scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
+
+        out->left = ((inW - scaledOutW) / 2) & ~0x1;
+        out->top = 0;
+        out->width = static_cast<int32_t>(scaledOutW);
+        out->height = inH;
+        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
+                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
+    }
+
+    return 0;
+}
+
+int formatConvert(
+        const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
+    int ret = 0;
+    switch (format) {
+        case V4L2_PIX_FMT_NV21:
+            ret = libyuv::I420ToNV21(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cr),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: convert to NV21 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case V4L2_PIX_FMT_NV12:
+            ret = libyuv::I420ToNV12(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cb),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: convert to NV12 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case V4L2_PIX_FMT_YVU420: // YV12
+        case V4L2_PIX_FMT_YUV420: // YU12
+            // TODO: maybe we can speed up here by somehow save this copy?
+            ret = libyuv::I420Copy(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cb),
+                    out.cStride,
+                    static_cast<uint8_t*>(out.cr),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case FLEX_YUV_GENERIC:
+            // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
+            ALOGE("%s: unsupported flexible yuv layout"
+                    " y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                    __FUNCTION__, out.y, out.cb, out.cr,
+                    out.yStride, out.cStride, out.chromaStep);
+            return -1;
+        default:
+            ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
+            return -1;
+    }
+    return 0;
+}
+
+int encodeJpegYU12(
+        const Size & inSz, const YCbCrLayout& inLayout,
+        int jpegQuality, const void *app1Buffer, size_t app1Size,
+        void *out, const size_t maxOutSize, size_t &actualCodeSize)
+{
+    /* libjpeg is a C library so we use C-style "inheritance" by
+     * putting libjpeg's jpeg_destination_mgr first in our custom
+     * struct. This allows us to cast jpeg_destination_mgr* to
+     * CustomJpegDestMgr* when we get it passed to us in a callback */
+    struct CustomJpegDestMgr {
+        struct jpeg_destination_mgr mgr;
+        JOCTET *mBuffer;
+        size_t mBufferSize;
+        size_t mEncodedSize;
+        bool mSuccess;
+    } dmgr;
+
+    jpeg_compress_struct cinfo = {};
+    jpeg_error_mgr jerr;
+
+    /* Initialize error handling with standard callbacks, but
+     * then override output_message (to print to ALOG) and
+     * error_exit to set a flag and print a message instead
+     * of killing the whole process */
+    cinfo.err = jpeg_std_error(&jerr);
+
+    cinfo.err->output_message = [](j_common_ptr cinfo) {
+        char buffer[JMSG_LENGTH_MAX];
+
+        /* Create the message */
+        (*cinfo->err->format_message)(cinfo, buffer);
+        ALOGE("libjpeg error: %s", buffer);
+    };
+    cinfo.err->error_exit = [](j_common_ptr cinfo) {
+        (*cinfo->err->output_message)(cinfo);
+        if(cinfo->client_data) {
+            auto & dmgr =
+                *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+            dmgr.mSuccess = false;
+        }
+    };
+    /* Now that we initialized some callbacks, let's create our compressor */
+    jpeg_create_compress(&cinfo);
+
+    /* Initialize our destination manager */
+    dmgr.mBuffer = static_cast<JOCTET*>(out);
+    dmgr.mBufferSize = maxOutSize;
+    dmgr.mEncodedSize = 0;
+    dmgr.mSuccess = true;
+    cinfo.client_data = static_cast<void*>(&dmgr);
+
+    /* These lambdas become C-style function pointers and as per C++11 spec
+     * may not capture anything */
+    dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mgr.next_output_byte = dmgr.mBuffer;
+        dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+        ALOGV("%s:%d jpeg start: %p [%zu]",
+              __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+    };
+
+    dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+        return 0;
+    };
+
+    dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+    };
+    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+    /* We are going to be using JPEG in raw data mode, so we are passing
+     * straight subsampled planar YCbCr and it will not touch our pixel
+     * data or do any scaling or anything */
+    cinfo.image_width = inSz.width;
+    cinfo.image_height = inSz.height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_YCbCr;
+
+    /* Initialize defaults and then override what we want */
+    jpeg_set_defaults(&cinfo);
+
+    jpeg_set_quality(&cinfo, jpegQuality, 1);
+    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+    cinfo.raw_data_in = 1;
+    cinfo.dct_method = JDCT_IFAST;
+
+    /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+     * because the source format is YUV420. Note that libjpeg sampling factors
+     * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+     * 1 V value for each 2 Y values */
+    cinfo.comp_info[0].h_samp_factor = 2;
+    cinfo.comp_info[0].v_samp_factor = 2;
+    cinfo.comp_info[1].h_samp_factor = 1;
+    cinfo.comp_info[1].v_samp_factor = 1;
+    cinfo.comp_info[2].h_samp_factor = 1;
+    cinfo.comp_info[2].v_samp_factor = 1;
+
+    /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+    int maxVSampFactor = std::max( {
+        cinfo.comp_info[0].v_samp_factor,
+        cinfo.comp_info[1].v_samp_factor,
+        cinfo.comp_info[2].v_samp_factor
+    });
+    int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
+                        cinfo.comp_info[1].v_samp_factor;
+
+    /* Start the compressor */
+    jpeg_start_compress(&cinfo, TRUE);
+
+    /* Compute our macroblock height, so we can pad our input to be vertically
+     * macroblock aligned.
+     * TODO: Does it need to be horizontally MCU aligned too? */
+
+    size_t mcuV = DCTSIZE*maxVSampFactor;
+    size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+    /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+     * data vertically (unfortunately doesn't help horizontally) */
+    std::vector<JSAMPROW> yLines (paddedHeight);
+    std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
+    std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
+
+    uint8_t *py = static_cast<uint8_t*>(inLayout.y);
+    uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
+    uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
+
+    for(uint32_t i = 0; i < paddedHeight; i++)
+    {
+        /* Once we are in the padding territory we still point to the last line
+         * effectively replicating it several times ~ CLAMP_TO_EDGE */
+        int li = std::min(i, inSz.height - 1);
+        yLines[i]  = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+        if(i < paddedHeight / cVSubSampling)
+        {
+            li = std::min(i, (inSz.height - 1) / cVSubSampling);
+            crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+            cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+        }
+    }
+
+    /* If APP1 data was passed in, use it */
+    if(app1Buffer && app1Size)
+    {
+        jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
+             static_cast<const JOCTET*>(app1Buffer), app1Size);
+    }
+
+    /* While we still have padded height left to go, keep giving it one
+     * macroblock at a time. */
+    while (cinfo.next_scanline < cinfo.image_height) {
+        const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+        const uint32_t nl = cinfo.next_scanline;
+        JSAMPARRAY planes[3]{ &yLines[nl],
+                              &cbLines[nl/cVSubSampling],
+                              &crLines[nl/cVSubSampling] };
+
+        uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+        if (done != batchSize) {
+            ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
+              __FUNCTION__, done, batchSize, cinfo.next_scanline,
+              cinfo.image_height);
+            return -1;
+        }
+    }
+
+    /* This will flush everything */
+    jpeg_finish_compress(&cinfo);
+
+    /* Grab the actual code size and set it */
+    actualCodeSize = dmgr.mEncodedSize;
+
+    return 0;
+}
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) {
+    Size thumbSize { 0, 0 };
+    camera_metadata_ro_entry entry =
+        chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for(uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+                  static_cast<uint32_t>(entry.data.i32[i+1]) };
+        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+    }
+
+    return thumbSize;
+}
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>& results) {
+    for (auto& result : results) {
+        if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+            native_handle_t* handle = const_cast<native_handle_t*>(
+                    result.inputBuffer.releaseFence.getNativeHandle());
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+        for (auto& buf : result.outputBuffers) {
+            if (buf.releaseFence.getNativeHandle() != nullptr) {
+                native_handle_t* handle = const_cast<native_handle_t*>(
+                        buf.releaseFence.getNativeHandle());
+                native_handle_close(handle);
+                native_handle_delete(handle);
+            }
+        }
+    }
+    return;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define UPDATE(md, tag, data, size)               \
+do {                                              \
+    if ((md).update((tag), (data), (size))) {     \
+        ALOGE("Update " #tag " failed!");         \
+        return BAD_VALUE;                         \
+    }                                             \
+} while (0)
+
+status_t fillCaptureResultCommon(
+        common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp,
+        camera_metadata_ro_entry& activeArraySize) {
+    if (activeArraySize.count < 4) {
+        ALOGE("%s: cannot find active array size!", __FUNCTION__);
+        return -EINVAL;
+    }
+    // android.control
+    // For USB camera, we don't know the AE state. Set the state to converged to
+    // indicate the frame should be good to use. Then apps don't have to wait the
+    // AE state.
+    const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
+    UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
+
+    const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+    UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
+
+    // Set AWB state to converged to indicate the frame should be good to use.
+    const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
+    UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+
+    const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+    UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
+
+    const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+    UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
+    // This means pipeline latency of X frame intervals. The maximum number is 4.
+    const uint8_t requestPipelineMaxDepth = 4;
+    UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
+
+    // android.scaler
+    const int32_t crop_region[] = {
+          activeArraySize.data.i32[0], activeArraySize.data.i32[1],
+          activeArraySize.data.i32[2], activeArraySize.data.i32[3],
+    };
+    UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
+
+    // android.sensor
+    UPDATE(md, ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
+
+    // android.statistics
+    const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+    UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
+
+    const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
+    UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
+
+    return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
 }  // namespace implementation
 }  // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+AllocatedV4L2Frame::AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn) :
+        Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) {
+    uint8_t* dataIn;
+    size_t dataSize;
+    if (frameIn->getData(&dataIn, &dataSize) != 0) {
+        ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__);
+        return;
+    }
+
+    mData.resize(dataSize);
+    std::memcpy(mData.data(), dataIn, dataSize);
+}
+
+int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+    if (outData == nullptr || dataSize == nullptr) {
+        ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize);
+        return -1;
+    }
+
+    *outData = mData.data();
+    *dataSize = mData.size();
+    return 0;
+}
+
+AllocatedV4L2Frame::~AllocatedV4L2Frame() {}
+
+}  // namespace implementation
+}  // namespace V3_6
 }  // namespace device
 
 
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index 71b7c17..180f0c1 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
@@ -84,7 +84,8 @@
 using ::android::Mutex;
 using ::android::base::unique_fd;
 
-struct ExternalCameraDeviceSession : public virtual RefBase {
+struct ExternalCameraDeviceSession : public virtual RefBase,
+        public virtual OutputThreadInterface {
 
     ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
             const ExternalCameraConfig& cfg,
@@ -110,6 +111,82 @@
     static const int kMaxStallStream = 1;
     static const uint32_t kMaxBytesPerPixel = 2;
 
+    class OutputThread : public android::Thread {
+    public:
+        OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+                const common::V1_0::helper::CameraMetadata&);
+        virtual ~OutputThread();
+
+        Status allocateIntermediateBuffers(
+                const Size& v4lSize, const Size& thumbSize,
+                const hidl_vec<Stream>& streams,
+                uint32_t blobBufferSize);
+        Status submitRequest(const std::shared_ptr<HalRequest>&);
+        void flush();
+        void dump(int fd);
+        virtual bool threadLoop() override;
+
+        void setExifMakeModel(const std::string& make, const std::string& model);
+
+        // The remaining request list is returned for offline processing
+        std::list<std::shared_ptr<HalRequest>> switchToOffline();
+
+    protected:
+        // Methods to request output buffer in parallel
+        // No-op for device@3.4. Implemented in device@3.5
+        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
+        virtual int waitForBufferRequestDone(
+                /*out*/std::vector<HalStreamBuffer>*) { return 0; }
+
+        static const int kFlushWaitTimeoutSec = 3; // 3 sec
+        static const int kReqWaitTimeoutMs = 33;   // 33ms
+        static const int kReqWaitTimesMax = 90;    // 33ms * 90 ~= 3 sec
+
+        void waitForNextRequest(std::shared_ptr<HalRequest>* out);
+        void signalRequestDone();
+
+        int cropAndScaleLocked(
+                sp<AllocatedFrame>& in, const Size& outSize,
+                YCbCrLayout* out);
+
+        int cropAndScaleThumbLocked(
+                sp<AllocatedFrame>& in, const Size& outSize,
+                YCbCrLayout* out);
+
+        int createJpegLocked(HalStreamBuffer &halBuf,
+                const common::V1_0::helper::CameraMetadata& settings);
+
+        void clearIntermediateBuffers();
+
+        const wp<OutputThreadInterface> mParent;
+        const CroppingType mCroppingType;
+        const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+        mutable std::mutex mRequestListLock;      // Protect acccess to mRequestList,
+                                                  // mProcessingRequest and mProcessingFrameNumer
+        std::condition_variable mRequestCond;     // signaled when a new request is submitted
+        std::condition_variable mRequestDoneCond; // signaled when a request is done processing
+        std::list<std::shared_ptr<HalRequest>> mRequestList;
+        bool mProcessingRequest = false;
+        uint32_t mProcessingFrameNumer = 0;
+
+        // V4L2 frameIn
+        // (MJPG decode)-> mYu12Frame
+        // (Scale)-> mScaledYu12Frames
+        // (Format convert) -> output gralloc frames
+        mutable std::mutex mBufferLock; // Protect access to intermediate buffers
+        sp<AllocatedFrame> mYu12Frame;
+        sp<AllocatedFrame> mYu12ThumbFrame;
+        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
+        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
+        YCbCrLayout mYu12FrameLayout;
+        YCbCrLayout mYu12ThumbFrameLayout;
+        uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
+
+        std::string mExifMake;
+        std::string mExifModel;
+    };
+
 protected:
 
     // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow
@@ -150,27 +227,22 @@
             ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb);
 
 protected:
-    struct HalStreamBuffer {
-        int32_t streamId;
-        uint64_t bufferId;
-        uint32_t width;
-        uint32_t height;
-        PixelFormat format;
-        V3_2::BufferUsageFlags usage;
-        buffer_handle_t* bufPtr;
-        int acquireFence;
-        bool fenceTimeout;
-    };
+    // Methods from OutputThreadInterface
+    virtual Status importBuffer(int32_t streamId,
+            uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr,
+            bool allowEmptyBuf) override;
 
-    struct HalRequest {
-        uint32_t frameNumber;
-        common::V1_0::helper::CameraMetadata setting;
-        sp<V4L2Frame> frameIn;
-        nsecs_t shutterTs;
-        std::vector<HalStreamBuffer> buffers;
-    };
+    virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
 
-    static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+    virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+        /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+        /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+    virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+    // End of OutputThreadInterface methods
 
     Status constructDefaultRequestSettingsRaw(RequestTemplate type,
             V3_2::CameraMetadata *outMetadata);
@@ -219,11 +291,6 @@
             // Optional argument for ICameraDeviceSession@3.5 impl
             bool allowEmptyBuf = false);
 
-    Status importBuffer(int32_t streamId,
-            uint64_t bufId, buffer_handle_t buf,
-            /*out*/buffer_handle_t** outBufPtr,
-            bool allowEmptyBuf);
-
     Status importBufferLocked(int32_t streamId,
             uint64_t bufId, buffer_handle_t buf,
             /*out*/buffer_handle_t** outBufPtr,
@@ -236,106 +303,15 @@
 
     Status processOneCaptureRequest(const CaptureRequest& request);
 
-    Status processCaptureResult(std::shared_ptr<HalRequest>&);
-    Status processCaptureRequestError(const std::shared_ptr<HalRequest>&);
     void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs);
-    void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec);
     void invokeProcessCaptureResultCallback(
             hidl_vec<CaptureResult> &results, bool tryWriteFmq);
-    static void freeReleaseFences(hidl_vec<CaptureResult>&);
 
     Size getMaxJpegResolution() const;
     Size getMaxThumbResolution() const;
 
-    ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
-
     int waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk);
 
-    class OutputThread : public android::Thread {
-    public:
-        OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
-        virtual ~OutputThread();
-
-        Status allocateIntermediateBuffers(
-                const Size& v4lSize, const Size& thumbSize,
-                const hidl_vec<Stream>& streams,
-                uint32_t blobBufferSize);
-        Status submitRequest(const std::shared_ptr<HalRequest>&);
-        void flush();
-        void dump(int fd);
-        virtual bool threadLoop() override;
-
-        void setExifMakeModel(const std::string& make, const std::string& model);
-
-    protected:
-        // Methods to request output buffer in parallel
-        // No-op for device@3.4. Implemented in device@3.5
-        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
-        virtual int waitForBufferRequestDone(
-                /*out*/std::vector<HalStreamBuffer>*) { return 0; }
-
-        static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
-                static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
-                static_cast<uint32_t>('X') << 24;
-        // returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
-        static uint32_t getFourCcFromLayout(const YCbCrLayout&);
-        static int getCropRect(
-                CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
-
-        static const int kFlushWaitTimeoutSec = 3; // 3 sec
-        static const int kReqWaitTimeoutMs = 33;   // 33ms
-        static const int kReqWaitTimesMax = 90;    // 33ms * 90 ~= 3 sec
-
-        void waitForNextRequest(std::shared_ptr<HalRequest>* out);
-        void signalRequestDone();
-
-        int cropAndScaleLocked(
-                sp<AllocatedFrame>& in, const Size& outSize,
-                YCbCrLayout* out);
-
-        int cropAndScaleThumbLocked(
-                sp<AllocatedFrame>& in, const Size& outSize,
-                YCbCrLayout* out);
-
-        int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out,
-                Size sz, uint32_t format);
-
-        static int encodeJpegYU12(const Size &inSz,
-                const YCbCrLayout& inLayout, int jpegQuality,
-                const void *app1Buffer, size_t app1Size,
-                void *out, size_t maxOutSize,
-                size_t &actualCodeSize);
-
-        int createJpegLocked(HalStreamBuffer &halBuf, const std::shared_ptr<HalRequest>& req);
-
-        const wp<ExternalCameraDeviceSession> mParent;
-        const CroppingType mCroppingType;
-
-        mutable std::mutex mRequestListLock;      // Protect acccess to mRequestList,
-                                                  // mProcessingRequest and mProcessingFrameNumer
-        std::condition_variable mRequestCond;     // signaled when a new request is submitted
-        std::condition_variable mRequestDoneCond; // signaled when a request is done processing
-        std::list<std::shared_ptr<HalRequest>> mRequestList;
-        bool mProcessingRequest = false;
-        uint32_t mProcessingFrameNumer = 0;
-
-        // V4L2 frameIn
-        // (MJPG decode)-> mYu12Frame
-        // (Scale)-> mScaledYu12Frames
-        // (Format convert) -> output gralloc frames
-        mutable std::mutex mBufferLock; // Protect access to intermediate buffers
-        sp<AllocatedFrame> mYu12Frame;
-        sp<AllocatedFrame> mYu12ThumbFrame;
-        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
-        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
-        YCbCrLayout mYu12FrameLayout;
-        YCbCrLayout mYu12ThumbFrameLayout;
-        uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
-
-        std::string mExifMake;
-        std::string mExifModel;
-    };
-
     // Protect (most of) HIDL interface methods from synchronized-entering
     mutable Mutex mInterfaceLock;
 
@@ -345,7 +321,7 @@
     const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
     const std::vector<SupportedV4L2Format> mSupportedFormats;
     const CroppingType mCroppingType;
-    const std::string& mCameraId;
+    const std::string mCameraId;
 
     // Not protected by mLock, this is almost a const.
     // Setup in constructor, reset in close() after OutputThread is joined
@@ -381,12 +357,6 @@
     std::mutex mInflightFramesLock; // protect mInflightFrames
     std::unordered_set<uint32_t>  mInflightFrames;
 
-    // buffers currently circulating between HAL and camera service
-    // key: bufferId sent via HIDL interface
-    // value: imported buffer_handle_t
-    // Buffer will be imported during processCaptureRequest and will be freed
-    // when the its stream is deleted or camera device session is closed
-    typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
     // Stream ID -> circulating buffers map
     std::map<int, CirculatingBuffers> mCirculatingBuffers;
     // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
@@ -395,6 +365,8 @@
     std::mutex mAfTriggerLock; // protect mAfTrigger
     bool mAfTrigger = false;
 
+    uint32_t mBlobBufferSize = 0;
+
     static HandleImporter sHandleImporter;
 
     /* Beginning of members not changed after initialize() */
@@ -410,6 +382,9 @@
 
     const Size mMaxThumbResolution;
     const Size mMaxJpegResolution;
+
+    std::string mExifMake;
+    std::string mExifModel;
     /* End of members not changed after initialize() */
 
 private:
@@ -484,4 +459,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index bd79807..1958fcb 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -105,7 +105,7 @@
     // Calls into virtual member function. Do not use it in constructor
     status_t initCameraCharacteristics();
     // Init available capabilities keys
-    status_t initAvailableCapabilities(
+    virtual status_t initAvailableCapabilities(
             ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
     // Init non-device dependent keys
     virtual status_t initDefaultCharsKeys(
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 341c622..74f75eb 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -17,16 +17,27 @@
 #ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
 #define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
 
+#include <android/hardware/camera/common/1.0/types.h>
+#include <android/hardware/camera/device/3.2/types.h>
+#include <android/hardware/graphics/common/1.0/types.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <inttypes.h>
 #include <mutex>
+#include <unordered_map>
 #include <unordered_set>
 #include <vector>
 #include "tinyxml2.h"  // XML parsing
 #include "utils/LightRefBase.h"
+#include "utils/Timers.h"
+#include <CameraMetadata.h>
+#include <HandleImporter.h>
 
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
 
 namespace android {
 namespace hardware {
@@ -113,16 +124,28 @@
     std::vector<FrameRate> frameRates;
 };
 
+// A Base class with basic information about a frame
+struct Frame : public VirtualLightRefBase {
+public:
+    Frame(uint32_t width, uint32_t height, uint32_t fourcc);
+    const uint32_t mWidth;
+    const uint32_t mHeight;
+    const uint32_t mFourcc;
+
+    // getData might involve map/allocation
+    virtual int getData(uint8_t** outData, size_t* dataSize) = 0;
+};
+
 // A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
 // Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
-class V4L2Frame : public virtual VirtualLightRefBase {
+class V4L2Frame : public Frame {
 public:
     V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd,
               uint32_t dataSize, uint64_t offset);
     ~V4L2Frame() override;
-    const uint32_t mWidth;
-    const uint32_t mHeight;
-    const uint32_t mFourcc;
+
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
     const int mBufferIndex; // for later enqueue
     int map(uint8_t** data, size_t* dataSize);
     int unmap();
@@ -137,13 +160,13 @@
 
 // A RAII class representing a CPU allocated YUV frame used as intermeidate buffers
 // when generating output images.
-class AllocatedFrame : public virtual VirtualLightRefBase {
+class AllocatedFrame : public Frame {
 public:
-    AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size?
+    AllocatedFrame(uint32_t w, uint32_t h); // only support V4L2_PIX_FMT_YUV420 for now
     ~AllocatedFrame() override;
-    const uint32_t mWidth;
-    const uint32_t mHeight;
-    const uint32_t mFourcc; // Only support YU12 format for now
+
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
     int allocate(YCbCrLayout* out = nullptr);
     int getLayout(YCbCrLayout* out);
     int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
@@ -165,8 +188,110 @@
 
 bool isAspectRatioClose(float ar1, float ar2);
 
+struct HalStreamBuffer {
+    int32_t streamId;
+    uint64_t bufferId;
+    uint32_t width;
+    uint32_t height;
+    ::android::hardware::graphics::common::V1_0::PixelFormat format;
+    ::android::hardware::camera::device::V3_2::BufferUsageFlags usage;
+    buffer_handle_t* bufPtr;
+    int acquireFence;
+    bool fenceTimeout;
+};
+
+struct HalRequest {
+    uint32_t frameNumber;
+    common::V1_0::helper::CameraMetadata setting;
+    sp<Frame> frameIn;
+    nsecs_t shutterTs;
+    std::vector<HalStreamBuffer> buffers;
+};
+
+static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
+// buffers currently circulating between HAL and camera service
+// key: bufferId sent via HIDL interface
+// value: imported buffer_handle_t
+// Buffer will be imported during processCaptureRequest (or requestStreamBuffer
+// in the case of HAL buffer manager is enabled) and will be freed
+// when the stream is deleted or camera device session is closed
+typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
+
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+        /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*inout*/HandleImporter& handleImporter,
+        int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf);
+
+static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
+        static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
+        static_cast<uint32_t>('X') << 24;
+
+// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
+uint32_t getFourCcFromLayout(const YCbCrLayout&);
+
+using ::android::hardware::camera::external::common::Size;
+int getCropRect(CroppingType ct, const Size& inSize,
+        const Size& outSize, IMapper::Rect* out);
+
+int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format);
+
+int encodeJpegYU12(const Size &inSz,
+        const YCbCrLayout& inLayout, int jpegQuality,
+        const void *app1Buffer, size_t app1Size,
+        void *out, size_t maxOutSize,
+        size_t &actualCodeSize);
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&);
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>&);
+
+status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp,
+        camera_metadata_ro_entry& activeArraySize);
+
+// Interface for OutputThread calling back to parent
+struct OutputThreadInterface : public virtual RefBase {
+    virtual ::android::hardware::camera::common::V1_0::Status importBuffer(
+            int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) = 0;
+
+    virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) = 0;
+
+    // Callbacks are fired within the method if msgs/results are nullptr.
+    // Otherwise the callbacks will be returned and caller is responsible to
+    // fire the callback later
+    virtual ::android::hardware::camera::common::V1_0::Status processCaptureRequestError(
+            const std::shared_ptr<HalRequest>&,
+            /*out*/std::vector<V3_2::NotifyMsg>* msgs = nullptr,
+            /*out*/std::vector<V3_2::CaptureResult>* results = nullptr) = 0;
+
+    virtual ::android::hardware::camera::common::V1_0::Status processCaptureResult(
+            std::shared_ptr<HalRequest>&) = 0;
+
+    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0;
+};
+
 }  // namespace implementation
 }  // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame.
+class AllocatedV4L2Frame : public V3_4::implementation::Frame {
+public:
+    AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn);
+    ~AllocatedV4L2Frame() override;
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+private:
+    std::vector<uint8_t> mData;
+};
+
+} // namespace implementation
+} // namespace V3_6
 }  // namespace device
 }  // namespace camera
 }  // namespace hardware
diff --git a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
index 00c1d0d..287ac32 100644
--- a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
@@ -80,7 +80,7 @@
 
 
 ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread(
-        wp<ExternalCameraDeviceSession> parent,
+        wp<OutputThreadInterface> parent,
         sp<V3_5::ICameraDeviceCallback> callbacks) :
         mParent(parent),
         mCallbacks(callbacks) {}
@@ -254,7 +254,8 @@
         mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5);
         mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
     }
-    mOutputThread = new OutputThread(this, mCroppingType, mBufferRequestThread);
+    mOutputThread = new OutputThread(
+            this, mCroppingType, mCameraCharacteristics, mBufferRequestThread);
 }
 
 void ExternalCameraDeviceSession::closeOutputThreadImpl() {
@@ -271,10 +272,11 @@
 }
 
 ExternalCameraDeviceSession::OutputThread::OutputThread(
-        wp<ExternalCameraDeviceSession> parent,
+        wp<OutputThreadInterface> parent,
         CroppingType ct,
+        const common::V1_0::helper::CameraMetadata& chars,
         sp<BufferRequestThread> bufReqThread) :
-        V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct),
+        V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct, chars),
         mBufferRequestThread(bufReqThread) {}
 
 ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
index 281f93a..e89ef45 100644
--- a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
 
 #include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
 #include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
@@ -72,6 +72,7 @@
 
 using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
 using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::HalStreamBuffer;
 
 struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCameraDeviceSession {
 
@@ -97,6 +98,62 @@
                 config, supportedFormats, devCfg);
     }
 
+    class BufferRequestThread : public android::Thread {
+    public:
+        BufferRequestThread(
+                wp<OutputThreadInterface> parent,
+                sp<V3_5::ICameraDeviceCallback> callbacks);
+
+        int requestBufferStart(const std::vector<HalStreamBuffer>&);
+        int waitForBufferRequestDone(
+                /*out*/std::vector<HalStreamBuffer>*);
+
+        virtual bool threadLoop() override;
+
+    private:
+        void waitForNextRequest();
+
+        const wp<OutputThreadInterface> mParent;
+        const sp<V3_5::ICameraDeviceCallback> mCallbacks;
+
+        std::mutex mLock;
+        bool mRequestingBuffer = false;
+
+        std::vector<HalStreamBuffer> mBufferReqs;
+        std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
+        // mHalBufferReqs is not under mLock protection during the HIDL transaction
+        hidl_vec<BufferRequest>      mHalBufferReqs;
+
+        // request buffers takes much less time in steady state, but can take much longer
+        // when requesting 1st buffer from a stream.
+        // TODO: consider a separate timeout for new vs. steady state?
+        // TODO: or make sure framework is warming up the pipeline during configure new stream?
+        static const int kReqProcTimeoutMs = 66;
+
+        static const int kReqWaitTimeoutMs = 33;
+        static const int kReqWaitTimesWarn = 90;  // 33ms * 90 ~= 3 sec
+        std::condition_variable mRequestCond;     // signaled when a new buffer request incoming
+        std::condition_variable mRequestDoneCond; // signaled when a request is done
+    };
+
+    class OutputThread :
+            public V3_4::implementation::ExternalCameraDeviceSession::OutputThread {
+    public:
+        // TODO: pass buffer request thread to OutputThread ctor
+        OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+                const common::V1_0::helper::CameraMetadata&,
+                sp<BufferRequestThread> bufReqThread);
+        virtual ~OutputThread();
+
+    protected:
+        // Methods to request output buffer in parallel
+        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) override;
+        virtual int waitForBufferRequestDone(
+                /*out*/std::vector<HalStreamBuffer>*) override;
+
+        const sp<BufferRequestThread> mBufferRequestThread;
+    };
+
 protected:
     // Methods from v3.4 and earlier will trampoline to inherited implementation
     Return<void> configureStreams_3_5(
@@ -120,63 +177,8 @@
             hidl_vec<buffer_handle_t*>& allBufPtrs,
             hidl_vec<int>& allFences) override;
 
-    class BufferRequestThread : public android::Thread {
-    public:
-        BufferRequestThread(
-                wp<ExternalCameraDeviceSession> parent,
-                sp<V3_5::ICameraDeviceCallback> callbacks);
-
-        int requestBufferStart(const std::vector<HalStreamBuffer>&);
-        int waitForBufferRequestDone(
-                /*out*/std::vector<HalStreamBuffer>*);
-
-        virtual bool threadLoop() override;
-
-    private:
-        void waitForNextRequest();
-
-        const wp<ExternalCameraDeviceSession> mParent;
-        const sp<V3_5::ICameraDeviceCallback> mCallbacks;
-
-        std::mutex mLock;
-        bool mRequestingBuffer = false;
-
-        std::vector<HalStreamBuffer> mBufferReqs;
-        std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
-        // mHalBufferReqs is not under mLock protection during the HIDL transaction
-        hidl_vec<BufferRequest>      mHalBufferReqs;
-
-        // request buffers takes much less time in steady state, but can take much longer
-        // when requesting 1st buffer from a stream.
-        // TODO: consider a separate timeout for new vs. steady state?
-        // TODO: or make sure framework is warming up the pipeline during configure new stream?
-        static const int kReqProcTimeoutMs = 66;
-
-        static const int kReqWaitTimeoutMs = 33;
-        static const int kReqWaitTimesWarn = 90;  // 33ms * 90 ~= 3 sec
-        std::condition_variable mRequestCond;     // signaled when a new buffer request incoming
-        std::condition_variable mRequestDoneCond; // signaled when a request is done
-    };
-
     sp<BufferRequestThread> mBufferRequestThread;
 
-    class OutputThread :
-            public V3_4::implementation::ExternalCameraDeviceSession::OutputThread {
-    public:
-        // TODO: pass buffer request thread to OutputThread ctor
-        OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType,
-                sp<BufferRequestThread> bufReqThread);
-        virtual ~OutputThread();
-
-    protected:
-        // Methods to request output buffer in parallel
-        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) override;
-        virtual int waitForBufferRequestDone(
-                /*out*/std::vector<HalStreamBuffer>*) override;
-
-        const sp<BufferRequestThread> mBufferRequestThread;
-    };
-
     sp<V3_5::ICameraDeviceCallback> mCallback_3_5;
     bool mSupportBufMgr;
 
@@ -270,4 +272,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.6/Android.bp b/camera/device/3.6/Android.bp
index 8766b93..19adb34 100644
--- a/camera/device/3.6/Android.bp
+++ b/camera/device/3.6/Android.bp
@@ -8,6 +8,7 @@
     },
     srcs: [
         "types.hal",
+        "ICameraDevice.hal",
         "ICameraDeviceSession.hal",
         "ICameraOfflineSession.hal",
     ],
diff --git a/camera/device/3.6/ICameraDevice.hal b/camera/device/3.6/ICameraDevice.hal
new file mode 100644
index 0000000..e859606
--- /dev/null
+++ b/camera/device/3.6/ICameraDevice.hal
@@ -0,0 +1,31 @@
+/*
+ * 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.camera.device@3.6;
+
+import @3.5::ICameraDevice;
+
+/**
+ * Camera device interface
+ *
+ * Supports the android.hardware.Camera API, and the android.hardware.camera2
+ * API at LIMITED or better hardware level.
+ *
+ * ICameraDevice.open() must return @3.2::ICameraDeviceSession or
+ * @3.5::ICameraDeviceSession or @3.6::ICameraDeviceSession.
+ */
+interface ICameraDevice extends @3.5::ICameraDevice {
+};
diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp
new file mode 100644
index 0000000..a2ddebd
--- /dev/null
+++ b/camera/device/3.6/default/Android.bp
@@ -0,0 +1,67 @@
+//
+// 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.
+//
+
+cc_library_headers {
+    name: "camera.device@3.6-external-impl_headers",
+    vendor: true,
+    export_include_dirs: ["include/ext_device_v3_6_impl"]
+}
+
+cc_library_shared {
+    name: "camera.device@3.6-external-impl",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    vendor: true,
+    srcs: [
+        "ExternalCameraDevice.cpp",
+        "ExternalCameraDeviceSession.cpp",
+        "ExternalCameraOfflineSession.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libutils",
+        "libcutils",
+        "camera.device@3.2-impl",
+        "camera.device@3.3-impl",
+        "camera.device@3.4-external-impl",
+        "camera.device@3.5-external-impl",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.device@3.5",
+        "android.hardware.camera.device@3.6",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "liblog",
+        "libhardware",
+        "libcamera_metadata",
+        "libfmq",
+        "libsync",
+        "libyuv",
+        "libjpeg",
+        "libexif",
+        "libtinyxml2"
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    local_include_dirs: ["include/ext_device_v3_6_impl"],
+    export_shared_lib_headers: [
+        "libfmq",
+    ],
+}
diff --git a/camera/device/3.6/default/ExternalCameraDevice.cpp b/camera/device/3.6/default/ExternalCameraDevice.cpp
new file mode 100644
index 0000000..244c7dd
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDevice.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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 "ExtCamDev@3.6"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include "ExternalCameraDevice_3_6.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDevice::ExternalCameraDevice(
+        const std::string& cameraId, const ExternalCameraConfig& cfg) :
+        V3_5::implementation::ExternalCameraDevice(cameraId, cfg) {}
+
+ExternalCameraDevice::~ExternalCameraDevice() {}
+
+sp<V3_4::implementation::ExternalCameraDeviceSession> ExternalCameraDevice::createSession(
+        const sp<V3_2::ICameraDeviceCallback>& cb,
+        const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats,
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        unique_fd v4l2Fd) {
+    return new ExternalCameraDeviceSession(
+            cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd));
+}
+
+#define UPDATE(tag, data, size)                    \
+do {                                               \
+  if (metadata->update((tag), (data), (size))) {   \
+    ALOGE("Update " #tag " failed!");              \
+    return -EINVAL;                                \
+  }                                                \
+} while (0)
+
+status_t ExternalCameraDevice::initAvailableCapabilities(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    status_t res =
+            V3_4::implementation::ExternalCameraDevice::initAvailableCapabilities(metadata);
+
+    if (res != OK) {
+        return res;
+    }
+
+    camera_metadata_entry caps = metadata->find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    std::vector<uint8_t> availableCapabilities;
+
+    for (size_t i = 0; i < caps.count; i++) {
+        uint8_t capability = caps.data.u8[i];
+        availableCapabilities.push_back(capability);
+    }
+
+    // Add OFFLINE_PROCESSING capability to device 3.6
+    availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING);
+
+    UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+           availableCapabilities.data(),
+           availableCapabilities.size());
+
+    return OK;
+}
+
+#undef UPDATE
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
new file mode 100644
index 0000000..60a1a10
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
@@ -0,0 +1,359 @@
+/*
+ * 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 "ExtCamDevSsn@3.6"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDeviceSession::ExternalCameraDeviceSession(
+        const sp<V3_2::ICameraDeviceCallback>& callback,
+        const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats,
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        unique_fd v4l2Fd) :
+        V3_5::implementation::ExternalCameraDeviceSession(
+                callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) {
+}
+
+ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {}
+
+
+Return<void> ExternalCameraDeviceSession::configureStreams_3_6(
+        const StreamConfiguration& requestedConfiguration,
+        ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb)  {
+    V3_2::StreamConfiguration config_v32;
+    V3_3::HalStreamConfiguration outStreams_v33;
+    V3_6::HalStreamConfiguration outStreams;
+    const V3_4::StreamConfiguration& requestedConfiguration_3_4 = requestedConfiguration.v3_4;
+    Mutex::Autolock _il(mInterfaceLock);
+
+    config_v32.operationMode = requestedConfiguration_3_4.operationMode;
+    config_v32.streams.resize(requestedConfiguration_3_4.streams.size());
+    uint32_t blobBufferSize = 0;
+    int numStallStream = 0;
+    for (size_t i = 0; i < config_v32.streams.size(); i++) {
+        config_v32.streams[i] = requestedConfiguration_3_4.streams[i].v3_2;
+        if (config_v32.streams[i].format == PixelFormat::BLOB) {
+            blobBufferSize = requestedConfiguration_3_4.streams[i].bufferSize;
+            numStallStream++;
+        }
+    }
+
+    // Fail early if there are multiple BLOB streams
+    if (numStallStream > kMaxStallStream) {
+        ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__,
+                kMaxStallStream, numStallStream);
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, outStreams);
+        return Void();
+    }
+
+    Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize);
+
+    fillOutputStream3_6(outStreams_v33, &outStreams);
+
+    _hidl_cb(status, outStreams);
+    return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::switchToOffline(
+        const hidl_vec<int32_t>& streamsToKeep,
+        ICameraDeviceSession::switchToOffline_cb _hidl_cb) {
+    std::vector<NotifyMsg> msgs;
+    std::vector<CaptureResult> results;
+    CameraOfflineSessionInfo info;
+    sp<ICameraOfflineSession> session;
+
+    Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session);
+
+    mCallback->notify(msgs);
+    hidl_vec<CaptureResult> hidlResults(std::move(results));
+    invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true);
+    V3_4::implementation::freeReleaseFences(hidlResults);
+
+    _hidl_cb(st, info, session);
+    return Void();
+}
+
+void ExternalCameraDeviceSession::fillOutputStream3_6(
+        const V3_3::HalStreamConfiguration& outStreams_v33,
+        /*out*/V3_6::HalStreamConfiguration* outStreams_v36) {
+    if (outStreams_v36 == nullptr) {
+        ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__);
+        return;
+    }
+    Mutex::Autolock _l(mLock);
+    outStreams_v36->streams.resize(outStreams_v33.streams.size());
+    for (size_t i = 0; i < outStreams_v36->streams.size(); i++) {
+        outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i];
+        outStreams_v36->streams[i].supportOffline =
+                supportOfflineLocked(outStreams_v33.streams[i].v3_2.id);
+    }
+}
+
+bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) {
+    const Stream& stream = mStreamMap[streamId];
+    if (stream.format == PixelFormat::BLOB &&
+            stream.dataSpace == static_cast<int32_t>(Dataspace::V0_JFIF)) {
+        return true;
+    }
+    // TODO: support YUV output stream?
+    return false;
+}
+
+bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+        std::shared_ptr<V3_4::implementation::HalRequest> halReq) {
+    for (const auto& buffer : halReq->buffers) {
+        for (auto offlineStreamId : offlineStreams) {
+            if (buffer.streamId == offlineStreamId) {
+                return false;
+            }
+        }
+    }
+    // Only drop a request completely if it has no offline output
+    return true;
+}
+
+void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+        std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+        const std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*out*/CameraOfflineSessionInfo* info) {
+    if (info == nullptr) {
+        ALOGE("%s: output info must not be null!", __FUNCTION__);
+        return;
+    }
+
+    info->offlineStreams.resize(offlineStreams.size());
+    info->offlineRequests.resize(offlineReqs.size());
+
+    // Fill in offline reqs and count outstanding buffers
+    for (size_t i = 0; i < offlineReqs.size(); i++) {
+        info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
+        info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
+        for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
+            int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
+            info->offlineRequests[i].pendingStreams[bIdx] = streamId;
+        }
+    }
+
+    for (size_t i = 0; i < offlineStreams.size(); i++) {
+        int32_t streamId = offlineStreams[i];
+        info->offlineStreams[i].id = streamId;
+        // outstanding buffers are 0 since we are doing hal buffer management and
+        // offline session will ask for those buffers later
+        info->offlineStreams[i].numOutstandingBuffers = 0;
+        const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
+        info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
+        size_t bIdx = 0;
+        for (const auto& pair : bufIdMap) {
+            // Fill in bufferId
+            info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
+        }
+
+    }
+}
+
+Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+        /*out*/std::vector<NotifyMsg>* msgs,
+        /*out*/std::vector<CaptureResult>* results,
+        /*out*/CameraOfflineSessionInfo* info,
+        /*out*/sp<ICameraOfflineSession>* session) {
+    ATRACE_CALL();
+    if (offlineStreams.size() > 1) {
+        ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
+        ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__,
+                msgs, results, info, session);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    msgs->clear();
+    results->clear();
+
+    Mutex::Autolock _il(mInterfaceLock);
+    Status status = initStatus();
+    if (status != Status::OK) {
+        return status;
+    }
+
+    Mutex::Autolock _l(mLock);
+    for (auto streamId : offlineStreams) {
+        if (!supportOfflineLocked(streamId)) {
+            return Status::ILLEGAL_ARGUMENT;
+        }
+    }
+
+    // pause output thread and get all remaining inflight requests
+    auto remainingReqs = mOutputThread->switchToOffline();
+    std::vector<std::shared_ptr<V3_4::implementation::HalRequest>> halReqs;
+
+    // Send out buffer/request error for remaining requests and filter requests
+    // to be handled in offline mode
+    for (auto& halReq : remainingReqs) {
+        bool dropReq = canDropRequest(offlineStreams, halReq);
+        if (dropReq) {
+            // Request is dropped completely. Just send request error and
+            // there is no need to send the request to offline session
+            processCaptureRequestError(halReq, msgs, results);
+            continue;
+        }
+
+        // All requests reach here must have at least one offline stream output
+        NotifyMsg shutter;
+        shutter.type = MsgType::SHUTTER;
+        shutter.msg.shutter.frameNumber = halReq->frameNumber;
+        shutter.msg.shutter.timestamp = halReq->shutterTs;
+        msgs->push_back(shutter);
+
+        std::vector<V3_4::implementation::HalStreamBuffer> offlineBuffers;
+        for (const auto& buffer : halReq->buffers) {
+            bool dropBuffer = true;
+            for (auto offlineStreamId : offlineStreams) {
+                if (buffer.streamId == offlineStreamId) {
+                    dropBuffer = false;
+                    break;
+                }
+            }
+            if (dropBuffer) {
+                NotifyMsg error;
+                error.type = MsgType::ERROR;
+                error.msg.error.frameNumber = halReq->frameNumber;
+                error.msg.error.errorStreamId = buffer.streamId;
+                error.msg.error.errorCode = ErrorCode::ERROR_BUFFER;
+                msgs->push_back(error);
+
+                CaptureResult result;
+                result.frameNumber = halReq->frameNumber;
+                result.partialResult = 0; // buffer only result
+                result.inputBuffer.streamId = -1;
+                result.outputBuffers.resize(1);
+                result.outputBuffers[0].streamId = buffer.streamId;
+                result.outputBuffers[0].bufferId = buffer.bufferId;
+                result.outputBuffers[0].status = BufferStatus::ERROR;
+                if (buffer.acquireFence >= 0) {
+                    native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                    handle->data[0] = buffer.acquireFence;
+                    result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false);
+                }
+                results->push_back(result);
+            } else {
+                offlineBuffers.push_back(buffer);
+            }
+        }
+        halReq->buffers = offlineBuffers;
+        halReqs.push_back(halReq);
+    }
+
+    // convert hal requests to offline request
+    std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+    for (auto& v4lReq : halReqs) {
+        std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
+        halReq->frameNumber = v4lReq->frameNumber;
+        halReq->setting = v4lReq->setting;
+        halReq->shutterTs = v4lReq->shutterTs;
+        halReq->buffers = v4lReq->buffers;
+        sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+                static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
+        halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame);
+        offlineReqs.push_back(halReq);
+        // enqueue V4L2 frame
+        enqueueV4l2Frame(v4l2Frame);
+    }
+
+    // Collect buffer caches/streams
+    hidl_vec<Stream> streamInfos;
+    streamInfos.resize(offlineStreams.size());
+    std::map<int, CirculatingBuffers> circulatingBuffers;
+    {
+        Mutex::Autolock _l(mCbsLock);
+        size_t idx = 0;
+        for(auto streamId : offlineStreams) {
+            circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
+            mCirculatingBuffers.erase(streamId);
+            streamInfos[idx++] = mStreamMap.at(streamId);
+            mStreamMap.erase(streamId);
+        }
+    }
+
+    fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
+
+    // create the offline session object
+    bool afTrigger;
+    {
+        std::lock_guard<std::mutex> lk(mAfTriggerLock);
+        afTrigger = mAfTrigger;
+    }
+    sp<ExternalCameraOfflineSession> sessionImpl = new ExternalCameraOfflineSession(
+            mCroppingType, mCameraCharacteristics, mCameraId,
+            mExifMake, mExifModel, mBlobBufferSize, afTrigger,
+            streamInfos, offlineReqs, circulatingBuffers);
+
+    bool initFailed = sessionImpl->initialize();
+    if (initFailed) {
+        ALOGE("%s: offline session initialize failed!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    // cleanup stream and buffer caches
+    {
+        Mutex::Autolock _l(mCbsLock);
+        for(auto pair : mStreamMap) {
+            cleanupBuffersLocked(/*Stream ID*/pair.first);
+        }
+        mCirculatingBuffers.clear();
+    }
+    mStreamMap.clear();
+
+    // update inflight records
+    {
+        std::lock_guard<std::mutex> lk(mInflightFramesLock);
+        mInflightFrames.clear();
+    }
+
+    // stop v4l2 streaming
+    if (v4l2StreamOffLocked() !=0) {
+        ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    // No need to return session if there is no offline requests left
+    if (offlineReqs.size() != 0) {
+        *session = sessionImpl->getInterface();
+    } else {
+        *session = nullptr;
+    }
+    return Status::OK;
+}
+
+} // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
new file mode 100644
index 0000000..e606fda
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
@@ -0,0 +1,554 @@
+/*
+ * 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 "ExtCamOfflnSsn@3.6"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+#include <android/log.h>
+
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace {
+
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+} // anonymous namespace
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+// static instance
+HandleImporter ExternalCameraOfflineSession::sHandleImporter;
+
+using V3_5::implementation::ExternalCameraDeviceSession;
+
+ExternalCameraOfflineSession::ExternalCameraOfflineSession(
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        const std::string& exifMake,
+        const std::string& exifModel,
+        const uint32_t blobBufferSize,
+        const bool afTrigger,
+        const hidl_vec<Stream>& offlineStreams,
+        std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+        const std::map<int, CirculatingBuffers>& circulatingBuffers) :
+        mCroppingType(croppingType), mChars(chars), mCameraId(cameraId),
+        mExifMake(exifMake), mExifModel(exifModel), mBlobBufferSize(blobBufferSize),
+        mAfTrigger(afTrigger), mOfflineStreams(offlineStreams), mOfflineReqs(offlineReqs),
+        mCirculatingBuffers(circulatingBuffers) {}
+
+ExternalCameraOfflineSession::~ExternalCameraOfflineSession() {
+    close();
+}
+
+bool ExternalCameraOfflineSession::initialize() {
+    mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
+            kMetadataMsgQueueSize, false /* non blocking */);
+    if (!mResultMetadataQueue->isValid()) {
+        ALOGE("%s: invalid result fmq", __FUNCTION__);
+        return true;
+    }
+    return false;
+}
+
+void ExternalCameraOfflineSession::initOutputThread() {
+    if (mOutputThread != nullptr) {
+        ALOGE("%s: OutputThread already exist!", __FUNCTION__);
+        return;
+    }
+
+    mBufferRequestThread = new ExternalCameraDeviceSession::BufferRequestThread(
+            this, mCallback);
+    mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
+
+    mOutputThread = new OutputThread(this, mCroppingType, mChars,
+            mBufferRequestThread, mOfflineReqs);
+
+    mOutputThread->setExifMakeModel(mExifMake, mExifModel);
+
+    Size inputSize = { mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight};
+    Size maxThumbSize = V3_4::implementation::getMaxThumbnailResolution(mChars);
+    mOutputThread->allocateIntermediateBuffers(
+            inputSize, maxThumbSize, mOfflineStreams, mBlobBufferSize);
+
+    mOutputThread->run("ExtCamOfflnOut", PRIORITY_DISPLAY);
+}
+
+bool ExternalCameraOfflineSession::OutputThread::threadLoop() {
+    auto parent = mParent.promote();
+    if (parent == nullptr) {
+       ALOGE("%s: session has been disconnected!", __FUNCTION__);
+       return false;
+    }
+
+    if (mOfflineReqs.empty()) {
+        ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__);
+        return false;
+    }
+
+    std::shared_ptr<HalRequest> req = mOfflineReqs.front();
+    mOfflineReqs.pop_front();
+
+    auto onDeviceError = [&](auto... args) {
+        ALOGE(args...);
+        parent->notifyError(
+                req->frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+        signalRequestDone();
+        return false;
+    };
+
+    if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
+        return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+                req->frameIn->mFourcc & 0xFF,
+                (req->frameIn->mFourcc >> 8) & 0xFF,
+                (req->frameIn->mFourcc >> 16) & 0xFF,
+                (req->frameIn->mFourcc >> 24) & 0xFF);
+    }
+
+    int res = requestBufferStart(req->buffers);
+    if (res != 0) {
+        ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+        return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+    }
+
+    std::unique_lock<std::mutex> lk(mBufferLock);
+    // Convert input V4L2 frame to YU12 of the same size
+    // TODO: see if we can save some computation by converting to YV12 here
+    uint8_t* inData;
+    size_t inDataSize;
+    if (req->frameIn->getData(&inData, &inDataSize) != 0) {
+        lk.unlock();
+        return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+    }
+
+    // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+    if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+        ATRACE_BEGIN("MJPGtoI420");
+        int res = libyuv::MJPGToI420(
+            inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y), mYu12FrameLayout.yStride,
+            static_cast<uint8_t*>(mYu12FrameLayout.cb), mYu12FrameLayout.cStride,
+            static_cast<uint8_t*>(mYu12FrameLayout.cr), mYu12FrameLayout.cStride,
+            mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth, mYu12Frame->mHeight);
+        ATRACE_END();
+
+        if (res != 0) {
+            // For some webcam, the first few V4L2 frames might be malformed...
+            ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
+            lk.unlock();
+            Status st = parent->processCaptureRequestError(req);
+            if (st != Status::OK) {
+                return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+            }
+            signalRequestDone();
+            return true;
+        }
+    }
+
+    ATRACE_BEGIN("Wait for BufferRequest done");
+    res = waitForBufferRequestDone(&req->buffers);
+    ATRACE_END();
+
+    if (res != 0) {
+        ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+        lk.unlock();
+        return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+    }
+
+    ALOGV("%s processing new request", __FUNCTION__);
+    const int kSyncWaitTimeoutMs = 500;
+    for (auto& halBuf : req->buffers) {
+        if (*(halBuf.bufPtr) == nullptr) {
+            ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+            halBuf.fenceTimeout = true;
+        } else if (halBuf.acquireFence >= 0) {
+            int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+            if (ret) {
+                halBuf.fenceTimeout = true;
+            } else {
+                ::close(halBuf.acquireFence);
+                halBuf.acquireFence = -1;
+            }
+        }
+
+        if (halBuf.fenceTimeout) {
+            continue;
+        }
+
+        // Gralloc lockYCbCr the buffer
+        switch (halBuf.format) {
+            case PixelFormat::BLOB: {
+                int ret = createJpegLocked(halBuf, req->setting);
+
+                if(ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: createJpegLocked failed with %d",
+                          __FUNCTION__, ret);
+                }
+            } break;
+            case PixelFormat::Y16: {
+                void* outLayout = sHandleImporter.lock(*(halBuf.bufPtr), halBuf.usage, inDataSize);
+
+                std::memcpy(outLayout, inData, inDataSize);
+
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            case PixelFormat::YCBCR_420_888:
+            case PixelFormat::YV12: {
+                IMapper::Rect outRect {0, 0,
+                        static_cast<int32_t>(halBuf.width),
+                        static_cast<int32_t>(halBuf.height)};
+                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+                        *(halBuf.bufPtr), halBuf.usage, outRect);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                        __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
+                        outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
+
+                // Convert to output buffer size/format
+                uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout);
+                ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__,
+                        outputFourcc & 0xFF,
+                        (outputFourcc >> 8) & 0xFF,
+                        (outputFourcc >> 16) & 0xFF,
+                        (outputFourcc >> 24) & 0xFF);
+
+                YCbCrLayout cropAndScaled;
+                ATRACE_BEGIN("cropAndScaleLocked");
+                int ret = cropAndScaleLocked(
+                        mYu12Frame,
+                        Size { halBuf.width, halBuf.height },
+                        &cropAndScaled);
+                ATRACE_END();
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
+                }
+
+                Size sz {halBuf.width, halBuf.height};
+                ATRACE_BEGIN("formatConvert");
+                ret = V3_4::implementation::formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
+                ATRACE_END();
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: format coversion failed!", __FUNCTION__);
+                }
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            default:
+                lk.unlock();
+                return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+        }
+    } // for each buffer
+    mScaledYu12Frames.clear();
+
+    // Don't hold the lock while calling back to parent
+    lk.unlock();
+    Status st = parent->processCaptureResult(req);
+    if (st != Status::OK) {
+        return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
+    }
+    signalRequestDone();
+    return true;
+}
+
+Status ExternalCameraOfflineSession::importBuffer(int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf) {
+    Mutex::Autolock _l(mCbsLock);
+    return V3_4::implementation::importBufferImpl(
+            mCirculatingBuffers, sHandleImporter, streamId,
+            bufId, buf, outBufPtr, allowEmptyBuf);
+    return Status::OK;
+};
+
+#define UPDATE(md, tag, data, size)               \
+do {                                              \
+    if ((md).update((tag), (data), (size))) {     \
+        ALOGE("Update " #tag " failed!");         \
+        return BAD_VALUE;                         \
+    }                                             \
+} while (0)
+
+status_t ExternalCameraOfflineSession::fillCaptureResult(
+        common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
+    bool afTrigger = false;
+    {
+        std::lock_guard<std::mutex> lk(mAfTriggerLock);
+        afTrigger = mAfTrigger;
+        if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+            camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+            if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+                mAfTrigger = afTrigger = true;
+            } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+                mAfTrigger = afTrigger = false;
+            }
+        }
+    }
+
+    // For USB camera, the USB camera handles everything and we don't have control
+    // over AF. We only simply fake the AF metadata based on the request
+    // received here.
+    uint8_t afState;
+    if (afTrigger) {
+        afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+    } else {
+        afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+    }
+    UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+    camera_metadata_ro_entry activeArraySize =
+            mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+    return V3_4::implementation::fillCaptureResultCommon(md, timestamp, activeArraySize);
+}
+
+#undef UPDATE
+
+Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
+    ATRACE_CALL();
+    // Fill output buffers
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    CaptureResult& result = results[0];
+    result.frameNumber = req->frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req->buffers.size());
+    for (size_t i = 0; i < req->buffers.size(); i++) {
+        result.outputBuffers[i].streamId = req->buffers[i].streamId;
+        result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+        if (req->buffers[i].fenceTimeout) {
+            result.outputBuffers[i].status = BufferStatus::ERROR;
+            if (req->buffers[i].acquireFence >= 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+            }
+            notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+        } else {
+            result.outputBuffers[i].status = BufferStatus::OK;
+            // TODO: refactor
+            if (req->buffers[i].acquireFence >= 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+            }
+        }
+    }
+
+    // Fill capture result metadata
+    fillCaptureResult(req->setting, req->shutterTs);
+    const camera_metadata_t *rawResult = req->setting.getAndLock();
+    V3_2::implementation::convertToHidl(rawResult, &result.result);
+    req->setting.unlock(rawResult);
+
+    // Callback into framework
+    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+    V3_4::implementation::freeReleaseFences(results);
+    return Status::OK;
+};
+
+void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback(
+        hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        const nsecs_t NS_TO_SECOND = 1000000000;
+        ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(/* 1s */NS_TO_SECOND) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+                    __FUNCTION__);
+            return;
+        }
+    }
+    if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+        for (CaptureResult &result : results) {
+            if (result.result.size() > 0) {
+                if (mResultMetadataQueue->write(result.result.data(), result.result.size())) {
+                    result.fmqResultSize = result.result.size();
+                    result.result.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    result.fmqResultSize = 0;
+                }
+            } else {
+                result.fmqResultSize = 0;
+            }
+        }
+    }
+    auto status = mCallback->processCaptureResult(results);
+    if (!status.isOk()) {
+        ALOGE("%s: processCaptureResult ERROR : %s", __FUNCTION__,
+              status.description().c_str());
+    }
+
+    mProcessCaptureResultLock.unlock();
+}
+
+Status ExternalCameraOfflineSession::processCaptureRequestError(
+        const std::shared_ptr<HalRequest>& req,
+        /*out*/std::vector<NotifyMsg>* outMsgs,
+        /*out*/std::vector<CaptureResult>* outResults) {
+    ATRACE_CALL();
+
+    if (outMsgs == nullptr) {
+        notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+    } else {
+        NotifyMsg shutter;
+        shutter.type = MsgType::SHUTTER;
+        shutter.msg.shutter.frameNumber = req->frameNumber;
+        shutter.msg.shutter.timestamp = req->shutterTs;
+
+        NotifyMsg error;
+        error.type = MsgType::ERROR;
+        error.msg.error.frameNumber = req->frameNumber;
+        error.msg.error.errorStreamId = -1;
+        error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+        outMsgs->push_back(shutter);
+        outMsgs->push_back(error);
+    }
+
+    // Fill output buffers
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    CaptureResult& result = results[0];
+    result.frameNumber = req->frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req->buffers.size());
+    for (size_t i = 0; i < req->buffers.size(); i++) {
+        result.outputBuffers[i].streamId = req->buffers[i].streamId;
+        result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+        result.outputBuffers[i].status = BufferStatus::ERROR;
+        if (req->buffers[i].acquireFence >= 0) {
+            native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+            handle->data[0] = req->buffers[i].acquireFence;
+            result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+        }
+    }
+
+    if (outResults == nullptr) {
+        // Callback into framework
+        invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+        V3_4::implementation::freeReleaseFences(results);
+    } else {
+        outResults->push_back(result);
+    }
+    return Status::OK;
+};
+
+ssize_t ExternalCameraOfflineSession::getJpegBufferSize(
+        uint32_t /*width*/, uint32_t /*height*/) const {
+    // Empty implementation here as the jpeg buffer size is passed in by ctor
+    return 0;
+};
+
+void ExternalCameraOfflineSession::notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) {
+    NotifyMsg msg;
+    msg.type = MsgType::ERROR;
+    msg.msg.error.frameNumber = frameNumber;
+    msg.msg.error.errorStreamId = streamId;
+    msg.msg.error.errorCode = ec;
+    mCallback->notify({msg});
+};
+
+Return<void> ExternalCameraOfflineSession::setCallback(const sp<ICameraDeviceCallback>& cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    if (mCallback != nullptr && cb != nullptr) {
+        ALOGE("%s: callback must not be set twice!", __FUNCTION__);
+        return Void();
+    }
+    mCallback = cb;
+
+    initOutputThread();
+
+    if (mOutputThread == nullptr) {
+        ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+    }
+    return Void();
+}
+
+Return<void> ExternalCameraOfflineSession::getCaptureResultMetadataQueue(
+        V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    _hidl_cb(*mResultMetadataQueue->getDesc());
+    return Void();
+}
+
+void ExternalCameraOfflineSession::cleanupBuffersLocked(int id) {
+    for (auto& pair : mCirculatingBuffers.at(id)) {
+        sHandleImporter.freeBuffer(pair.second);
+    }
+    mCirculatingBuffers[id].clear();
+    mCirculatingBuffers.erase(id);
+}
+
+Return<void> ExternalCameraOfflineSession::close() {
+    Mutex::Autolock _il(mInterfaceLock);
+    {
+        Mutex::Autolock _l(mLock);
+        if (mClosed) {
+            ALOGW("%s: offline session already closed!", __FUNCTION__);
+            return Void();
+        }
+    }
+    if (mBufferRequestThread) {
+        mBufferRequestThread->requestExit();
+        mBufferRequestThread->join();
+        mBufferRequestThread.clear();
+    }
+    if (mOutputThread) {
+        mOutputThread->flush();
+        mOutputThread->requestExit();
+        mOutputThread->join();
+        mOutputThread.clear();
+    }
+
+    Mutex::Autolock _l(mLock);
+    // free all buffers
+    {
+        Mutex::Autolock _cbl(mCbsLock);
+        for(auto stream : mOfflineStreams) {
+            cleanupBuffersLocked(stream.id);
+        }
+    }
+    mCallback.clear();
+    mClosed = true;
+    return Void();
+}
+
+} // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.6/default/OWNERS b/camera/device/3.6/default/OWNERS
new file mode 100644
index 0000000..f48a95c
--- /dev/null
+++ b/camera/device/3.6/default/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
new file mode 100644
index 0000000..db0d9a5
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+
+struct ExternalCameraDeviceSession : public V3_5::implementation::ExternalCameraDeviceSession {
+
+    ExternalCameraDeviceSession(const sp<V3_2::ICameraDeviceCallback>&,
+            const ExternalCameraConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats,
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            unique_fd v4l2Fd);
+    virtual ~ExternalCameraDeviceSession();
+
+    // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+    // dealing with minor version revs and simultaneous implementation and interface inheritance
+    virtual sp<V3_4::ICameraDeviceSession> getInterface() override {
+        return new TrampolineSessionInterface_3_6(this);
+    }
+
+protected:
+    // Methods from v3.5 and earlier will trampoline to inherited implementation
+    Return<void> configureStreams_3_6(
+            const StreamConfiguration& requestedConfiguration,
+            ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb);
+
+    Return<void> switchToOffline(
+            const hidl_vec<int32_t>& streamsToKeep,
+            ICameraDeviceSession::switchToOffline_cb _hidl_cb);
+
+    void fillOutputStream3_6(const V3_3::HalStreamConfiguration& outStreams_v33,
+            /*out*/V3_6::HalStreamConfiguration* outStreams_v36);
+    bool supportOfflineLocked(int32_t streamId);
+
+    // Main body of switchToOffline. This method does not invoke any callbacks
+    // but instead returns the necessary callbacks in output arguments so callers
+    // can callback later without holding any locks
+    Status switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+            /*out*/std::vector<NotifyMsg>* msgs,
+            /*out*/std::vector<CaptureResult>* results,
+            /*out*/CameraOfflineSessionInfo* info,
+            /*out*/sp<ICameraOfflineSession>* session);
+
+    // Whether a request can be completely dropped when switching to offline
+    bool canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+            std::shared_ptr<V3_4::implementation::HalRequest> halReq);
+
+    void fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+            std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+            const std::map<int, CirculatingBuffers>& circulatingBuffers,
+            /*out*/CameraOfflineSessionInfo* info);
+
+private:
+
+    struct TrampolineSessionInterface_3_6 : public ICameraDeviceSession {
+        TrampolineSessionInterface_3_6(sp<ExternalCameraDeviceSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> constructDefaultRequestSettings(
+                RequestTemplate type,
+                V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+            return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+            return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+            return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> getCaptureRequestMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<Status> flush() override {
+            return mParent->flush();
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+        virtual Return<void> configureStreams_3_3(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_3_cb _hidl_cb) override {
+            return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_4(
+                const V3_4::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_4_cb _hidl_cb) override {
+            return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
+            return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_5(
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_5_cb _hidl_cb) override {
+            return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> signalStreamFlush(
+                const hidl_vec<int32_t>& requests,
+                uint32_t streamConfigCounter) override {
+            return mParent->signalStreamFlush(requests, streamConfigCounter);
+        }
+
+        virtual Return<void> isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams,
+                const V3_2::CameraMetadata& newSessionParams,
+                ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) override {
+            return mParent->isReconfigurationRequired(oldSessionParams, newSessionParams, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_6(
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_6_cb _hidl_cb) override {
+            return mParent->configureStreams_3_6(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> switchToOffline(
+                const hidl_vec<int32_t>& streamsToKeep,
+                switchToOffline_cb _hidl_cb) override {
+            return mParent->switchToOffline(streamsToKeep, _hidl_cb);
+        }
+
+    private:
+        sp<ExternalCameraDeviceSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h
new file mode 100644
index 0000000..020bec4
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
+
+#include <android/hardware/camera/device/3.6/ICameraDevice.h>
+
+#include "ExternalCameraDeviceSession.h"
+#include <../../../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_6::ICameraDevice;
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct ExternalCameraDevice : public V3_5::implementation::ExternalCameraDevice {
+
+    // Called by external camera provider HAL.
+    // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+    // be multiple CameraDevice trying to access the same physical camera.  Also, provider will have
+    // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+    // camera is detached.
+    ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg);
+    virtual ~ExternalCameraDevice();
+
+    virtual sp<V3_2::ICameraDevice> getInterface() override {
+        return new TrampolineDeviceInterface_3_6(this);
+    }
+
+protected:
+    virtual sp<V3_4::implementation::ExternalCameraDeviceSession> createSession(
+            const sp<V3_2::ICameraDeviceCallback>&,
+            const ExternalCameraConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats,
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            unique_fd v4l2Fd) override;
+
+    virtual status_t initAvailableCapabilities(
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*) override;
+
+private:
+    struct TrampolineDeviceInterface_3_6 : public ICameraDevice {
+        TrampolineDeviceInterface_3_6(sp<ExternalCameraDevice> parent) :
+            mParent(parent) {}
+
+        virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb)
+                override {
+            return mParent->getResourceCost(_hidl_cb);
+        }
+
+        virtual Return<void> getCameraCharacteristics(
+                V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getCameraCharacteristics(_hidl_cb);
+        }
+
+        virtual Return<Status> setTorchMode(TorchMode mode) override {
+            return mParent->setTorchMode(mode);
+        }
+
+        virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback,
+                V3_2::ICameraDevice::open_cb _hidl_cb) override {
+            return mParent->open(callback, _hidl_cb);
+        }
+
+        virtual Return<void> dumpState(const hidl_handle& fd) override {
+            return mParent->dumpState(fd);
+        }
+
+        virtual Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+                V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb);
+        }
+
+        virtual Return<void> isStreamCombinationSupported(
+                const V3_4::StreamConfiguration& streams,
+                V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) override {
+            return mParent->isStreamCombinationSupported(streams, _hidl_cb);
+        }
+
+    private:
+        sp<ExternalCameraDevice> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
new file mode 100644
index 0000000..230b67c
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
@@ -0,0 +1,232 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+#include <android/hardware/camera/common/1.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <deque>
+#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include <HandleImporter.h>
+#include <Exif.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_5::BufferRequest;
+using ::android::hardware::camera::device::V3_5::BufferRequestStatus;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_2::DataspaceFlags;
+using ::android::hardware::camera::device::V3_2::CameraBlob;
+using ::android::hardware::camera::device::V3_2::CameraBlobId;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::camera::external::common::SizeHasher;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::CirculatingBuffers;
+using ::android::hardware::camera::device::V3_4::implementation::HalRequest;
+using ::android::hardware::camera::device::V3_4::implementation::OutputThreadInterface;
+
+struct ExternalCameraOfflineSession : public virtual RefBase,
+        public virtual OutputThreadInterface {
+
+    ExternalCameraOfflineSession(
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            const std::string& exifMake,
+            const std::string& exifModel,
+            uint32_t blobBufferSize,
+            bool afTrigger,
+            const hidl_vec<Stream>& offlineStreams,
+            std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+            const std::map<int, CirculatingBuffers>& circulatingBuffers);
+
+    bool initialize();
+
+    virtual ~ExternalCameraOfflineSession();
+
+    // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+    // dealing with minor version revs and simultaneous implementation and interface inheritance
+    virtual sp<V3_6::ICameraOfflineSession> getInterface() {
+        return new TrampolineSessionInterface_3_6(this);
+    }
+
+protected:
+
+    // Methods from OutputThreadInterface
+    virtual Status importBuffer(int32_t streamId,
+            uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr,
+            bool allowEmptyBuf) override;
+
+    virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
+
+    virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+            /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+            /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+    virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+    // End of OutputThreadInterface methods
+
+    class OutputThread : public V3_5::implementation::ExternalCameraDeviceSession::OutputThread {
+    public:
+        OutputThread(
+                wp<OutputThreadInterface> parent, CroppingType ct,
+                const common::V1_0::helper::CameraMetadata& chars,
+                sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> bufReqThread,
+                std::deque<std::shared_ptr<HalRequest>>& offlineReqs) :
+                V3_5::implementation::ExternalCameraDeviceSession::OutputThread(
+                        parent, ct, chars, bufReqThread),
+                mOfflineReqs(offlineReqs) {}
+
+        virtual bool threadLoop() override;
+
+    protected:
+        std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+    }; // OutputThread
+
+
+    Return<void> setCallback(const sp<ICameraDeviceCallback>& cb);
+
+    Return<void> getCaptureResultMetadataQueue(
+            V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb);
+
+    Return<void> close();
+
+    void initOutputThread();
+
+    void invokeProcessCaptureResultCallback(
+            hidl_vec<CaptureResult> &results, bool tryWriteFmq);
+
+    status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
+
+    void cleanupBuffersLocked(int id);
+
+    // Protect (most of) HIDL interface methods from synchronized-entering
+    mutable Mutex mInterfaceLock;
+
+    mutable Mutex mLock; // Protect all data members except otherwise noted
+
+    bool mClosed = false;
+    const CroppingType mCroppingType;
+    const common::V1_0::helper::CameraMetadata mChars;
+    const std::string mCameraId;
+    const std::string mExifMake;
+    const std::string mExifModel;
+    const uint32_t mBlobBufferSize;
+
+    std::mutex mAfTriggerLock; // protect mAfTrigger
+    bool mAfTrigger;
+
+    const hidl_vec<Stream> mOfflineStreams;
+    std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+
+    // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+    mutable Mutex mCbsLock;
+    std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+    static HandleImporter sHandleImporter;
+
+    using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+    std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+    // Protect against invokeProcessCaptureResultCallback()
+    Mutex mProcessCaptureResultLock;
+
+    sp<ICameraDeviceCallback> mCallback;
+
+    sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> mBufferRequestThread;
+    sp<OutputThread> mOutputThread;
+private:
+
+    struct TrampolineSessionInterface_3_6 : public ICameraOfflineSession {
+        TrampolineSessionInterface_3_6(sp<ExternalCameraOfflineSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> setCallback(const sp<ICameraDeviceCallback>& cb) override {
+            return mParent->setCallback(cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+    private:
+        sp<ExternalCameraOfflineSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index 9203b8d..627ddf4 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -49,6 +49,7 @@
         "android.hardware.camera.device@3.3",
         "android.hardware.camera.device@3.4",
         "android.hardware.camera.device@3.5",
+        "android.hardware.camera.device@3.6",
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
@@ -60,6 +61,7 @@
         "camera.device@3.4-impl",
         "camera.device@3.5-external-impl",
         "camera.device@3.5-impl",
+        "camera.device@3.6-external-impl",
         "libcamera_metadata",
         "libcutils",
         "libhardware",
@@ -73,7 +75,8 @@
     ],
     header_libs: [
         "camera.device@3.4-external-impl_headers",
-        "camera.device@3.5-external-impl_headers"
+        "camera.device@3.5-external-impl_headers",
+        "camera.device@3.6-external-impl_headers"
     ],
     export_include_dirs: ["."],
 }
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index a6fd288..2bfced2 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -26,6 +26,7 @@
 #include "ExternalCameraProviderImpl_2_4.h"
 #include "ExternalCameraDevice_3_4.h"
 #include "ExternalCameraDevice_3_5.h"
+#include "ExternalCameraDevice_3_6.h"
 
 namespace android {
 namespace hardware {
@@ -73,6 +74,7 @@
     switch(mPreferredHal3MinorVersion) {
         case 4:
         case 5:
+        case 6:
             // OK
             break;
         default:
@@ -171,6 +173,12 @@
                     cameraId, mCfg);
             break;
         }
+        case 6: {
+            ALOGV("Constructing v3.6 external camera device");
+            deviceImpl = new device::V3_6::implementation::ExternalCameraDevice(
+                    cameraId, mCfg);
+            break;
+        }
         default:
             ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion);
             _hidl_cb(Status::INTERNAL_ERROR, nullptr);
@@ -202,7 +210,9 @@
     ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
     Mutex::Autolock _l(mLock);
     std::string deviceName;
-    if (mPreferredHal3MinorVersion == 5) {
+    if (mPreferredHal3MinorVersion == 6) {
+        deviceName = std::string("device@3.6/external/") + devName;
+    } else if (mPreferredHal3MinorVersion == 5) {
         deviceName = std::string("device@3.5/external/") + devName;
     } else {
         deviceName = std::string("device@3.4/external/") + devName;
@@ -249,7 +259,9 @@
 void ExternalCameraProviderImpl_2_4::deviceRemoved(const char* devName) {
     Mutex::Autolock _l(mLock);
     std::string deviceName;
-    if (mPreferredHal3MinorVersion == 5) {
+    if (mPreferredHal3MinorVersion == 6) {
+        deviceName = std::string("device@3.6/external/") + devName;
+    } else if (mPreferredHal3MinorVersion == 5) {
         deviceName = std::string("device@3.5/external/") + devName;
     } else {
         deviceName = std::string("device@3.4/external/") + devName;
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 15f5c9a..4b9d6f1 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -38,7 +38,8 @@
         "android.hardware.camera.device@3.3",
         "android.hardware.camera.device@3.4",
         "android.hardware.camera.device@3.5",
-	"android.hardware.camera.metadata@3.4",
+        "android.hardware.camera.device@3.6",
+        "android.hardware.camera.metadata@3.4",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.provider@2.5",
         "android.hardware.camera.provider@2.6",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index b4092ca..5c73aa2 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -37,6 +37,8 @@
 #include <android/hardware/camera/device/3.5/ICameraDevice.h>
 #include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
 #include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraDevice.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
 #include <android/hardware/camera/metadata/3.4/types.h>
 #include <android/hardware/camera/provider/2.4/ICameraProvider.h>
 #include <android/hardware/camera/provider/2.5/ICameraProvider.h>
@@ -133,6 +135,8 @@
 
 const uint32_t kMaxPreviewWidth = 1920;
 const uint32_t kMaxPreviewHeight = 1080;
+const uint32_t kMaxStillWidth = 2048;
+const uint32_t kMaxStillHeight = 1536;
 const uint32_t kMaxVideoWidth = 4096;
 const uint32_t kMaxVideoHeight = 2160;
 const int64_t kStreamBufferTimeoutSec = 3;
@@ -162,11 +166,13 @@
 namespace {
     // "device@<version>/legacy/<id>"
     const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
+    const int CAMERA_DEVICE_API_VERSION_3_6 = 0x306;
     const int CAMERA_DEVICE_API_VERSION_3_5 = 0x305;
     const int CAMERA_DEVICE_API_VERSION_3_4 = 0x304;
     const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303;
     const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
     const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
+    const char *kHAL3_6 = "3.6";
     const char *kHAL3_5 = "3.5";
     const char *kHAL3_4 = "3.4";
     const char *kHAL3_3 = "3.3";
@@ -202,7 +208,9 @@
             return -1;
         }
 
-        if (version.compare(kHAL3_5) == 0) {
+        if (version.compare(kHAL3_6) == 0) {
+            return CAMERA_DEVICE_API_VERSION_3_6;
+        } else if (version.compare(kHAL3_5) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_5;
         } else if (version.compare(kHAL3_4) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_4;
@@ -717,7 +725,8 @@
     void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
             sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
             sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
-            sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/);
+            sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
+            sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/);
     void castDevice(const sp<device::V3_2::ICameraDevice> &device, int32_t deviceVersion,
             sp<device::V3_5::ICameraDevice> *device3_5/*out*/);
     void createStreamConfiguration(const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
@@ -727,6 +736,17 @@
             ::android::hardware::camera::device::V3_5::StreamConfiguration *config3_5,
             uint32_t jpegBufferSize = 0);
 
+    void configureOfflineStillStream(const std::string &name, int32_t deviceVersion,
+            sp<ICameraProvider> provider,
+            const AvailableStream *threshold,
+            sp<device::V3_6::ICameraDeviceSession> *session/*out*/,
+            V3_2::Stream *stream /*out*/,
+            device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/,
+            bool *supportsPartialResults /*out*/,
+            uint32_t *partialResultCount /*out*/,
+            sp<DeviceCb> *outCb /*out*/,
+            uint32_t *jpegBufferSize /*out*/,
+            bool *useHalBufManager /*out*/);
     void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
             const AvailableStream *previewThreshold,
@@ -792,6 +812,7 @@
             uint32_t* outBufSize);
     static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
     static Status isLogicalMultiCamera(const camera_metadata_t *staticMeta);
+    static Status isOfflineSessionSupported(const camera_metadata_t *staticMeta);
     static Status getPhysicalCameraIds(const camera_metadata_t *staticMeta,
             std::unordered_set<std::string> *physicalIds/*out*/);
     static Status getSupportedKeys(camera_metadata_t *staticMeta,
@@ -818,6 +839,9 @@
             CameraParameters &cameraParams, const char *mode) ;
     static Status isMonochromeCamera(const camera_metadata_t *staticMeta);
 
+    // Used by switchToOffline where a new result queue is created for offline reqs
+    void updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue);
+
 protected:
 
     // In-flight queue for tracking completion of capture requests.
@@ -1442,7 +1466,13 @@
         hidl_vec<StreamBuffer> tmpRetBuffers(bufReq.numBuffersRequested);
         for (size_t j = 0; j < bufReq.numBuffersRequested; j++) {
             hidl_handle buffer_handle;
-            mParent->allocateGraphicBuffer(stream.v3_2.width, stream.v3_2.height,
+            uint32_t w = stream.v3_2.width;
+            uint32_t h = stream.v3_2.height;
+            if (stream.v3_2.format == PixelFormat::BLOB) {
+                w = stream.bufferSize;
+                h = 1;
+            }
+            mParent->allocateGraphicBuffer(w, h,
                     android_convertGralloc1To0Usage(
                             halStream.producerUsage, halStream.consumerUsage),
                     halStream.overrideFormat, &buffer_handle);
@@ -1706,6 +1736,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -1748,6 +1779,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2489,6 +2521,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2568,6 +2601,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2694,6 +2728,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2759,6 +2794,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2788,8 +2824,12 @@
                 sp<device::V3_3::ICameraDeviceSession> sessionV3_3;
                 sp<device::V3_4::ICameraDeviceSession> sessionV3_4;
                 sp<device::V3_5::ICameraDeviceSession> sessionV3_5;
-                castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4, &sessionV3_5);
-                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
+                sp<device::V3_6::ICameraDeviceSession> sessionV3_6;
+                castSession(session, deviceVersion, &sessionV3_3,
+                        &sessionV3_4, &sessionV3_5, &sessionV3_6);
+                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) {
+                    ASSERT_TRUE(sessionV3_6.get() != nullptr);
+                } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
                     ASSERT_TRUE(sessionV3_5.get() != nullptr);
                 } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
                     ASSERT_TRUE(sessionV3_4.get() != nullptr);
@@ -2851,6 +2891,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2949,11 +2990,12 @@
         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;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider,
                 &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         outputStreams.clear();
@@ -3057,11 +3099,12 @@
         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;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         outputStreams.clear();
@@ -3254,11 +3297,12 @@
         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;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         Status rc = isZSLModeAvailable(staticMeta);
@@ -3421,8 +3465,9 @@
         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;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
             ASSERT_NE(session3_4, nullptr);
         } else {
@@ -3543,11 +3588,12 @@
         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;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         // Check if camera support depth only
@@ -3660,11 +3706,12 @@
         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;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         Status rc = isConstrainedModeAvailable(staticMeta);
@@ -3871,11 +3918,12 @@
         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;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         // Check if camera support depth only
@@ -4613,6 +4661,207 @@
     }
 }
 
+// Verify camera offline session behavior
+TEST_P(CameraHidlTest, switchToOffline) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    AvailableStream threshold = {kMaxStillWidth, kMaxStillHeight,
+                                        static_cast<int32_t>(PixelFormat::BLOB)};
+    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_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
+
+        camera_metadata_t* staticMetaBuffer;
+        {
+            Return<void> ret;
+            sp<ICameraDeviceSession> session;
+            openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta(
+                    staticMetaBuffer);
+
+            if (isOfflineSessionSupported(staticMetaBuffer) != Status::OK) {
+                ret = session->close();
+                ASSERT_TRUE(ret.isOk());
+                continue;
+            }
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+        }
+
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        V3_2::Stream stream;
+        V3_6::HalStreamConfiguration halStreamConfig;
+        sp<V3_6::ICameraDeviceSession> session;
+        sp<DeviceCb> cb;
+        uint32_t jpegBufferSize;
+        bool useHalBufManager;
+        configureOfflineStillStream(name, deviceVersion, mProvider, &threshold,
+                &session /*out*/, &stream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/, &partialResultCount /*out*/, &cb /*out*/,
+                &jpegBufferSize /*out*/, &useHalBufManager /*out*/);
+
+        auto ret = session->constructDefaultRequestSettings(RequestTemplate::STILL_CAPTURE,
+            [&](auto status, const auto& req) {
+                ASSERT_EQ(Status::OK, status);
+                settings = req; });
+        ASSERT_TRUE(ret.isOk());
+
+        std::shared_ptr<ResultMetadataQueue> resultQueue;
+        auto resultQueueRet =
+            session->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());
+
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta;
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
+        hidl_handle buffers[kBurstFrameCount];
+        StreamBuffer outputBuffers[kBurstFrameCount];
+        CaptureRequest requests[kBurstFrameCount];
+        InFlightRequest inflightReqs[kBurstFrameCount];
+        hidl_vec<uint8_t> requestSettings[kBurstFrameCount];
+        auto halStreamConfig3_2 = halStreamConfig.streams[0].v3_4.v3_3.v3_2;
+        for (uint32_t i = 0; i < kBurstFrameCount; i++) {
+            std::unique_lock<std::mutex> l(mLock);
+
+            if (useHalBufManager) {
+                outputBuffers[i] = {halStreamConfig3_2.id, /*bufferId*/ 0,
+                        buffers[i], BufferStatus::OK, nullptr, nullptr};
+            } else {
+                // jpeg buffer (w,h) = (blobLen, 1)
+                allocateGraphicBuffer(jpegBufferSize, /*height*/1,
+                        android_convertGralloc1To0Usage(halStreamConfig3_2.producerUsage,
+                            halStreamConfig3_2.consumerUsage),
+                        halStreamConfig3_2.overrideFormat, &buffers[i]);
+                outputBuffers[i] = {halStreamConfig3_2.id, bufferId + i,
+                    buffers[i], BufferStatus::OK, nullptr, nullptr};
+            }
+
+            requestMeta.clear();
+            requestMeta.append(reinterpret_cast<camera_metadata_t *> (settings.data()));
+
+            camera_metadata_t *metaBuffer = requestMeta.release();
+            requestSettings[i].setToExternal(reinterpret_cast<uint8_t *> (metaBuffer),
+                    get_camera_metadata_size(metaBuffer), true);
+
+            requests[i] = {frameNumber + i, 0 /* fmqSettingsSize */, requestSettings[i],
+                emptyInputBuffer, {outputBuffers[i]}};
+
+            inflightReqs[i] = {1, false, supportsPartialResults, partialResultCount,
+                    resultQueue};
+            mInflightMap.add(frameNumber + i, &inflightReqs[i]);
+        }
+
+        Status status = Status::INTERNAL_ERROR;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        hidl_vec<CaptureRequest> burstRequest;
+        burstRequest.setToExternal(requests, kBurstFrameCount);
+        Return<void> returnStatus = session->processCaptureRequest(burstRequest, cachesToRemove,
+                [&status, &numRequestProcessed] (auto s, uint32_t n) {
+                    status = s;
+                    numRequestProcessed = n;
+                });
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_EQ(numRequestProcessed, kBurstFrameCount);
+
+        hidl_vec<int32_t> offlineStreamIds = {halStreamConfig3_2.id};
+        V3_6::CameraOfflineSessionInfo offlineSessionInfo;
+        sp<device::V3_6::ICameraOfflineSession> offlineSession;
+        returnStatus = session->switchToOffline(offlineStreamIds,
+                [&status, &offlineSessionInfo, &offlineSession] (auto stat, auto info,
+                    auto offSession) {
+                    status = stat;
+                    offlineSessionInfo = info;
+                    offlineSession = offSession;
+                });
+        ASSERT_TRUE(returnStatus.isOk());
+
+        if (!halStreamConfig.streams[0].supportOffline) {
+            ASSERT_EQ(status, Status::ILLEGAL_ARGUMENT);
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        ASSERT_EQ(status, Status::OK);
+        // Hal might be unable to find any requests qualified for offline mode.
+        if (offlineSession == nullptr) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        ASSERT_EQ(offlineSessionInfo.offlineStreams.size(), 1u);
+        ASSERT_EQ(offlineSessionInfo.offlineStreams[0].id, halStreamConfig3_2.id);
+        ASSERT_NE(offlineSessionInfo.offlineRequests.size(), 0u);
+
+        // close device session to make sure offline session does not rely on it
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+
+        std::shared_ptr<ResultMetadataQueue> offlineResultQueue;
+        auto offlineResultQueueRet =
+            offlineSession->getCaptureResultMetadataQueue(
+                [&offlineResultQueue](const auto& descriptor) {
+                    offlineResultQueue = std::make_shared<ResultMetadataQueue>(
+                            descriptor);
+                    if (!offlineResultQueue->isValid() ||
+                            offlineResultQueue->availableToWrite() <= 0) {
+                        ALOGE("%s: offline session returns empty result metadata fmq,"
+                                " not use it", __func__);
+                        offlineResultQueue = nullptr;
+                        // Don't use the queue onwards.
+                    }
+                });
+        ASSERT_TRUE(offlineResultQueueRet.isOk());
+
+        updateInflightResultQueue(offlineResultQueue);
+
+        ret = offlineSession->setCallback(cb);
+        ASSERT_TRUE(ret.isOk());
+
+        for (size_t i = 0; i < kBurstFrameCount; i++) {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReqs[i].errorCodeValid && ((0 < inflightReqs[i].numBuffersLeft) ||
+                            (!inflightReqs[i].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(inflightReqs[i].errorCodeValid);
+            ASSERT_NE(inflightReqs[i].resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(stream.id, inflightReqs[i].resultOutputBuffers[0].streamId);
+            ASSERT_FALSE(inflightReqs[i].collectedResult.isEmpty());
+        }
+
+
+        ret = offlineSession->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
 // Check whether an invalid capture request with missing output buffers
 // will be reported correctly.
 TEST_P(CameraHidlTest, processCaptureRequestInvalidBuffer) {
@@ -4972,6 +5221,30 @@
     return ret;
 }
 
+// Check if the camera device has logical multi-camera capability.
+Status CameraHidlTest::isOfflineSessionSupported(const camera_metadata_t *staticMeta) {
+    Status ret = Status::METHOD_NOT_SUPPORTED;
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    for (size_t i = 0; i < entry.count; i++) {
+        if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING == entry.data.u8[i]) {
+            ret = Status::OK;
+            break;
+        }
+    }
+
+    return ret;
+}
+
 // Generate a list of physical camera ids backing a logical multi-camera.
 Status CameraHidlTest::getPhysicalCameraIds(const camera_metadata_t *staticMeta,
         std::unordered_set<std::string> *physicalIds) {
@@ -5330,7 +5603,8 @@
     *outCb = cb;
 
     sp<device::V3_3::ICameraDeviceSession> session3_3;
-    castSession(session, deviceVersion, &session3_3, session3_4, session3_5);
+    sp<device::V3_6::ICameraDeviceSession> session3_6;
+    castSession(session, deviceVersion, &session3_3, session3_4, session3_5, &session3_6);
     ASSERT_NE(nullptr, (*session3_4).get());
 
     *useHalBufManager = false;
@@ -5423,6 +5697,144 @@
     ASSERT_TRUE(ret.isOk());
 }
 
+// Configure preview stream with possible offline session support
+void CameraHidlTest::configureOfflineStillStream(const std::string &name,
+        int32_t deviceVersion,
+        sp<ICameraProvider> provider,
+        const AvailableStream *threshold,
+        sp<device::V3_6::ICameraDeviceSession> *session/*out*/,
+        V3_2::Stream *stream /*out*/,
+        device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/,
+        bool *supportsPartialResults /*out*/,
+        uint32_t *partialResultCount /*out*/,
+        sp<DeviceCb> *outCb /*out*/,
+        uint32_t *jpegBufferSize /*out*/,
+        bool *useHalBufManager /*out*/) {
+    ASSERT_NE(nullptr, session);
+    ASSERT_NE(nullptr, halStreamConfig);
+    ASSERT_NE(nullptr, stream);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_NE(nullptr, outCb);
+    ASSERT_NE(nullptr, jpegBufferSize);
+    ASSERT_NE(nullptr, useHalBufManager);
+
+    std::vector<AvailableStream> outputStreams;
+    ::android::sp<device::V3_6::ICameraDevice> cameraDevice;
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+    Return<void> ret;
+    ret = provider->getCameraDeviceInterface_V3_x(
+        name,
+        [&cameraDevice](auto status, const auto& device) {
+            ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                  (int)status);
+            ASSERT_EQ(Status::OK, status);
+            ASSERT_NE(device, nullptr);
+            auto castResult = device::V3_6::ICameraDevice::castFrom(device);
+            ASSERT_TRUE(castResult.isOk());
+            cameraDevice = castResult;
+        });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_t *staticMeta;
+    ret = cameraDevice->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);
+    }
+
+    *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);
+    }
+
+    auto st = getJpegBufferSize(staticMeta, jpegBufferSize);
+    ASSERT_EQ(st, Status::OK);
+
+    sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta);
+    ret = cameraDevice->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);
+            auto castResult = device::V3_6::ICameraDeviceSession::castFrom(newSession);
+            ASSERT_TRUE(castResult.isOk());
+            *session = castResult;
+        });
+    ASSERT_TRUE(ret.isOk());
+    *outCb = cb;
+
+    outputStreams.clear();
+    auto rc = getAvailableOutputStreams(staticMeta,
+            outputStreams, threshold);
+    size_t idx = 0;
+    int currLargest = outputStreams[0].width * outputStreams[0].height;
+    for (size_t i = 0; i < outputStreams.size(); i++) {
+        int area = outputStreams[i].width * outputStreams[i].height;
+        if (area > currLargest) {
+            idx = i;
+            currLargest = area;
+        }
+    }
+    free_camera_metadata(staticMeta);
+    ASSERT_EQ(Status::OK, rc);
+    ASSERT_FALSE(outputStreams.empty());
+
+    V3_2::DataspaceFlags dataspaceFlag = 0;
+    switch (static_cast<PixelFormat>(outputStreams[idx].format)) {
+        case PixelFormat::BLOB:
+            dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::V0_JFIF);
+            break;
+        case PixelFormat::Y16:
+            dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::DEPTH);
+            break;
+        default:
+            dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::UNKNOWN);
+    }
+
+    ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(/*size*/1);
+    V3_4::Stream stream3_4 = {{ 0 /*streamId*/, StreamType::OUTPUT,
+        static_cast<uint32_t> (outputStreams[idx].width),
+        static_cast<uint32_t> (outputStreams[idx].height),
+        static_cast<PixelFormat> (outputStreams[idx].format),
+        GRALLOC1_CONSUMER_USAGE_CPU_READ, dataspaceFlag, StreamRotation::ROTATION_0},
+        nullptr /*physicalId*/, /*bufferSize*/ *jpegBufferSize};
+    streams3_4[0] = stream3_4;
+
+    ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+    ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
+    config3_4 = {streams3_4, StreamConfigurationMode::NORMAL_MODE, {}};
+
+    config3_5.v3_4 = config3_4;
+    config3_5.streamConfigCounter = 0;
+    ret = (*session)->configureStreams_3_6(config3_5,
+            [&] (Status s, device::V3_6::HalStreamConfiguration halConfig) {
+                ASSERT_EQ(Status::OK, s);
+                *halStreamConfig = halConfig;
+
+                if (*useHalBufManager) {
+                    hidl_vec<V3_2::HalStream> halStreams3_2(1);
+                    halStreams3_2[0] = halConfig.streams[0].v3_4.v3_3.v3_2;
+                    cb->setCurrentStreamConfig(streams3_4, halStreams3_2);
+                }
+            });
+    *stream = streams3_4[0].v3_2;
+    ASSERT_TRUE(ret.isOk());
+}
+
 bool CameraHidlTest::isDepthOnly(camera_metadata_t* staticMeta) {
     camera_metadata_ro_entry scalarEntry;
     camera_metadata_ro_entry depthEntry;
@@ -5454,6 +5866,14 @@
     return false;
 }
 
+void CameraHidlTest::updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue) {
+    std::unique_lock<std::mutex> l(mLock);
+    for (size_t i = 0; i < mInflightMap.size(); i++) {
+        auto& req = mInflightMap.editValueAt(i);
+        req->resultQueue = resultQueue;
+    }
+}
+
 // Open a device session and configure a preview stream.
 void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t deviceVersion,
         sp<ICameraProvider> provider,
@@ -5522,7 +5942,8 @@
     sp<device::V3_3::ICameraDeviceSession> session3_3;
     sp<device::V3_4::ICameraDeviceSession> session3_4;
     sp<device::V3_5::ICameraDeviceSession> session3_5;
-    castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5);
+    sp<device::V3_6::ICameraDeviceSession> session3_6;
+    castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
 
     *useHalBufManager = false;
     status = find_camera_metadata_ro_entry(staticMeta,
@@ -5657,12 +6078,20 @@
 void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
         sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
         sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
-        sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/) {
+        sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
+        sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/) {
     ASSERT_NE(nullptr, session3_3);
     ASSERT_NE(nullptr, session3_4);
     ASSERT_NE(nullptr, session3_5);
+    ASSERT_NE(nullptr, session3_6);
 
     switch (deviceVersion) {
+        case CAMERA_DEVICE_API_VERSION_3_6: {
+            auto castResult = device::V3_6::ICameraDeviceSession::castFrom(session);
+            ASSERT_TRUE(castResult.isOk());
+            *session3_6 = castResult;
+        }
+        [[fallthrough]];
         case CAMERA_DEVICE_API_VERSION_3_5: {
             auto castResult = device::V3_5::ICameraDeviceSession::castFrom(session);
             ASSERT_TRUE(castResult.isOk());
@@ -6261,7 +6690,8 @@
     sp<device::V3_3::ICameraDeviceSession> session3_3;
     sp<device::V3_4::ICameraDeviceSession> session3_4;
     sp<device::V3_5::ICameraDeviceSession> session3_5;
-    castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+    sp<device::V3_6::ICameraDeviceSession> session3_6;
+    castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
     ASSERT_NE(nullptr, session3_5.get());
 
     hidl_vec<int32_t> streamIds(1);
diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp
index 4563362..9ddf651 100644
--- a/camera/provider/2.5/default/Android.bp
+++ b/camera/provider/2.5/default/Android.bp
@@ -52,6 +52,8 @@
         "android.hardware.camera.provider@2.4-external",
         "android.hardware.camera.provider@2.5",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "camera.device@3.3-impl",
@@ -72,7 +74,8 @@
     ],
     header_libs: [
         "camera.device@3.4-external-impl_headers",
-        "camera.device@3.5-external-impl_headers"
+        "camera.device@3.5-external-impl_headers",
+        "camera.device@3.6-external-impl_headers"
     ],
     export_include_dirs: ["."],
 }
@@ -165,7 +168,10 @@
         "android.hardware.camera.provider@2.5",
         "android.hardware.camera.provider@2.5-external",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "libbinder",
+        "libcamera_metadata",
         "libhidlbase",
         "liblog",
         "libtinyxml2",
@@ -179,5 +185,6 @@
         "camera.device@3.4-impl_headers",
         "camera.device@3.5-external-impl_headers",
         "camera.device@3.5-impl_headers",
+        "camera.device@3.6-external-impl_headers",
     ],
 }
diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal
index 0948db6..9c46ba0 100644
--- a/camera/provider/2.6/ICameraProvider.hal
+++ b/camera/provider/2.6/ICameraProvider.hal
@@ -38,20 +38,29 @@
      * streaming concurrently with the other camera ids in the combination.
      *
      *       Target 1                  Target 2
-     * ---------------------------------------------
-     * | Type  |   Size       |   Type  |   Size   |
-     * ---------------------------------------------
-     * | YUV   |  1280 X 720  |                    |
-     * ---------------------------------------------
-     * | PRIV  |  1280 X 720  |                    |
-     * ---------------------------------------------
-     * | YUV   |  1280 X 720  |   YUV   |1280 X 720|
-     * ---------------------------------------------
-     * | PRIV  |  1280 X 720  |   PRIV  |1280 X 720|
-     * ---------------------------------------------
-     * | PRIV  |  1280 X 720  |   YUV   |1280 X 720|
-     * ---------------------------------------------
-
+     * -----------------------------------------------------
+     * | Type         |   Size   |   Type       |   Size   |
+     * -----------------------------------------------------
+     * | YUV          |  s1440p  |                         |
+     * -----------------------------------------------------
+     * | JPEG         |  s1440p  |                         |
+     * -----------------------------------------------------
+     * | PRIV         |  s1440p  |                         |
+     * -----------------------------------------------------
+     * | YUV / PRIV   |  s720p   |  YUV / PRIV   | s1440p  |
+     * -----------------------------------------------------
+     * | YUV / PRIV   |  s720p   |  JPEG         | s1440p  |
+     * -----------------------------------------------------
+     *
+     * where:
+     * s720p - min (max output resolution for the given format, 1280 X 720)
+     * s1440p - min (max output resolution for the given format, 1920 X 1440)
+     *
+     * The camera framework must call this method whenever it gets a
+     * cameraDeviceStatusChange callback adding a new camera device or removing
+     * a camera device known to it. This is so that the camera framework can get new combinations
+     * of camera ids that can stream concurrently, that might have potentially appeared.
+     *
      * @return status Status code for the operation
      * @return cameraIds a list of camera id combinations that support
      *         concurrent stream configurations with the minimum guarantees
diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
index 7e5a61a..1b5797b 100644
--- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
+++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
@@ -16,8 +16,6 @@
 
 #define LOG_TAG "mediacas_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/cas/1.0/IDescramblerBase.h>
 #include <android/hardware/cas/1.0/types.h>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index b9d3001..f1db89d 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -45,6 +45,7 @@
         <interface>
             <name>IEvsEnumerator</name>
             <instance>default</instance>
+            <regex-instance>[a-z]+/[0-9]+</regex-instance>
         </interface>
     </hal>
     <hal format="aidl" optional="true">
@@ -152,7 +153,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.contexthub</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IContexthub</name>
             <instance>default</instance>
@@ -160,7 +161,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.drm</name>
-        <version>1.0-3</version>
+        <version>1.3</version>
         <interface>
             <name>ICryptoFactory</name>
             <regex-instance>.*</regex-instance>
@@ -279,14 +280,6 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.light</name>
-        <version>2.0</version>
-        <interface>
-            <name>ILight</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.light</name>
         <interface>
@@ -347,7 +340,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="false">
         <name>android.hardware.power</name>
         <interface>
             <name>IPower</name>
@@ -382,7 +375,10 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.radio.config</name>
-        <version>1.3</version>
+        <!--
+        See compatibility_matrix.4.xml on versioning of radio config HAL.
+        -->
+        <version>1.1</version>
         <interface>
             <name>IRadioConfig</name>
             <instance>default</instance>
@@ -415,7 +411,7 @@
     <hal format="hidl" optional="true">
         <name>android.hardware.sensors</name>
         <version>1.0</version>
-        <version>2.0</version>
+        <version>2.0-1</version>
         <interface>
             <name>ISensors</name>
             <instance>default</instance>
@@ -494,14 +490,6 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
-        <name>android.hardware.vibrator</name>
-        <version>1.0-3</version>
-        <interface>
-            <name>IVibrator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
         <name>android.hardware.vr</name>
         <version>1.0</version>
         <interface>
diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp
index 9e99c33..d51c966 100644
--- a/contexthub/1.0/vts/functional/Android.bp
+++ b/contexthub/1.0/vts/functional/Android.bp
@@ -18,7 +18,10 @@
     name: "VtsHalContexthubV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalContexthubV1_0TargetTest.cpp"],
-    static_libs: ["android.hardware.contexthub@1.0"],
+    static_libs: [
+        "android.hardware.contexthub@1.0",
+        "VtsHalContexthubUtils",
+    ],
     test_suites: [
         "general-tests",
         "vts-core",
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index a1d173b..ada232b 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -16,6 +16,10 @@
 
 #define LOG_TAG "contexthub_hidl_hal_test"
 
+#include "ContexthubCallbackBase.h"
+#include "ContexthubHidlTestBase.h"
+#include "VtsHalContexthubUtils.h"
+
 #include <android-base/logging.h>
 #include <android/hardware/contexthub/1.0/IContexthub.h>
 #include <android/hardware/contexthub/1.0/IContexthubCallback.h>
@@ -23,17 +27,17 @@
 #include <android/log.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 #include <cinttypes>
 #include <future>
 #include <utility>
 
-using ::android::hardware::Return;
-using ::android::hardware::Void;
+using ::android::sp;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
 using ::android::hardware::contexthub::V1_0::AsyncEventType;
 using ::android::hardware::contexthub::V1_0::ContextHub;
 using ::android::hardware::contexthub::V1_0::ContextHubMsg;
@@ -43,10 +47,11 @@
 using ::android::hardware::contexthub::V1_0::NanoAppBinary;
 using ::android::hardware::contexthub::V1_0::Result;
 using ::android::hardware::contexthub::V1_0::TransactionResult;
-using ::android::sp;
-
-#define ASSERT_OK(result) ASSERT_EQ(result, Result::OK)
-#define EXPECT_OK(result) EXPECT_EQ(result, Result::OK)
+using ::android::hardware::contexthub::vts_utils::asBaseType;
+using ::android::hardware::contexthub::vts_utils::ContexthubCallbackBase;
+using ::android::hardware::contexthub::vts_utils::ContexthubHidlTestBase;
+using ::android::hardware::contexthub::vts_utils::getHalAndHubIdList;
+using ::android::hardware::contexthub::vts_utils::getHubsSync;
 
 namespace {
 
@@ -54,132 +59,37 @@
 // app ID is reserved and must never appear in the list of loaded apps.
 constexpr uint64_t kNonExistentAppId = 0x476f6f6754555555;
 
-// Helper that does explicit conversion of an enum class to its underlying/base
-// type. Useful for stream output of enum values.
-template<typename EnumType>
-constexpr typename std::underlying_type<EnumType>::type asBaseType(
-    EnumType value) {
-  return static_cast<typename std::underlying_type<EnumType>::type>(value);
-}
+const std::vector<std::tuple<std::string, std::string>> kTestParameters =
+        getHalAndHubIdList<IContexthub>();
 
-// Synchronously queries IContexthub::getHubs() and returns the result
-hidl_vec<ContextHub> getHubsSync(sp<IContexthub> hubApi) {
-  hidl_vec<ContextHub> hubList;
-  std::promise<void> barrier;
-
-  hubApi->getHubs([&hubList, &barrier](const hidl_vec<ContextHub>& hubs) {
-    hubList = hubs;
-    barrier.set_value();
-  });
-  barrier.get_future().wait_for(std::chrono::seconds(1));
-
-  return hubList;
-}
-
-// Gets a list of valid hub IDs in the system
-std::vector<std::string> getHubIds(const std::string& service_name) {
-    std::vector<std::string> hubIds;
-
-    sp<IContexthub> hubApi = IContexthub::getService(service_name);
-
-    if (hubApi != nullptr) {
-        for (const ContextHub& hub : getHubsSync(hubApi)) {
-            hubIds.push_back(std::to_string(hub.hubId));
-        }
-    }
-
-    ALOGD("Running tests against all %zu reported hubs for service %s", hubIds.size(),
-          service_name.c_str());
-    return hubIds;
-}
-
-// Test fixture parameterized by hub ID, initializes the HAL and makes the context hub API handle
-// available.
-class ContexthubHidlTest : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
-  public:
-    virtual void SetUp() override {
-        hubApi = IContexthub::getService(std::get<0>(GetParam()));
-        ASSERT_NE(hubApi, nullptr);
-
-        // getHubs() must be called at least once for proper initialization of the
-        // HAL implementation
-        getHubsSync(hubApi);
-    }
-
-    uint32_t getHubId() { return std::stoi(std::get<1>(GetParam())); }
-
-    Result registerCallback(sp<IContexthubCallback> cb) {
-        Result result = hubApi->registerCallback(getHubId(), cb);
-        ALOGD("Registered callback, result %" PRIu32, result);
-        return result;
-    }
-
-    sp<IContexthub> hubApi;
-};
-
-// Base callback implementation that just logs all callbacks by default
-class ContexthubCallbackBase : public IContexthubCallback {
- public:
-  virtual Return<void> handleClientMsg(const ContextHubMsg& /*msg*/) override {
-    ALOGD("Got client message callback");
-    return Void();
-  }
-
-  virtual Return<void> handleTxnResult(
-      uint32_t txnId, TransactionResult result) override {
-    ALOGD("Got transaction result callback for txnId %" PRIu32 " with result %"
-          PRId32, txnId, result);
-    return Void();
-  }
-
-  virtual Return<void> handleHubEvent(AsyncEventType evt) override {
-    ALOGD("Got hub event callback for event type %" PRIu32, evt);
-    return Void();
-  }
-
-  virtual Return<void> handleAppAbort(uint64_t appId, uint32_t abortCode)
-      override {
-    ALOGD("Got app abort notification for appId 0x%" PRIx64 " with abort code "
-          "0x%" PRIx32, appId, abortCode);
-    return Void();
-  }
-
-  virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& /*appInfo*/)
-      override {
-    ALOGD("Got app info callback");
-    return Void();
-  }
-};
+class ContexthubHidlTest : public ContexthubHidlTestBase<IContexthub> {};
 
 // Wait for a callback to occur (signaled by the given future) up to the
 // provided timeout. If the future is invalid or the callback does not come
 // within the given time, returns false.
-template<class ReturnType>
-bool waitForCallback(
-    std::future<ReturnType> future,
-    ReturnType *result,
-    std::chrono::milliseconds timeout = std::chrono::seconds(5)) {
-  auto expiration = std::chrono::system_clock::now() + timeout;
+template <class ReturnType>
+bool waitForCallback(std::future<ReturnType> future, ReturnType* result,
+                     std::chrono::milliseconds timeout = std::chrono::seconds(5)) {
+    auto expiration = std::chrono::system_clock::now() + timeout;
 
-  EXPECT_NE(result, nullptr);
-  EXPECT_TRUE(future.valid());
-  if (result != nullptr && future.valid()) {
-    std::future_status status = future.wait_until(expiration);
-    EXPECT_NE(status, std::future_status::timeout)
-        << "Timed out waiting for callback";
+    EXPECT_NE(result, nullptr);
+    EXPECT_TRUE(future.valid());
+    if (result != nullptr && future.valid()) {
+        std::future_status status = future.wait_until(expiration);
+        EXPECT_NE(status, std::future_status::timeout) << "Timed out waiting for callback";
 
-    if (status == std::future_status::ready) {
-      *result = future.get();
-      return true;
+        if (status == std::future_status::ready) {
+            *result = future.get();
+            return true;
+        }
     }
-  }
 
-  return false;
+    return false;
 }
 
 // Ensures that the metadata reported in getHubs() is sane
 TEST_P(ContexthubHidlTest, TestGetHubs) {
-    hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
+    hidl_vec<ContextHub> hubs = getHubsSync(hubApi.get());
     ALOGD("System reports %zu hubs", hubs.size());
 
     for (const ContextHub& hub : hubs) {
@@ -199,189 +109,158 @@
 }
 
 TEST_P(ContexthubHidlTest, TestRegisterCallback) {
-  ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId());
-  ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+    ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId());
+    ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
 }
 
 TEST_P(ContexthubHidlTest, TestRegisterNullCallback) {
-  ALOGD("TestRegisterNullCallback called, hubId %" PRIu32, getHubId());
-  ASSERT_OK(registerCallback(nullptr));
+    ALOGD("TestRegisterNullCallback called, hubId %" PRIu32, getHubId());
+    ASSERT_OK(registerCallback(nullptr));
 }
 
 // Helper callback that puts the async appInfo callback data into a promise
 class QueryAppsCallback : public ContexthubCallbackBase {
- public:
-  virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& appInfo)
-      override {
-    ALOGD("Got app info callback with %zu apps", appInfo.size());
-    promise.set_value(appInfo);
-    return Void();
-  }
+  public:
+    virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& appInfo) override {
+        ALOGD("Got app info callback with %zu apps", appInfo.size());
+        promise.set_value(appInfo);
+        return Void();
+    }
 
-  std::promise<hidl_vec<HubAppInfo>> promise;
+    std::promise<hidl_vec<HubAppInfo>> promise;
 };
 
 // Calls queryApps() and checks the returned metadata
 TEST_P(ContexthubHidlTest, TestQueryApps) {
-  ALOGD("TestQueryApps called, hubId %u", getHubId());
-  sp<QueryAppsCallback> cb = new QueryAppsCallback();
-  ASSERT_OK(registerCallback(cb));
+    ALOGD("TestQueryApps called, hubId %u", getHubId());
+    sp<QueryAppsCallback> cb = new QueryAppsCallback();
+    ASSERT_OK(registerCallback(cb));
 
-  Result result = hubApi->queryApps(getHubId());
-  ASSERT_OK(result);
+    Result result = hubApi->queryApps(getHubId());
+    ASSERT_OK(result);
 
-  ALOGD("Waiting for app info callback");
-  hidl_vec<HubAppInfo> appList;
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appList));
-  for (const HubAppInfo &appInfo : appList) {
-    EXPECT_NE(appInfo.appId, UINT64_C(0));
-    EXPECT_NE(appInfo.appId, kNonExistentAppId);
-  }
+    ALOGD("Waiting for app info callback");
+    hidl_vec<HubAppInfo> appList;
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appList));
+    for (const HubAppInfo& appInfo : appList) {
+        EXPECT_NE(appInfo.appId, UINT64_C(0));
+        EXPECT_NE(appInfo.appId, kNonExistentAppId);
+    }
 }
 
 // Helper callback that puts the TransactionResult for the expectedTxnId into a
 // promise
 class TxnResultCallback : public ContexthubCallbackBase {
- public:
-  virtual Return<void> handleTxnResult(
-      uint32_t txnId, TransactionResult result) override {
-    ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %"
-          PRIu32 ") with result %" PRId32, txnId, expectedTxnId, result);
-    if (txnId == expectedTxnId) {
-      promise.set_value(result);
+  public:
+    virtual Return<void> handleTxnResult(uint32_t txnId, TransactionResult result) override {
+        ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %" PRIu32
+              ") with result %" PRId32,
+              txnId, expectedTxnId, result);
+        if (txnId == expectedTxnId) {
+            promise.set_value(result);
+        }
+        return Void();
     }
-    return Void();
-  }
 
-  uint32_t expectedTxnId = 0;
-  std::promise<TransactionResult> promise;
+    uint32_t expectedTxnId = 0;
+    std::promise<TransactionResult> promise;
 };
 
 // Parameterized fixture that sets the callback to TxnResultCallback
 class ContexthubTxnTest : public ContexthubHidlTest {
- public:
-  virtual void SetUp() override {
-    ContexthubHidlTest::SetUp();
-    ASSERT_OK(registerCallback(cb));
-  }
+  public:
+    virtual void SetUp() override {
+        ContexthubHidlTest::SetUp();
+        ASSERT_OK(registerCallback(cb));
+    }
 
-  sp<TxnResultCallback> cb = new TxnResultCallback();
+    sp<TxnResultCallback> cb = new TxnResultCallback();
 };
 
-
 // Checks cases where the hub implementation is expected to return an error, but
 // that error can be returned either synchronously or in the asynchronous
 // transaction callback. Returns an AssertionResult that can be used in
 // ASSERT/EXPECT_TRUE. Allows checking the sync result against 1 additional
 // allowed error code apart from OK and TRANSACTION_FAILED, which are always
 // allowed.
-::testing::AssertionResult checkFailureSyncOrAsync(
-    Result result, Result allowedSyncResult,
-    std::future<TransactionResult>&& future) {
-  if (result == Result::OK) {
-    // No error reported synchronously - this is OK, but then we should get an
-    // async callback with a failure status
-    TransactionResult asyncResult;
-    if (!waitForCallback(std::forward<std::future<TransactionResult>>(future),
-                         &asyncResult)) {
-      return ::testing::AssertionFailure()
-          << "Got successful sync result, then failed to receive async cb";
-    } else if (asyncResult == TransactionResult::SUCCESS) {
-      return ::testing::AssertionFailure()
-          << "Got successful sync result, then unexpected successful async "
-             "result";
+::testing::AssertionResult checkFailureSyncOrAsync(Result result, Result allowedSyncResult,
+                                                   std::future<TransactionResult>&& future) {
+    if (result == Result::OK) {
+        // No error reported synchronously - this is OK, but then we should get an
+        // async callback with a failure status
+        TransactionResult asyncResult;
+        if (!waitForCallback(std::forward<std::future<TransactionResult>>(future), &asyncResult)) {
+            return ::testing::AssertionFailure()
+                   << "Got successful sync result, then failed to receive async cb";
+        } else if (asyncResult == TransactionResult::SUCCESS) {
+            return ::testing::AssertionFailure()
+                   << "Got successful sync result, then unexpected successful async "
+                      "result";
+        }
+    } else if (result != allowedSyncResult && result != Result::TRANSACTION_FAILED) {
+        return ::testing::AssertionFailure()
+               << "Got sync result " << asBaseType(result) << ", expected TRANSACTION_FAILED or "
+               << asBaseType(allowedSyncResult);
     }
-  } else if (result != allowedSyncResult &&
-             result != Result::TRANSACTION_FAILED) {
-    return ::testing::AssertionFailure() << "Got sync result "
-        << asBaseType(result) << ", expected TRANSACTION_FAILED or "
-        << asBaseType(allowedSyncResult);
-  }
 
-  return ::testing::AssertionSuccess();
+    return ::testing::AssertionSuccess();
 }
 
 TEST_P(ContexthubTxnTest, TestSendMessageToNonExistentNanoApp) {
-  ContextHubMsg msg;
-  msg.appName = kNonExistentAppId;
-  msg.msgType = 1;
-  msg.msg.resize(4);
-  std::fill(msg.msg.begin(), msg.msg.end(), 0);
+    ContextHubMsg msg;
+    msg.appName = kNonExistentAppId;
+    msg.msgType = 1;
+    msg.msg.resize(4);
+    std::fill(msg.msg.begin(), msg.msg.end(), 0);
 
-  ALOGD("Sending message to non-existent nanoapp");
-  Result result = hubApi->sendMessageToHub(getHubId(), msg);
-  if (result != Result::OK &&
-      result != Result::BAD_PARAMS &&
-      result != Result::TRANSACTION_FAILED) {
-    FAIL() << "Got result " << asBaseType(result) << ", expected OK, BAD_PARAMS"
-        << ", or TRANSACTION_FAILED";
-  }
+    ALOGD("Sending message to non-existent nanoapp");
+    Result result = hubApi->sendMessageToHub(getHubId(), msg);
+    if (result != Result::OK && result != Result::BAD_PARAMS &&
+        result != Result::TRANSACTION_FAILED) {
+        FAIL() << "Got result " << asBaseType(result) << ", expected OK, BAD_PARAMS"
+               << ", or TRANSACTION_FAILED";
+    }
 }
 
 TEST_P(ContexthubTxnTest, TestLoadEmptyNanoApp) {
-  cb->expectedTxnId = 0123;
-  NanoAppBinary emptyApp;
+    cb->expectedTxnId = 0123;
+    NanoAppBinary emptyApp;
 
-  emptyApp.appId = kNonExistentAppId;
-  emptyApp.appVersion = 1;
-  emptyApp.flags = 0;
-  emptyApp.targetChreApiMajorVersion = 1;
-  emptyApp.targetChreApiMinorVersion = 0;
+    emptyApp.appId = kNonExistentAppId;
+    emptyApp.appVersion = 1;
+    emptyApp.flags = 0;
+    emptyApp.targetChreApiMajorVersion = 1;
+    emptyApp.targetChreApiMinorVersion = 0;
 
-  ALOGD("Loading empty nanoapp");
-  Result result = hubApi->loadNanoApp(getHubId(), emptyApp, cb->expectedTxnId);
-  EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
-                                      cb->promise.get_future()));
+    ALOGD("Loading empty nanoapp");
+    Result result = hubApi->loadNanoApp(getHubId(), emptyApp, cb->expectedTxnId);
+    EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
 }
 
 TEST_P(ContexthubTxnTest, TestUnloadNonexistentNanoApp) {
-  cb->expectedTxnId = 1234;
+    cb->expectedTxnId = 1234;
 
-  ALOGD("Unloading nonexistent nanoapp");
-  Result result = hubApi->unloadNanoApp(getHubId(), kNonExistentAppId,
-                                        cb->expectedTxnId);
-  EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
-                                      cb->promise.get_future()));
+    ALOGD("Unloading nonexistent nanoapp");
+    Result result = hubApi->unloadNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId);
+    EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
 }
 
 TEST_P(ContexthubTxnTest, TestEnableNonexistentNanoApp) {
-  cb->expectedTxnId = 2345;
+    cb->expectedTxnId = 2345;
 
-  ALOGD("Enabling nonexistent nanoapp");
-  Result result = hubApi->enableNanoApp(getHubId(), kNonExistentAppId,
-                                        cb->expectedTxnId);
-  EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
-                                      cb->promise.get_future()));
+    ALOGD("Enabling nonexistent nanoapp");
+    Result result = hubApi->enableNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId);
+    EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
 }
 
 TEST_P(ContexthubTxnTest, TestDisableNonexistentNanoApp) {
-  cb->expectedTxnId = 3456;
+    cb->expectedTxnId = 3456;
 
-  ALOGD("Disabling nonexistent nanoapp");
-  Result result = hubApi->disableNanoApp(getHubId(), kNonExistentAppId,
-                                         cb->expectedTxnId);
-  EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
-                                      cb->promise.get_future()));
+    ALOGD("Disabling nonexistent nanoapp");
+    Result result = hubApi->disableNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId);
+    EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
 }
 
-// Return the test parameters of a vecter of tuples for all IContexthub services and each of its hub
-// id: <service name of IContexthub, hub id of the IContexthub service>
-static std::vector<std::tuple<std::string, std::string>> get_parameters() {
-    std::vector<std::tuple<std::string, std::string>> parameters;
-    std::vector<std::string> service_names =
-            android::hardware::getAllHalInstanceNames(IContexthub::descriptor);
-    for (const std::string& service_name : service_names) {
-        std::vector<std::string> ids = getHubIds(service_name);
-        for (const std::string& id : ids) {
-            parameters.push_back(std::make_tuple(service_name, id));
-        }
-    }
-
-    return parameters;
-}
-
-static std::vector<std::tuple<std::string, std::string>> kTestParameters = get_parameters();
-
 INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
                          android::hardware::PrintInstanceTupleNameToString<>);
 
diff --git a/contexthub/1.1/Android.bp b/contexthub/1.1/Android.bp
new file mode 100644
index 0000000..649f1db
--- /dev/null
+++ b/contexthub/1.1/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.contexthub@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IContexthub.hal",
+    ],
+    interfaces: [
+        "android.hardware.contexthub@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/contexthub/1.1/IContexthub.hal b/contexthub/1.1/IContexthub.hal
new file mode 100644
index 0000000..a3b4bd4
--- /dev/null
+++ b/contexthub/1.1/IContexthub.hal
@@ -0,0 +1,31 @@
+/*
+ * 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.contexthub@1.1;
+
+import @1.0::IContexthub;
+import @1.0::Result;
+
+interface IContexthub extends @1.0::IContexthub {
+    /**
+     * Notification sent by the framework to indicate that the user
+     * has changed a setting.
+     *
+     * @param setting User setting that has been modified.
+     * @param newValue The update value of the user setting.
+     */
+    onSettingChanged(Setting setting, SettingValue newValue);
+};
\ No newline at end of file
diff --git a/contexthub/1.1/default/Android.bp b/contexthub/1.1/default/Android.bp
new file mode 100644
index 0000000..86858c0
--- /dev/null
+++ b/contexthub/1.1/default/Android.bp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+cc_binary {
+    name: "android.hardware.contexthub@1.1-service.mock",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.contexthub@1.1-service.rc"],
+    srcs: [
+        "Contexthub.cpp",
+        "service.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "android.hardware.contexthub@1.0",
+        "android.hardware.contexthub@1.1",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    vintf_fragments: ["android.hardware.contexthub@1.1.xml"],
+}
diff --git a/contexthub/1.1/default/Contexthub.cpp b/contexthub/1.1/default/Contexthub.cpp
new file mode 100644
index 0000000..19cc262
--- /dev/null
+++ b/contexthub/1.1/default/Contexthub.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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 "Contexthub.h"
+
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::contexthub::V1_0::ContextHub;
+using ::android::hardware::contexthub::V1_0::HubAppInfo;
+using ::android::hardware::contexthub::V1_0::Result;
+
+namespace {
+
+constexpr uint32_t kMockHubId = 0;
+
+}  // anonymous namespace
+
+Return<void> Contexthub::getHubs(getHubs_cb _hidl_cb) {
+    ContextHub hub = {};
+    hub.name = "Mock Context Hub";
+    hub.vendor = "AOSP";
+    hub.toolchain = "n/a";
+    hub.platformVersion = 1;
+    hub.toolchainVersion = 1;
+    hub.hubId = kMockHubId;
+    hub.peakMips = 1;
+    hub.peakPowerDrawMw = 1;
+    hub.maxSupportedMsgLen = 4096;
+    hub.chrePlatformId = UINT64_C(0x476f6f6754000000);
+    hub.chreApiMajorVersion = 1;
+    hub.chreApiMinorVersion = 4;
+
+    // Report a single mock hub
+    std::vector<ContextHub> hubs;
+    hubs.push_back(hub);
+
+    _hidl_cb(hubs);
+    return Void();
+}
+
+Return<Result> Contexthub::registerCallback(uint32_t hubId, const sp<IContexthubCallback>& cb) {
+    if (hubId == kMockHubId) {
+        mCallback = cb;
+        return Result::OK;
+    }
+    return Result::BAD_PARAMS;
+}
+
+// We don't expose any nanoapps, therefore all nanoapp-related API calls return with BAD_PARAMS
+Return<Result> Contexthub::sendMessageToHub(uint32_t /*hubId*/, const ContextHubMsg& /*msg*/) {
+    return Result::BAD_PARAMS;
+}
+
+Return<Result> Contexthub::loadNanoApp(uint32_t /*hubId*/, const NanoAppBinary& /*appBinary*/,
+                                       uint32_t /*transactionId*/) {
+    return Result::BAD_PARAMS;
+}
+
+Return<Result> Contexthub::unloadNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
+                                         uint32_t /*transactionId*/) {
+    return Result::BAD_PARAMS;
+}
+
+Return<Result> Contexthub::enableNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
+                                         uint32_t /*transactionId*/) {
+    return Result::BAD_PARAMS;
+}
+
+Return<Result> Contexthub::disableNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
+                                          uint32_t /*transactionId*/) {
+    return Result::BAD_PARAMS;
+}
+
+Return<Result> Contexthub::queryApps(uint32_t hubId) {
+    if (hubId == kMockHubId && mCallback != nullptr) {
+        std::vector<HubAppInfo> nanoapps;
+        mCallback->handleAppsInfo(nanoapps);
+        return Result::OK;
+    }
+    return Result::BAD_PARAMS;
+}
+
+Return<void> Contexthub::onSettingChanged(Setting /*setting*/, SettingValue /*newValue*/) {
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace contexthub
+}  // namespace hardware
+}  // namespace android
diff --git a/contexthub/1.1/default/Contexthub.h b/contexthub/1.1/default/Contexthub.h
new file mode 100644
index 0000000..0da61d1
--- /dev/null
+++ b/contexthub/1.1/default/Contexthub.h
@@ -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.
+ */
+#pragma once
+
+#include <android/hardware/contexthub/1.1/IContexthub.h>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace V1_1 {
+namespace implementation {
+
+class Contexthub : public V1_1::IContexthub {
+    using ContextHubMsg = ::android::hardware::contexthub::V1_0::ContextHubMsg;
+    using IContexthubCallback = ::android::hardware::contexthub::V1_0::IContexthubCallback;
+    using NanoAppBinary = ::android::hardware::contexthub::V1_0::NanoAppBinary;
+    using Result = ::android::hardware::contexthub::V1_0::Result;
+
+  public:
+    // Methods from V1_0::IContexthub
+    Return<void> getHubs(getHubs_cb _hidl_cb) override;
+    Return<Result> registerCallback(uint32_t hubId,
+                                    const ::android::sp<IContexthubCallback>& cb) override;
+    Return<Result> sendMessageToHub(uint32_t hubId, const ContextHubMsg& msg) override;
+    Return<Result> loadNanoApp(uint32_t hubId, const NanoAppBinary& appBinary,
+                               uint32_t transactionId) override;
+    Return<Result> unloadNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
+    Return<Result> enableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
+    Return<Result> disableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
+    Return<Result> queryApps(uint32_t hubId) override;
+
+    // Methods from V1_1::IContexthub
+    Return<void> onSettingChanged(Setting setting, SettingValue newValue) override;
+
+  private:
+    sp<IContexthubCallback> mCallback;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace contexthub
+}  // namespace hardware
+}  // namespace android
diff --git a/contexthub/1.1/default/OWNERS b/contexthub/1.1/default/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/contexthub/1.1/default/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc b/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc
new file mode 100644
index 0000000..9db00f9
--- /dev/null
+++ b/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.contexthub-hal-1-1-mock /vendor/bin/hw/android.hardware.contexthub@1.1-service.mock
+    interface android.hardware.contexthub@1.0::IContexthub default
+    interface android.hardware.contexthub@1.1::IContexthub default
+    class hal
+    user system
+    group system
diff --git a/contexthub/1.1/default/android.hardware.contexthub@1.1.xml b/contexthub/1.1/default/android.hardware.contexthub@1.1.xml
new file mode 100644
index 0000000..388f781
--- /dev/null
+++ b/contexthub/1.1/default/android.hardware.contexthub@1.1.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.contexthub</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IContexthub</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/contexthub/1.1/default/service.cpp b/contexthub/1.1/default/service.cpp
new file mode 100644
index 0000000..c5643f1
--- /dev/null
+++ b/contexthub/1.1/default/service.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "android.hardware.contexthub@1.1-service"
+
+#include <android/hardware/contexthub/1.1/IContexthub.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include "Contexthub.h"
+
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::contexthub::V1_1::IContexthub;
+using ::android::hardware::contexthub::V1_1::implementation::Contexthub;
+
+int main() {
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    ::android::sp<IContexthub> contexthub = new Contexthub();
+    if (contexthub->registerAsService() != ::android::OK) {
+        ALOGE("Failed to register Contexthub HAL instance");
+        return 1;
+    }
+
+    joinRpcThreadpool();
+    ALOGE("Service exited");
+    return 1;
+}
diff --git a/radio/config/1.3/IRadioConfigIndication.hal b/contexthub/1.1/types.hal
similarity index 64%
copy from radio/config/1.3/IRadioConfigIndication.hal
copy to contexthub/1.1/types.hal
index 9ef496c..885cf32 100644
--- a/radio/config/1.3/IRadioConfigIndication.hal
+++ b/contexthub/1.1/types.hal
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,13 +14,19 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.config@1.3;
-
-import @1.2::IRadioConfigIndication;
+package android.hardware.contexthub@1.1;
 
 /**
- * Interface declaring unsolicited radio config indications.
+ * Used to indicate the type of user setting that has changed.
  */
-interface IRadioConfigIndication extends @1.2::IRadioConfigIndication {
-
+enum Setting : uint8_t {
+    LOCATION,
 };
+
+/**
+ * Used to indicate the value of a user setting.
+ */
+enum SettingValue : uint8_t  {
+    DISABLED,
+    ENABLED,
+};
\ No newline at end of file
diff --git a/identity/1.0/vts/functional/Android.bp b/contexthub/1.1/vts/functional/Android.bp
similarity index 65%
rename from identity/1.0/vts/functional/Android.bp
rename to contexthub/1.1/vts/functional/Android.bp
index 03b49de..f1625a6 100644
--- a/identity/1.0/vts/functional/Android.bp
+++ b/contexthub/1.1/vts/functional/Android.bp
@@ -1,5 +1,5 @@
 //
-// Copyright (C) 2019 The Android Open Source Project
+// 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.
@@ -15,19 +15,13 @@
 //
 
 cc_test {
-    name: "VtsHalIdentityCredentialTargetTest",
+    name: "VtsHalContexthubV1_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
-    srcs: [
-        "VtsHalIdentityCredentialTargetTest.cpp",
-    ],
+    srcs: ["VtsHalContexthubV1_1TargetTest.cpp"],
     static_libs: [
-        "android.hardware.identity@1.0",
-        "android.hardware.identity-support-lib",
-        "android.hardware.keymaster@4.0",
-        "libcppbor",
-    ],
-    shared_libs: [
-        "libcrypto",
+        "android.hardware.contexthub@1.0",
+        "android.hardware.contexthub@1.1",
+        "VtsHalContexthubUtils",
     ],
     test_suites: [
         "general-tests",
diff --git a/contexthub/1.1/vts/functional/OWNERS b/contexthub/1.1/vts/functional/OWNERS
new file mode 100644
index 0000000..161b2f0
--- /dev/null
+++ b/contexthub/1.1/vts/functional/OWNERS
@@ -0,0 +1,8 @@
+#Context Hub team
+arthuri@google.com
+bduddie@google.com
+stange@google.com
+
+#VTS team
+dshi@google.com
+trong@google.com
diff --git a/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp b/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
new file mode 100644
index 0000000..f2fcdfc
--- /dev/null
+++ b/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 "contexthub_hidl_hal_test"
+
+#include "ContexthubCallbackBase.h"
+#include "ContexthubHidlTestBase.h"
+#include "VtsHalContexthubUtils.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/contexthub/1.0/IContexthub.h>
+#include <android/hardware/contexthub/1.1/IContexthub.h>
+#include <android/log.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <cinttypes>
+
+using ::android::hardware::contexthub::V1_1::IContexthub;
+using ::android::hardware::contexthub::V1_1::Setting;
+using ::android::hardware::contexthub::V1_1::SettingValue;
+using ::android::hardware::contexthub::vts_utils::ContexthubCallbackBase;
+using ::android::hardware::contexthub::vts_utils::ContexthubHidlTestBase;
+using ::android::hardware::contexthub::vts_utils::getHalAndHubIdList;
+
+namespace {
+
+const std::vector<std::tuple<std::string, std::string>> kTestParameters =
+        getHalAndHubIdList<IContexthub>();
+
+class ContexthubHidlTest : public ContexthubHidlTestBase<IContexthub> {};
+
+TEST_P(ContexthubHidlTest, TestOnSettingChanged) {
+    // In VTS, we only test that sending the values doesn't cause things to blow up - other test
+    // suites verify the expected E2E behavior in CHRE
+    ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+    hubApi->onSettingChanged(Setting::LOCATION, SettingValue::DISABLED);
+    hubApi->onSettingChanged(Setting::LOCATION, SettingValue::ENABLED);
+    ASSERT_OK(registerCallback(nullptr));
+}
+
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
+}  // anonymous namespace
diff --git a/radio/config/1.3/IRadioConfigIndication.hal b/contexthub/common/vts/Android.bp
similarity index 61%
copy from radio/config/1.3/IRadioConfigIndication.hal
copy to contexthub/common/vts/Android.bp
index 9ef496c..3d5196a 100644
--- a/radio/config/1.3/IRadioConfigIndication.hal
+++ b/contexthub/common/vts/Android.bp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,13 +14,17 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.config@1.3;
-
-import @1.2::IRadioConfigIndication;
-
-/**
- * Interface declaring unsolicited radio config indications.
- */
-interface IRadioConfigIndication extends @1.2::IRadioConfigIndication {
-
-};
+cc_test_library {
+    name: "VtsHalContexthubUtils",
+    srcs: [
+        "VtsHalContexthubUtils.cpp",
+    ],
+    export_include_dirs: ["."],
+    shared_libs: [
+        "android.hardware.contexthub@1.0",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/contexthub/common/vts/ContexthubCallbackBase.h b/contexthub/common/vts/ContexthubCallbackBase.h
new file mode 100644
index 0000000..124a116
--- /dev/null
+++ b/contexthub/common/vts/ContexthubCallbackBase.h
@@ -0,0 +1,63 @@
+/*
+ * 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 <android/hardware/contexthub/1.0/IContexthubCallback.h>
+#include <log/log.h>
+
+#include <cinttypes>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace vts_utils {
+
+// Base callback implementation that just logs all callbacks by default, but
+// records a failure if
+class ContexthubCallbackBase : public V1_0::IContexthubCallback {
+  public:
+    virtual Return<void> handleClientMsg(const V1_0::ContextHubMsg& /*msg*/) override {
+        ALOGD("Got client message callback");
+        return Void();
+    }
+
+    virtual Return<void> handleTxnResult(uint32_t txnId, V1_0::TransactionResult result) override {
+        ALOGD("Got transaction result callback for txnId %" PRIu32 " with result %" PRId32, txnId,
+              result);
+        return Void();
+    }
+
+    virtual Return<void> handleHubEvent(V1_0::AsyncEventType evt) override {
+        ALOGD("Got hub event callback for event type %" PRIu32, evt);
+        return Void();
+    }
+
+    virtual Return<void> handleAppAbort(uint64_t appId, uint32_t abortCode) override {
+        ALOGD("Got app abort notification for appId 0x%" PRIx64 " with abort code 0x%" PRIx32,
+              appId, abortCode);
+        return Void();
+    }
+
+    virtual Return<void> handleAppsInfo(const hidl_vec<V1_0::HubAppInfo>& /*appInfo*/) override {
+        ALOGD("Got app info callback");
+        return Void();
+    }
+};
+
+}  // namespace vts_utils
+}  // namespace contexthub
+}  // namespace hardware
+}  // namespace android
diff --git a/contexthub/common/vts/ContexthubHidlTestBase.h b/contexthub/common/vts/ContexthubHidlTestBase.h
new file mode 100644
index 0000000..ee5b7d3
--- /dev/null
+++ b/contexthub/common/vts/ContexthubHidlTestBase.h
@@ -0,0 +1,53 @@
+/*
+ * 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 <android/hardware/contexthub/1.0/IContexthubCallback.h>
+#include <gtest/gtest.h>
+
+#include <string>
+#include <tuple>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace vts_utils {
+
+// Base fixture for Context Hub HAL tests. Parameterized by service name and hub ID.
+template <class IContexthubVersion>
+class ContexthubHidlTestBase
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+  public:
+    virtual void SetUp() override { fetchHubApi(); }
+
+    void fetchHubApi() {
+        hubApi = IContexthubVersion::getService(std::get<0>(GetParam()));
+        ASSERT_NE(hubApi, nullptr);
+    }
+
+    uint32_t getHubId() { return std::stoi(std::get<1>(GetParam())); }
+
+    V1_0::Result registerCallback(sp<V1_0::IContexthubCallback> cb) {
+        return hubApi->registerCallback(getHubId(), cb);
+    }
+
+    sp<IContexthubVersion> hubApi;
+};
+
+}  // namespace vts_utils
+}  // namespace contexthub
+}  // namespace hardware
+}  // namespace android
diff --git a/contexthub/common/vts/OWNERS b/contexthub/common/vts/OWNERS
new file mode 100644
index 0000000..161b2f0
--- /dev/null
+++ b/contexthub/common/vts/OWNERS
@@ -0,0 +1,8 @@
+#Context Hub team
+arthuri@google.com
+bduddie@google.com
+stange@google.com
+
+#VTS team
+dshi@google.com
+trong@google.com
diff --git a/contexthub/common/vts/VtsHalContexthubUtils.cpp b/contexthub/common/vts/VtsHalContexthubUtils.cpp
new file mode 100644
index 0000000..5033b41
--- /dev/null
+++ b/contexthub/common/vts/VtsHalContexthubUtils.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 "VtsHalContexthubUtils.h"
+
+#include <chrono>
+#include <future>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace vts_utils {
+
+using ::android::hardware::contexthub::V1_0::ContextHub;
+using ::android::hardware::contexthub::V1_0::IContexthub;
+
+// Synchronously queries IContexthub::getHubs() and returns the result
+hidl_vec<ContextHub> getHubsSync(IContexthub* hubApi) {
+    hidl_vec<ContextHub> hubList;
+    std::promise<void> barrier;
+
+    hubApi->getHubs([&hubList, &barrier](const hidl_vec<ContextHub>& hubs) {
+        hubList = hubs;
+        barrier.set_value();
+    });
+    barrier.get_future().wait_for(std::chrono::seconds(1));
+
+    return hubList;
+}
+
+}  // namespace vts_utils
+}  // namespace contexthub
+}  // namespace hardware
+}  // namespace android
diff --git a/contexthub/common/vts/VtsHalContexthubUtils.h b/contexthub/common/vts/VtsHalContexthubUtils.h
new file mode 100644
index 0000000..8f9b694
--- /dev/null
+++ b/contexthub/common/vts/VtsHalContexthubUtils.h
@@ -0,0 +1,70 @@
+/*
+ * 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 <android/hardware/contexthub/1.0/IContexthub.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <utils/StrongPointer.h>
+
+#include <chrono>
+#include <future>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace vts_utils {
+
+#define ASSERT_OK(result) ASSERT_EQ(result, ::android::hardware::contexthub::V1_0::Result::OK)
+#define EXPECT_OK(result) EXPECT_EQ(result, ::android::hardware::contexthub::V1_0::Result::OK)
+
+// Helper that does explicit conversion of an enum class to its underlying/base
+// type. Useful for stream output of enum values.
+template <typename EnumType>
+inline constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
+    return static_cast<typename std::underlying_type<EnumType>::type>(value);
+}
+
+// Synchronously queries IContexthub::getHubs() and returns the result
+hidl_vec<V1_0::ContextHub> getHubsSync(V1_0::IContexthub* hubApi);
+
+// Create a vector of tuples that include each IContexthub service paired with each hub ID it
+// exposes via getHubs(). Each tuple represents a test target that we should run the VTS suite
+// against.
+template <class IContexthubVersion>
+static std::vector<std::tuple<std::string, std::string>> getHalAndHubIdList() {
+    std::vector<std::tuple<std::string, std::string>> parameters;
+    std::vector<std::string> serviceNames =
+            ::android::hardware::getAllHalInstanceNames(IContexthubVersion::descriptor);
+    for (const std::string& serviceName : serviceNames) {
+        sp<IContexthubVersion> hubApi = IContexthubVersion::getService(serviceName);
+        if (hubApi != nullptr) {
+            hidl_vec<V1_0::ContextHub> hubs = getHubsSync(hubApi.get());
+            for (const V1_0::ContextHub& hub : hubs) {
+                parameters.push_back(std::make_tuple(serviceName, std::to_string(hub.hubId)));
+            }
+        }
+    }
+
+    return parameters;
+}
+
+}  // namespace vts_utils
+}  // namespace contexthub
+}  // namespace hardware
+}  // namespace android
diff --git a/current.txt b/current.txt
index 75975f2..09fdd69 100644
--- a/current.txt
+++ b/current.txt
@@ -588,6 +588,7 @@
 cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
 a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types
 9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback
+af334f1fc85c62b343f84b74d0495eed6f495f7fecedb53463db10c202310058 android.hardware.gnss.measurement_corrections@1.0::types
 bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider
 2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback
 b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
@@ -596,21 +597,23 @@
 5f6d3097ba84cb63c430787123f4de1b31c11f90b531b98eae9a8623a5ae962a android.hardware.neuralnetworks@1.1::types
 fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice
 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel
-7f7ef383268c95a1b8fe4e55c662bc806bb0ac11a154f6b049a113a44b0f024f android.hardware.neuralnetworks@1.2::types
+00649d29680f2c47edf60000c3ae7ae906ba638f0616947147e3676a83cf36fa android.hardware.neuralnetworks@1.2::types
 a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types
 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
 fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
+ff5dd821c2c7a9c78607159c4d788960b725487263c49d956ca5fa3d37008b45 android.hardware.wifi@1.2::IWifiStaIface
+5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface
 
 # HALs released in Android R
 e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types
-dd3e9280be60a5e042331c1046d13938e2cc323dc4b267cc74d544bf62fc0314 android.hardware.audio@6.0::IDevice
+7241bd4596a927cd46d4b82f5e29e2cbe57f194aa1b25555f1d1d352e8b15c61 android.hardware.audio@6.0::IDevice
 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory
 bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice
 fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream
 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn
 78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut
 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback
-43a3303378f5b9852c2da9ac2c1d440965aab7ba02a800229e7b3c84e2167e06 android.hardware.audio.common@6.0::types
+167ed5cfb7d91db2e2bf20f1320c1a9004eeb768e26f535e0f7db94a21867d21 android.hardware.audio.common@6.0::types
 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect
 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect
@@ -634,57 +637,67 @@
 40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks
 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
+b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice
+daad72a2f482d8a1f660d0e99ac1b78fedb414a4cfbe3fa56b2cd480e5d6f0cb android.hardware.camera.provider@2.6::ICameraProvider
+8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
 c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas
 9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener
 f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService
 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types
+8351cc01eed4c0b4482d9572b5c7ddfd17874d8edb51d6761d348116fc91dd18 android.hardware.contexthub@1.1::IContexthub
+3581d0ba61663cdd45807494dcd697d01c074f27587df9140655f94346969cfe android.hardware.contexthub@1.1::types
 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory
 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory
-881aa8720fb1d69aa9843bfab69d810ab7654a61d2f5ab5e2626cbf240f24eaf android.hardware.dumpstate@1.1::types
-13b33f623521ded51a6c0f7ea5b77e97066d0aa1e38a83c2873f08ad67294f89 android.hardware.dumpstate@1.1::IDumpstateDevice
+d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types
+186bc152ae189ab48f3a761a44ddf5edd0d483073c5b6ca1f802f8b50488b754 android.hardware.dumpstate@1.1::IDumpstateDevice
 769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types
-88371e0edf69a1f72bfc45ecb2335e9b145e87339d3eecc92664a1fb200213ba android.hardware.gnss@2.1::IGnss
-ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback
-ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration
-5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement
-d7bf37660a0946de9599dcbae997b077ee3e604fc2044534d40d3da04297a5d3 android.hardware.gnss@2.1::IGnssMeasurementCallback
+c319e68b03829958404402c2d9c682019678087d60495807c0a7444e0a6af981 android.hardware.gnss@2.1::IGnss
+ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardware.gnss@2.1::IGnssAntennaInfo
+0bc3ed97cbc3f6abc89c68f4e9f4d124f9f723431997dc88c2186cf4d2ad47ee android.hardware.gnss@2.1::IGnssAntennaInfoCallback
+3541d83adfeac16ee3e45d183a58dffe06012ccb5aa5bcd2e4f6eeae269f69cd android.hardware.gnss@2.1::IGnssCallback
+737d750017738f0753d13ba01a3310e0161f294b8ae80b3fd63eaa227e9d9c66 android.hardware.gnss@2.1::IGnssConfiguration
+7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement
+0a16e5913e94d995cfcf959a1c6f10b0b8e9dfdb5f45ac6e7244711ddd740272 android.hardware.gnss@2.1::IGnssMeasurementCallback
 6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections
-a3f439b782a6a92aaf3c0250f3526e94e8bf8844c3d578f0815e21b12c431346 android.hardware.gnss.measurement_corrections@1.1::types
+956c1576ca0d6f11b42980ef59052062836b6763fe973af6cb709da50787f710 android.hardware.gnss.measurement_corrections@1.1::types
 ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
-db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types
+e2f8bc1868fd4a3fd587c172773ea5a8c2f5a3deaf7958394102ca455252b255 android.hardware.health@2.1::types
 0589e410f519e36514e7ece18f283f022df0f70efd2c12821d822f67f74aba98 android.hardware.identity@1.0::types
 bbeee9604128ede83ee755b67e73b5ad29e6e1dbac9ec41fea6ffe2745b0c50a android.hardware.identity@1.0::IIdentityCredential
 96ce8aad80f4c476f25261f790d357c117e79e18474c7dadd850dac704bbe65e android.hardware.identity@1.0::IIdentityCredentialStore
-6e1e28a96c90ba78d47257faea3f3bb4e6360affbbfa5822f0dc31211f9266ff android.hardware.identity@1.0::IWritableIdentityCredential
+8da9c938e58f7d636ddd2f92c646f99d9a9e79612e6441b6380ab12744251873 android.hardware.identity@1.0::IWritableIdentityCredential
 27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice
 adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
 ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types
 df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
 a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer
-d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice
-4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback
-29e26e83399b69c7998b787bd30426dd5baa2da350effca76bbee1ba877355c9 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
-384fd9fd6e4d43ea11d407e52ea81da5242c3c5f4b458b8707d8feb652a13e36 android.hardware.neuralnetworks@1.3::IPreparedModel
-0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-5f1a4e0c29fc686ed476f9f04eed35e4405d21288cb2746b978d6891de5cc37d android.hardware.neuralnetworks@1.3::types
+278817920bfd5292a7713f97f1832cca53de3de640f7670e413d97c6e7fd581c android.hardware.neuralnetworks@1.3::IDevice
+127ba11efb8220dc3aec9a8f441b59eaf1c68d7f03f577833e1824de75a36b17 android.hardware.neuralnetworks@1.3::IExecutionCallback
+6e904be0ddca5ae1de8eba020e6c38ed935ea7d80cd08f47787f137a0ca58555 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
+2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel
+eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
+dd39887aa4fb60ce60ea9cc043edeadbbae6e922d09d3946311b0b410024ae14 android.hardware.neuralnetworks@1.3::types
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
 c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
-11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types
+2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types
 a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
-8aed0a8e03e7a67bfdfb78ad7529a9ae95bea36e6060473b204c89d772522126 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
-def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
-62cf050c593c1ec34b49178b5bdde72dd9b80d9bad3eb184e4f0cd564d28678c android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
+159d48c9efb881f44d5deda8917b89fb4da26837f019446d6d73b73ea5010eca android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
+2ce1f7fb52e49f80b13a9b153d491bce530552f02357ea729acae922a8659f93 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
+77531c8d048f8f8ae532babd0ca86332a865ec9aace1b051226ef2b21123e645 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types
-50e22cd55ad5499e68e81541bbc67bd10e59c1b9f3ff8cc7ba70dcb0d2918381 android.hardware.radio@1.5::types
-8cc3306e8cd755d04521d1611b217b9d13a2a76d2af57cbea8f875333b3363f7 android.hardware.radio@1.5::IRadio
+99f5c26b952271d1246c957e1d0271fa39445ee65cc93aa7c187834f98914a33 android.hardware.radio@1.5::types
+7fefa2cc5b3b3be10b5cff5c5dc195385f491d4bf23ca65f9c6b3c30c8753a33 android.hardware.radio@1.5::IRadio
 e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication
-7b77721a7716e163f5cc5f2830ed5616b953fcf0e5406f69de0fde5ce95e4184 android.hardware.radio@1.5::IRadioResponse
-2fd107f3de1b7e36825e241a88dfae8edf3a77c166cb746f00ddf6440ab78db1 android.hardware.radio.config@1.3::types
+829d3827eeb5a8f563e80fe627419b3231012fc02bc2e79782ec5e9ad9f799a4 android.hardware.radio@1.5::IRadioResponse
+4c4ce691df02faa28c0729e2a033ec464e1d72699be8bcde4dfb141313dbeba8 android.hardware.radio.config@1.3::types
 a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig
 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
 0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse
-51d1c8d285e0456da2a3fdfbf4700c6277165d5e83219894d651c8ea0e39aa8b android.hardware.soundtrigger@2.3::types
-12d7533ff0754f45bf59ab300799074570a99a676545652c2c23abc73cb4515d android.hardware.soundtrigger@2.3::ISoundTriggerHw
+3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors
+3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback
+8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types
+4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types
+b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw
 7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
diff --git a/drm/1.0/default/OWNERS b/drm/1.0/default/OWNERS
new file mode 100644
index 0000000..ecb421c
--- /dev/null
+++ b/drm/1.0/default/OWNERS
@@ -0,0 +1,6 @@
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
diff --git a/drm/1.0/vts/OWNERS b/drm/1.0/vts/OWNERS
new file mode 100644
index 0000000..ecb421c
--- /dev/null
+++ b/drm/1.0/vts/OWNERS
@@ -0,0 +1,6 @@
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp
index 4fbd54d..235bfb4 100644
--- a/drm/1.0/vts/functional/Android.bp
+++ b/drm/1.0/vts/functional/Android.bp
@@ -14,23 +14,75 @@
 // limitations under the License.
 //
 
-cc_test {
-    name: "VtsHalDrmV1_0TargetTest",
+cc_library_static {
+    name: "libdrmvtshelper",
     defaults: ["VtsHalTargetTestDefaults"],
+    local_include_dirs: [
+        "include",
+    ],
     srcs: [
-        "drm_hal_clearkey_test.cpp",
-        "drm_hal_vendor_test.cpp",
         "vendor_modules.cpp",
     ],
     static_libs: [
+       "android.hardware.drm@1.0-helper",
+    ],
+    export_include_dirs: ["include"],
+}
+
+cc_library_static {
+    name: "android.hardware.drm@1.0-vts",
+    defaults: ["VtsHalTargetTestDefaults"],
+    local_include_dirs: [
+        "include",
+    ],
+    srcs: [
+        "drm_hal_clearkey_test.cpp",
+        "drm_hal_vendor_test.cpp",
+    ],
+    shared_libs: [
         "android.hardware.drm@1.0",
-        "android.hardware.drm@1.0-helper",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libhidlmemory",
         "libnativehelper",
-        "libssl",
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0-helper",
         "libcrypto_static",
+        "libdrmvtshelper",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.drm@1.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+        "libnativehelper",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
+
+cc_test {
+    name: "VtsHalDrmV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "drm_hal_test_main.cpp",
+    ],
+    whole_static_libs: [
+        "android.hardware.drm@1.0-vts",
+    ],
+    shared_libs: [
+        "android.hardware.drm@1.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+        "libnativehelper",
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0-helper",
+        "libcrypto_static",
+        "libdrmvtshelper",
     ],
     test_suites: [
         "general-tests",
diff --git a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
index 5713d2e..ebdc2d7 100644
--- a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
@@ -16,127 +16,26 @@
 
 #define LOG_TAG "drm_hal_clearkey_test@1.0"
 
-#include <android/hardware/drm/1.0/ICryptoFactory.h>
-#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.0/IDrmFactory.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.0/types.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/ServiceManagement.h>
-#include <hidlmemory/mapping.h>
-#include <log/log.h>
 #include <openssl/aes.h>
-#include <memory>
 #include <random>
 
-using ::android::hardware::drm::V1_0::BufferType;
-using ::android::hardware::drm::V1_0::DestinationBuffer;
-using ::android::hardware::drm::V1_0::ICryptoFactory;
-using ::android::hardware::drm::V1_0::ICryptoPlugin;
-using ::android::hardware::drm::V1_0::IDrmFactory;
-using ::android::hardware::drm::V1_0::IDrmPlugin;
-using ::android::hardware::drm::V1_0::KeyedVector;
-using ::android::hardware::drm::V1_0::KeyValue;
-using ::android::hardware::drm::V1_0::KeyRequestType;
-using ::android::hardware::drm::V1_0::KeyType;
-using ::android::hardware::drm::V1_0::Mode;
-using ::android::hardware::drm::V1_0::Pattern;
-using ::android::hardware::drm::V1_0::SecureStop;
-using ::android::hardware::drm::V1_0::SecureStopId;
-using ::android::hardware::drm::V1_0::SessionId;
-using ::android::hardware::drm::V1_0::SharedBuffer;
-using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_0::SubSample;
-
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
+#include "android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h"
 
 using std::string;
-using std::unique_ptr;
 using std::random_device;
 using std::map;
 using std::mt19937;
 using std::vector;
 
-/**
- * These clearkey tests use white box knowledge of the legacy clearkey
- * plugin to verify that the HIDL HAL services and interfaces are working.
- * It is not intended to verify any vendor's HAL implementation. If you
- * are looking for vendor HAL tests, see drm_hal_vendor_test.cpp
- */
-#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
-#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
-
-static const uint8_t kCommonPsshBoxUUID[16] = {
-    0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,
-    0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B};
-
-// To be used in mpd to specify drm scheme for players
-static const uint8_t kClearKeyUUID[16] = {
-    0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
-    0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
-
 static const uint8_t kInvalidUUID[16] = {
     0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
     0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
 
-class DrmHalClearkeyFactoryTest : public ::testing::TestWithParam<std::string> {
-  public:
-    void SetUp() override {
-        const ::testing::TestInfo* const test_info =
-                ::testing::UnitTest::GetInstance()->current_test_info();
-        ALOGD("Running test %s.%s", test_info->test_case_name(),
-              test_info->name());
-
-        const std::string instanceName = GetParam();
-        drmFactory = IDrmFactory::getService(instanceName);
-        ASSERT_NE(nullptr, drmFactory.get());
-        cryptoFactory = ICryptoFactory::getService(instanceName);
-        ASSERT_NE(nullptr, cryptoFactory.get());
-
-        const bool drmClearKey = drmFactory->isCryptoSchemeSupported(kClearKeyUUID);
-        const bool cryptoClearKey = cryptoFactory->isCryptoSchemeSupported(kClearKeyUUID);
-        EXPECT_EQ(drmClearKey, cryptoClearKey);
-        const bool supportsClearKey = drmClearKey && cryptoClearKey;
-
-        const bool drmCommonPsshBox = drmFactory->isCryptoSchemeSupported(kCommonPsshBoxUUID);
-        const bool cryptoCommonPsshBox = cryptoFactory->isCryptoSchemeSupported(kCommonPsshBoxUUID);
-        EXPECT_EQ(drmCommonPsshBox, cryptoCommonPsshBox);
-        const bool supportsCommonPsshBox = drmCommonPsshBox && cryptoCommonPsshBox;
-
-        EXPECT_EQ(supportsClearKey, supportsCommonPsshBox);
-        correspondsToThisTest = supportsClearKey && supportsCommonPsshBox;
-
-        if (instanceName == "clearkey") {
-            EXPECT_TRUE(correspondsToThisTest);
-
-            // TODO(b/147449315)
-            // Only the clearkey plugged into the "default" instance supports
-            // this test. Currently the "clearkey" instance fails some tests
-            // here.
-            GTEST_SKIP() << "Clearkey tests don't work with 'clearkey' instance yet.";
-        }
-
-        if (!correspondsToThisTest) {
-            GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
-        }
-    }
-
-   protected:
-    sp<IDrmFactory> drmFactory;
-    sp<ICryptoFactory> cryptoFactory;
-
-    bool correspondsToThisTest;
-};
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace vts {
 
 /**
  * Ensure the factory doesn't support an invalid scheme UUID
@@ -264,48 +163,6 @@
     EXPECT_OK(res);
 }
 
-class DrmHalClearkeyPluginTest : public DrmHalClearkeyFactoryTest {
-   public:
-    virtual void SetUp() override {
-        // Create factories
-        DrmHalClearkeyFactoryTest::SetUp();
-
-        if (!correspondsToThisTest) {
-            GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
-        }
-
-        ASSERT_NE(nullptr, drmFactory.get());
-        hidl_string packageName("android.hardware.drm.test");
-        auto res = drmFactory->createPlugin(
-                kClearKeyUUID, packageName,
-                [this](Status status, const sp<IDrmPlugin>& plugin) {
-                    EXPECT_EQ(Status::OK, status);
-                    ASSERT_NE(nullptr, plugin.get());
-                    drmPlugin = plugin;
-                });
-        ASSERT_OK(res);
-
-        hidl_vec<uint8_t> initVec;
-        res = cryptoFactory->createPlugin(
-                kClearKeyUUID, initVec,
-                [this](Status status, const sp<ICryptoPlugin>& plugin) {
-                    EXPECT_EQ(Status::OK, status);
-                    ASSERT_NE(nullptr, plugin.get());
-                    cryptoPlugin = plugin;
-                });
-        ASSERT_OK(res);
-    }
-
-    SessionId openSession();
-    void closeSession(const SessionId& sessionId);
-    hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
-    sp<IMemory> getDecryptMemory(size_t size, size_t index);
-
-   protected:
-    sp<IDrmPlugin> drmPlugin;
-    sp<ICryptoPlugin> cryptoPlugin;
-};
-
 /**
  *  DrmPlugin tests
  */
@@ -966,30 +823,6 @@
  * Decrypt tests
  */
 
-class DrmHalClearkeyDecryptTest : public DrmHalClearkeyPluginTest {
-   public:
-     void SetUp() override {
-         DrmHalClearkeyPluginTest::SetUp();
-
-         if (!correspondsToThisTest) {
-             GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
-         }
-     }
-    void fillRandom(const sp<IMemory>& memory);
-    hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
-        EXPECT_EQ(16u, vec.size());
-        return hidl_array<uint8_t, 16>(&vec[0]);
-    }
-    uint32_t decrypt(Mode mode, uint8_t* iv, const hidl_vec<SubSample>& subSamples,
-            const Pattern& pattern, Status status);
-    void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
-            const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
-    void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
-            const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
-    void decryptWithInvalidKeys(hidl_vec<uint8_t>& invalidResponse,
-            vector<uint8_t>& iv, const Pattern& noPattern, const vector<SubSample>& subSamples);
-};
-
 void DrmHalClearkeyDecryptTest::fillRandom(const sp<IMemory>& memory) {
     random_device rd;
     mt19937 rand(rd());
@@ -1300,20 +1133,8 @@
     decryptWithInvalidKeys(invalidResponse, iv, noPattern, subSamples);
 }
 
-static const std::set<std::string> kAllInstances = [] {
-    std::vector<std::string> drmInstances =
-            android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
-    std::vector<std::string> cryptoInstances =
-            android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
-    std::set<std::string> allInstances;
-    allInstances.insert(drmInstances.begin(), drmInstances.end());
-    allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
-    return allInstances;
-}();
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyFactoryTest, testing::ValuesIn(kAllInstances),
-                         android::hardware::PrintInstanceNameToString);
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyPluginTest, testing::ValuesIn(kAllInstances),
-                         android::hardware::PrintInstanceNameToString);
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyDecryptTest, testing::ValuesIn(kAllInstances),
-                         android::hardware::PrintInstanceNameToString);
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
diff --git a/drm/1.0/vts/functional/drm_hal_test_main.cpp b/drm/1.0/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000..fd2538b
--- /dev/null
+++ b/drm/1.0/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 "drm_hal_vendor_test@1.0"
+
+#include "vendor_modules.h"
+#include "android/hardware/drm/1.0/vts/drm_hal_vendor_test.h"
+#include "android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h"
+
+using ::android::hardware::drm::V1_0::ICryptoFactory;
+using ::android::hardware::drm::V1_0::IDrmFactory;
+
+using ::android::hardware::drm::V1_0::vts::DrmHalClearkeyFactoryTest;
+using ::android::hardware::drm::V1_0::vts::DrmHalClearkeyPluginTest;
+using ::android::hardware::drm::V1_0::vts::DrmHalClearkeyDecryptTest;
+
+using ::android::hardware::drm::V1_0::vts::DrmHalVendorFactoryTest;
+using ::android::hardware::drm::V1_0::vts::DrmHalVendorPluginTest;
+using ::android::hardware::drm::V1_0::vts::DrmHalVendorDecryptTest;
+
+/**
+ * Instantiate the set of test cases for each vendor module
+ */
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+    std::vector<std::string> drmInstances =
+            android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+    std::vector<std::string> cryptoInstances =
+            android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+    std::set<std::string> allInstances;
+    allInstances.insert(drmInstances.begin(), drmInstances.end());
+    allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+    std::vector<DrmHalTestParam> allInstanceUuidCombos;
+    auto noUUID = [](std::string s) { return DrmHalTestParam(s); };
+    std::transform(allInstances.begin(), allInstances.end(),
+            std::back_inserter(allInstanceUuidCombos), noUUID);
+    return allInstanceUuidCombos;
+}();
+
+INSTANTIATE_TEST_CASE_P(DrmHalVendorFactoryTestCases, DrmHalVendorFactoryTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_CASE_P(DrmHalVendorPluginTestCases, DrmHalVendorPluginTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_CASE_P(DrmHalVendorDecryptTestCases, DrmHalVendorDecryptTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyFactoryTest, testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyPluginTest, testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyDecryptTest, testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
diff --git a/drm/1.0/vts/functional/drm_hal_vendor_module_api.h b/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
new file mode 120000
index 0000000..a8b5ade
--- /dev/null
+++ b/drm/1.0/vts/functional/drm_hal_vendor_module_api.h
@@ -0,0 +1 @@
+include/drm_hal_vendor_module_api.h
\ No newline at end of file
diff --git a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
index 2259985..5c6c98b 100644
--- a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
@@ -16,138 +16,46 @@
 
 #define LOG_TAG "drm_hal_vendor_test@1.0"
 
-#include <android/hardware/drm/1.0/ICryptoFactory.h>
-#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.0/IDrmFactory.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.0/IDrmPluginListener.h>
-#include <android/hardware/drm/1.0/types.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
-#include <hidlmemory/mapping.h>
-#include <log/log.h>
 #include <openssl/aes.h>
-#include <memory>
 #include <random>
 
 #include "drm_hal_vendor_module_api.h"
 #include "vendor_modules.h"
 #include <VtsHalHidlTargetCallbackBase.h>
 
-using ::android::hardware::drm::V1_0::BufferType;
-using ::android::hardware::drm::V1_0::DestinationBuffer;
-using ::android::hardware::drm::V1_0::EventType;
-using ::android::hardware::drm::V1_0::ICryptoFactory;
-using ::android::hardware::drm::V1_0::ICryptoPlugin;
-using ::android::hardware::drm::V1_0::IDrmFactory;
-using ::android::hardware::drm::V1_0::IDrmPlugin;
-using ::android::hardware::drm::V1_0::IDrmPluginListener;
-using ::android::hardware::drm::V1_0::KeyedVector;
-using ::android::hardware::drm::V1_0::KeyRequestType;
-using ::android::hardware::drm::V1_0::KeyStatus;
-using ::android::hardware::drm::V1_0::KeyStatusType;
-using ::android::hardware::drm::V1_0::KeyType;
-using ::android::hardware::drm::V1_0::KeyValue;
-using ::android::hardware::drm::V1_0::Mode;
-using ::android::hardware::drm::V1_0::Pattern;
-using ::android::hardware::drm::V1_0::SecureStop;
-using ::android::hardware::drm::V1_0::SecureStopId;
-using ::android::hardware::drm::V1_0::SessionId;
-using ::android::hardware::drm::V1_0::SharedBuffer;
-using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_0::SubSample;
+#include "android/hardware/drm/1.0/vts/drm_hal_vendor_test.h"
 
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
-using std::string;
-using std::unique_ptr;
 using std::random_device;
-using std::map;
 using std::mt19937;
-using std::vector;
-
-using ContentConfiguration = ::DrmHalVTSVendorModule_V1::ContentConfiguration;
-using Key = ::DrmHalVTSVendorModule_V1::ContentConfiguration::Key;
-
-#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
-#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
-
-#define RETURN_IF_SKIPPED                                                                  \
-    if (vendorModule == nullptr || !vendorModule->isInstalled()) {                         \
-        GTEST_SKIP() << "This drm scheme not supported."                                   \
-                     << " library:" << GetParam() << " service-name:"                      \
-                     << (vendorModule == nullptr ? "N/A" : vendorModule->getServiceName()) \
-                     << std::endl;                                                         \
-        return;                                                                            \
-    }
 
 static const uint8_t kInvalidUUID[16] = {
         0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
         0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
 };
 
-static drm_vts::VendorModules* gVendorModules = nullptr;
-
-class DrmHalVendorFactoryTest : public testing::TestWithParam<std::string> {
-   public:
-     DrmHalVendorFactoryTest()
-         : vendorModule(
-                   static_cast<DrmHalVTSVendorModule_V1*>(gVendorModules->getModule(GetParam()))) {}
-
-     virtual ~DrmHalVendorFactoryTest() {}
-
-     virtual void SetUp() {
-         const ::testing::TestInfo* const test_info =
-                 ::testing::UnitTest::GetInstance()->current_test_info();
-         ALOGD("Running test %s.%s from vendor module %s", test_info->test_case_name(),
-               test_info->name(), GetParam().c_str());
-
-         const std::string instance = GetParam();
-         if (instance == "widevine") {
-             ASSERT_NE(nullptr, vendorModule.get());
-         }
-
-         if (vendorModule == nullptr) {
-             GTEST_SKIP() << "No vendor module available";
-         } else {
-             ASSERT_EQ(instance, vendorModule->getServiceName());
-             contentConfigurations = vendorModule->getContentConfigurations();
-         }
-
-         drmFactory = IDrmFactory::getService(instance);
-         ASSERT_NE(nullptr, drmFactory.get());
-         cryptoFactory = ICryptoFactory::getService(instance);
-         ASSERT_NE(nullptr, cryptoFactory.get());
-
-         // If drm scheme not installed skip subsequent tests
-         if (!drmFactory->isCryptoSchemeSupported(getVendorUUID())) {
-             // no GTEST_SKIP since only some tests require the module
-             vendorModule->setInstalled(false);
-         }
-     }
-
-   protected:
-    hidl_array<uint8_t, 16> getVendorUUID() {
-        if (vendorModule == nullptr) return {};
-        vector<uint8_t> uuid = vendorModule->getUUID();
-        return hidl_array<uint8_t, 16>(&uuid[0]);
+static drm_vts::VendorModules* gVendorModules = [] {
+#if defined(__LP64__)
+    const char* kModulePath = "/data/local/tmp/64/lib";
+#else
+    const char* kModulePath = "/data/local/tmp/32/lib";
+#endif
+    auto modules = new drm_vts::VendorModules(kModulePath);
+    if (modules->getPathList().size() == 0) {
+        std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
+                ", all vendor tests will be skipped" << std::endl;
     }
+    return modules;
+}();
 
-    sp<IDrmFactory> drmFactory;
-    sp<ICryptoFactory> cryptoFactory;
-    unique_ptr<DrmHalVTSVendorModule_V1> vendorModule;
-    vector<ContentConfiguration> contentConfigurations;
-};
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace vts {
+
+DrmHalVendorFactoryTest::DrmHalVendorFactoryTest()
+     : vendorModule(static_cast<DrmHalVTSVendorModule_V1*>(
+             gVendorModules->getModuleByName(GetParam().instance_))) {} // getModuleByName
 
 TEST_P(DrmHalVendorFactoryTest, ValidateConfigurations) {
     const char* kVendorStr = "Vendor module ";
@@ -195,8 +103,8 @@
  */
 TEST_P(DrmHalVendorFactoryTest, PluginConfigUUIDSupported) {
     RETURN_IF_SKIPPED;
-    EXPECT_TRUE(drmFactory->isCryptoSchemeSupported(getVendorUUID()));
-    EXPECT_TRUE(cryptoFactory->isCryptoSchemeSupported(getVendorUUID()));
+    EXPECT_TRUE(drmFactory->isCryptoSchemeSupported(getUUID()));
+    EXPECT_TRUE(cryptoFactory->isCryptoSchemeSupported(getUUID()));
 }
 
 /**
@@ -232,7 +140,7 @@
     RETURN_IF_SKIPPED;
     hidl_string packageName("android.hardware.drm.test");
     auto res = drmFactory->createPlugin(
-            getVendorUUID(), packageName,
+            getUUID(), packageName,
             [&](Status status, const sp<IDrmPlugin>& plugin) {
                 EXPECT_EQ(Status::OK, status);
                 EXPECT_NE(nullptr, plugin.get());
@@ -247,7 +155,7 @@
     RETURN_IF_SKIPPED;
     hidl_vec<uint8_t> initVec;
     auto res = cryptoFactory->createPlugin(
-            getVendorUUID(), initVec,
+            getUUID(), initVec,
             [&](Status status, const sp<ICryptoPlugin>& plugin) {
                 EXPECT_EQ(Status::OK, status);
                 EXPECT_NE(nullptr, plugin.get());
@@ -285,50 +193,6 @@
     EXPECT_OK(res);
 }
 
-class DrmHalVendorPluginTest : public DrmHalVendorFactoryTest {
-   public:
-    virtual ~DrmHalVendorPluginTest() {}
-    virtual void SetUp() override {
-        // Create factories
-        DrmHalVendorFactoryTest::SetUp();
-        RETURN_IF_SKIPPED;
-
-        hidl_string packageName("android.hardware.drm.test");
-        auto res = drmFactory->createPlugin(
-                getVendorUUID(), packageName,
-                [this](Status status, const sp<IDrmPlugin>& plugin) {
-                    EXPECT_EQ(Status::OK, status);
-                    ASSERT_NE(nullptr, plugin.get());
-                    drmPlugin = plugin;
-                });
-        ASSERT_OK(res);
-
-        hidl_vec<uint8_t> initVec;
-        res = cryptoFactory->createPlugin(
-                getVendorUUID(), initVec,
-                [this](Status status, const sp<ICryptoPlugin>& plugin) {
-                    EXPECT_EQ(Status::OK, status);
-                    ASSERT_NE(nullptr, plugin.get());
-                    cryptoPlugin = plugin;
-                });
-        ASSERT_OK(res);
-    }
-
-    virtual void TearDown() override {}
-
-    SessionId openSession();
-    void closeSession(const SessionId& sessionId);
-    sp<IMemory> getDecryptMemory(size_t size, size_t index);
-    KeyedVector toHidlKeyedVector(const map<string, string>& params);
-    hidl_vec<uint8_t> loadKeys(const SessionId& sessionId,
-                               const ContentConfiguration& configuration,
-                               const KeyType& type);
-
-   protected:
-    sp<IDrmPlugin> drmPlugin;
-    sp<ICryptoPlugin> cryptoPlugin;
-};
-
 /**
  *  DrmPlugin tests
  */
@@ -1193,7 +1057,7 @@
 
     EXPECT_OK(res);
 
-    sp<IMemory> mappedMemory = mapMemory(hidlMemory);
+    sp<IMemory> mappedMemory = android::hardware::mapMemory(hidlMemory);
     EXPECT_NE(nullptr, mappedMemory.get());
     res = cryptoPlugin->setSharedBufferBase(hidlMemory, index);
     EXPECT_OK(res);
@@ -1237,29 +1101,6 @@
  * Decrypt tests
  */
 
-class DrmHalVendorDecryptTest : public DrmHalVendorPluginTest {
-   public:
-    DrmHalVendorDecryptTest() = default;
-    virtual ~DrmHalVendorDecryptTest() {}
-
-   protected:
-    void fillRandom(const sp<IMemory>& memory);
-    hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
-        EXPECT_EQ(vec.size(), 16u);
-        return hidl_array<uint8_t, 16>(&vec[0]);
-    }
-    hidl_vec<KeyValue> queryKeyStatus(SessionId sessionId);
-    void removeKeys(SessionId sessionId);
-    uint32_t decrypt(Mode mode, bool isSecure,
-            const hidl_array<uint8_t, 16>& keyId, uint8_t* iv,
-            const hidl_vec<SubSample>& subSamples, const Pattern& pattern,
-            const vector<uint8_t>& key, Status expectedStatus);
-    void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
-            const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
-    void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
-            const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
-};
-
 void DrmHalVendorDecryptTest::fillRandom(const sp<IMemory>& memory) {
     random_device rd;
     mt19937 rand(rd());
@@ -1566,47 +1407,8 @@
     }
 }
 
-
-/**
- * Instantiate the set of test cases for each vendor module
- */
-
-static const std::set<std::string> kAllInstances = [] {
-    std::vector<std::string> drmInstances =
-            android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
-    std::vector<std::string> cryptoInstances =
-            android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
-    std::set<std::string> allInstances;
-    allInstances.insert(drmInstances.begin(), drmInstances.end());
-    allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
-    return allInstances;
-}();
-
-INSTANTIATE_TEST_CASE_P(DrmHalVendorFactoryTestCases, DrmHalVendorFactoryTest,
-                        testing::ValuesIn(kAllInstances),
-                        android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_CASE_P(DrmHalVendorPluginTestCases, DrmHalVendorPluginTest,
-                        testing::ValuesIn(kAllInstances),
-                        android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_CASE_P(DrmHalVendorDecryptTestCases, DrmHalVendorDecryptTest,
-                        testing::ValuesIn(kAllInstances),
-                        android::hardware::PrintInstanceNameToString);
-
-int main(int argc, char** argv) {
-#if defined(__LP64__)
-    const char* kModulePath = "/data/local/tmp/64/lib";
-#else
-    const char* kModulePath = "/data/local/tmp/32/lib";
-#endif
-    gVendorModules = new drm_vts::VendorModules(kModulePath);
-    if (gVendorModules->getPathList().size() == 0) {
-        std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
-                ", all vendor tests will be skipped" << std::endl;
-    }
-    ::testing::InitGoogleTest(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
diff --git a/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h b/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h
new file mode 100644
index 0000000..ca707b8
--- /dev/null
+++ b/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+#ifndef DRM_HAL_CLEARKEY_TEST_H
+#define DRM_HAL_CLEARKEY_TEST_H
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidlmemory/mapping.h>
+#include <log/log.h>
+
+#include "drm_vts_helper.h"
+
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+using ::drm_vts::DrmHalTestParam;
+using ::drm_vts::PrintParamInstanceToString;
+
+using std::string;
+using std::map;
+using std::vector;
+
+/**
+ * These clearkey tests use white box knowledge of the legacy clearkey
+ * plugin to verify that the HIDL HAL services and interfaces are working.
+ * It is not intended to verify any vendor's HAL implementation. If you
+ * are looking for vendor HAL tests, see drm_hal_vendor_test.cpp
+ */
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace vts {
+
+class DrmHalClearkeyFactoryTest : public ::testing::TestWithParam<DrmHalTestParam> {
+  public:
+    void SetUp() override {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("Running test %s.%s", test_info->test_case_name(),
+              test_info->name());
+
+        const std::string instanceName = GetParam().instance_;
+        drmFactory = IDrmFactory::getService(instanceName);
+        ASSERT_NE(nullptr, drmFactory.get());
+        cryptoFactory = ICryptoFactory::getService(instanceName);
+        ASSERT_NE(nullptr, cryptoFactory.get());
+
+        const bool drmClearKey = drmFactory->isCryptoSchemeSupported(kClearKeyUUID);
+        const bool cryptoClearKey = cryptoFactory->isCryptoSchemeSupported(kClearKeyUUID);
+        EXPECT_EQ(drmClearKey, cryptoClearKey);
+        const bool supportsClearKey = drmClearKey && cryptoClearKey;
+
+        const bool drmCommonPsshBox = drmFactory->isCryptoSchemeSupported(kCommonPsshBoxUUID);
+        const bool cryptoCommonPsshBox = cryptoFactory->isCryptoSchemeSupported(kCommonPsshBoxUUID);
+        EXPECT_EQ(drmCommonPsshBox, cryptoCommonPsshBox);
+        const bool supportsCommonPsshBox = drmCommonPsshBox && cryptoCommonPsshBox;
+
+        EXPECT_EQ(supportsClearKey, supportsCommonPsshBox);
+        correspondsToThisTest = supportsClearKey && supportsCommonPsshBox;
+
+        if (instanceName == "clearkey") {
+            EXPECT_TRUE(correspondsToThisTest);
+
+            // TODO(b/147449315)
+            // Only the clearkey plugged into the "default" instance supports
+            // this test. Currently the "clearkey" instance fails some tests
+            // here.
+            GTEST_SKIP() << "Clearkey tests don't work with 'clearkey' instance yet.";
+        }
+
+        if (!correspondsToThisTest) {
+            GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
+        }
+    }
+
+   protected:
+    static constexpr uint8_t kCommonPsshBoxUUID[16] = {
+        0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,
+        0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B};
+
+    // To be used in mpd to specify drm scheme for players
+    static constexpr uint8_t kClearKeyUUID[16] = {
+        0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
+        0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
+
+    sp<IDrmFactory> drmFactory;
+    sp<ICryptoFactory> cryptoFactory;
+
+    bool correspondsToThisTest;
+};
+
+class DrmHalClearkeyPluginTest : public DrmHalClearkeyFactoryTest {
+   public:
+    virtual void SetUp() override {
+        // Create factories
+        DrmHalClearkeyFactoryTest::SetUp();
+
+        if (!correspondsToThisTest) {
+            GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
+        }
+
+        ASSERT_NE(nullptr, drmFactory.get());
+        hidl_string packageName("android.hardware.drm.test");
+        auto res = drmFactory->createPlugin(
+                getUUID(), packageName,
+                [this](Status status, const sp<IDrmPlugin>& plugin) {
+                    EXPECT_EQ(Status::OK, status);
+                    ASSERT_NE(nullptr, plugin.get());
+                    drmPlugin = plugin;
+                });
+        ASSERT_OK(res);
+
+        hidl_vec<uint8_t> initVec;
+        res = cryptoFactory->createPlugin(
+                getUUID(), initVec,
+                [this](Status status, const sp<ICryptoPlugin>& plugin) {
+                    EXPECT_EQ(Status::OK, status);
+                    ASSERT_NE(nullptr, plugin.get());
+                    cryptoPlugin = plugin;
+                });
+        ASSERT_OK(res);
+    }
+
+    SessionId openSession();
+    void closeSession(const SessionId& sessionId);
+    hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
+    sp<IMemory> getDecryptMemory(size_t size, size_t index);
+
+   protected:
+    hidl_array<uint8_t, 16> getUUID() {
+        if (GetParamUUID() == hidl_array<uint8_t, 16>()) {
+            return kClearKeyUUID;
+        }
+        return GetParamUUID();
+    }
+
+    hidl_array<uint8_t, 16> GetParamUUID() {
+        return GetParam().scheme_;
+    }
+
+    sp<IDrmPlugin> drmPlugin;
+    sp<ICryptoPlugin> cryptoPlugin;
+};
+
+class DrmHalClearkeyDecryptTest : public DrmHalClearkeyPluginTest {
+   public:
+     void SetUp() override {
+         DrmHalClearkeyPluginTest::SetUp();
+
+         if (!correspondsToThisTest) {
+             GTEST_SKIP() << "Cannot test clearkey features on non-clearkey DRM modules";
+         }
+     }
+    void fillRandom(const sp<IMemory>& memory);
+    hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
+        EXPECT_EQ(16u, vec.size());
+        return hidl_array<uint8_t, 16>(&vec[0]);
+    }
+    uint32_t decrypt(Mode mode, uint8_t* iv, const hidl_vec<SubSample>& subSamples,
+            const Pattern& pattern, Status status);
+    void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+            const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
+    void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+            const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
+    void decryptWithInvalidKeys(hidl_vec<uint8_t>& invalidResponse,
+            vector<uint8_t>& iv, const Pattern& noPattern, const vector<SubSample>& subSamples);
+};
+
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
+
+#endif  // DRM_HAL_CLEARKEY_TEST_H
diff --git a/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_vendor_test.h b/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_vendor_test.h
new file mode 100644
index 0000000..468d335
--- /dev/null
+++ b/drm/1.0/vts/functional/include/android/hardware/drm/1.0/vts/drm_hal_vendor_test.h
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+#ifndef DRM_HAL_VENDOR_TEST_H
+#define DRM_HAL_VENDOR_TEST_H
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/IDrmPluginListener.h>
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidlmemory/mapping.h>
+#include <log/log.h>
+
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "drm_hal_vendor_module_api.h"
+#include "drm_vts_helper.h"
+#include "vendor_modules.h"
+#include <VtsHalHidlTargetCallbackBase.h>
+
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+using ::drm_vts::DrmHalTestParam;
+using ::drm_vts::PrintParamInstanceToString;
+
+using std::string;
+using std::unique_ptr;
+using std::map;
+using std::vector;
+
+using ContentConfiguration = ::DrmHalVTSVendorModule_V1::ContentConfiguration;
+using Key = ::DrmHalVTSVendorModule_V1::ContentConfiguration::Key;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+#define RETURN_IF_SKIPPED                                                                  \
+    if (vendorModule == nullptr || !vendorModule->isInstalled()) {                         \
+        GTEST_SKIP() << "This drm scheme not supported."                                   \
+                     << " library:" << GetParam() << " service-name:"                      \
+                     << (vendorModule == nullptr ? "N/A" : vendorModule->getServiceName()) \
+                     << std::endl;                                                         \
+        return;                                                                            \
+    }
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_0 {
+namespace vts {
+
+class DrmHalVendorFactoryTest : public testing::TestWithParam<DrmHalTestParam> {
+   public:
+     DrmHalVendorFactoryTest();
+     virtual ~DrmHalVendorFactoryTest() {}
+
+     virtual void SetUp() {
+         const ::testing::TestInfo* const test_info =
+                 ::testing::UnitTest::GetInstance()->current_test_info();
+         ALOGD("Running test %s.%s from vendor module %s", test_info->test_case_name(),
+               test_info->name(), GetParam().instance_.c_str());
+
+         const std::string instance = GetParam().instance_;
+         if (instance == "widevine") {
+             ASSERT_NE(nullptr, vendorModule.get());
+         }
+
+         if (vendorModule == nullptr) {
+             GTEST_SKIP() << "No vendor module available";
+         } else {
+             ASSERT_EQ(instance, vendorModule->getServiceName());
+             contentConfigurations = vendorModule->getContentConfigurations();
+         }
+
+         drmFactory = IDrmFactory::getService(instance);
+         ASSERT_NE(nullptr, drmFactory.get());
+         cryptoFactory = ICryptoFactory::getService(instance);
+         ASSERT_NE(nullptr, cryptoFactory.get());
+
+         // If drm scheme not installed skip subsequent tests
+         if (!drmFactory->isCryptoSchemeSupported(getUUID())) {
+             // no GTEST_SKIP since only some tests require the module
+             vendorModule->setInstalled(false);
+             hidl_array<uint8_t, 16> noUUID;
+             ASSERT_EQ(GetParamUUID(), noUUID) << "param uuid unsupported";
+         }
+     }
+
+   protected:
+    hidl_array<uint8_t, 16> getUUID() {
+        if (GetParamUUID() == hidl_array<uint8_t, 16>()) {
+            return getVendorUUID();
+        }
+        return GetParamUUID();
+    }
+
+    hidl_array<uint8_t, 16> getVendorUUID() {
+        if (vendorModule == nullptr) return {};
+        vector<uint8_t> uuid = vendorModule->getUUID();
+        return hidl_array<uint8_t, 16>(&uuid[0]);
+    }
+
+    hidl_array<uint8_t, 16> GetParamUUID() {
+        return GetParam().scheme_;
+    }
+
+    sp<IDrmFactory> drmFactory;
+    sp<ICryptoFactory> cryptoFactory;
+    unique_ptr<DrmHalVTSVendorModule_V1> vendorModule;
+    vector<ContentConfiguration> contentConfigurations;
+};
+
+class DrmHalVendorPluginTest : public DrmHalVendorFactoryTest {
+   public:
+    virtual ~DrmHalVendorPluginTest() {}
+    virtual void SetUp() override {
+        // Create factories
+        DrmHalVendorFactoryTest::SetUp();
+        RETURN_IF_SKIPPED;
+
+        hidl_string packageName("android.hardware.drm.test");
+        auto res = drmFactory->createPlugin(
+                getVendorUUID(), packageName,
+                [this](Status status, const sp<IDrmPlugin>& plugin) {
+                    EXPECT_EQ(Status::OK, status);
+                    ASSERT_NE(nullptr, plugin.get());
+                    drmPlugin = plugin;
+                });
+        ASSERT_OK(res);
+
+        hidl_vec<uint8_t> initVec;
+        res = cryptoFactory->createPlugin(
+                getVendorUUID(), initVec,
+                [this](Status status, const sp<ICryptoPlugin>& plugin) {
+                    EXPECT_EQ(Status::OK, status);
+                    ASSERT_NE(nullptr, plugin.get());
+                    cryptoPlugin = plugin;
+                });
+        ASSERT_OK(res);
+    }
+
+    virtual void TearDown() override {}
+
+    SessionId openSession();
+    void closeSession(const SessionId& sessionId);
+    sp<IMemory> getDecryptMemory(size_t size, size_t index);
+    KeyedVector toHidlKeyedVector(const map<string, string>& params);
+    hidl_vec<uint8_t> loadKeys(const SessionId& sessionId,
+                               const ContentConfiguration& configuration,
+                               const KeyType& type);
+
+   protected:
+    sp<IDrmPlugin> drmPlugin;
+    sp<ICryptoPlugin> cryptoPlugin;
+};
+
+class DrmHalVendorDecryptTest : public DrmHalVendorPluginTest {
+   public:
+    DrmHalVendorDecryptTest() = default;
+    virtual ~DrmHalVendorDecryptTest() {}
+
+   protected:
+    void fillRandom(const sp<IMemory>& memory);
+    hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
+        EXPECT_EQ(vec.size(), 16u);
+        return hidl_array<uint8_t, 16>(&vec[0]);
+    }
+    hidl_vec<KeyValue> queryKeyStatus(SessionId sessionId);
+    void removeKeys(SessionId sessionId);
+    uint32_t decrypt(Mode mode, bool isSecure,
+            const hidl_array<uint8_t, 16>& keyId, uint8_t* iv,
+            const hidl_vec<SubSample>& subSamples, const Pattern& pattern,
+            const vector<uint8_t>& key, Status expectedStatus);
+    void aes_ctr_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+            const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
+    void aes_cbc_decrypt(uint8_t* dest, uint8_t* src, uint8_t* iv,
+            const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
+};
+
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
+
+#endif  // DRM_HAL_VENDOR_TEST_H
diff --git a/drm/1.0/vts/functional/drm_hal_vendor_module_api.h b/drm/1.0/vts/functional/include/drm_hal_vendor_module_api.h
similarity index 100%
rename from drm/1.0/vts/functional/drm_hal_vendor_module_api.h
rename to drm/1.0/vts/functional/include/drm_hal_vendor_module_api.h
diff --git a/drm/1.0/vts/functional/include/drm_vts_helper.h b/drm/1.0/vts/functional/include/drm_vts_helper.h
new file mode 100644
index 0000000..1f02af9
--- /dev/null
+++ b/drm/1.0/vts/functional/include/drm_vts_helper.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef DRM_VTS_HELPER_H
+#define DRM_VTS_HELPER_H
+
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+
+#include <array>
+#include <chrono>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace drm_vts {
+
+using ::android::hardware::hidl_array;
+
+struct DrmHalTestParam {
+    const std::string instance_;
+    const hidl_array<uint8_t, 16> scheme_{};
+    DrmHalTestParam(const std::string& instance) : instance_(instance) {}
+    DrmHalTestParam(const std::string& instance, const hidl_array<uint8_t, 16>& scheme)
+        : instance_(instance), scheme_(scheme) {}
+};
+
+inline std::ostream& operator<<(std::ostream& stream, const DrmHalTestParam& val) {
+      stream << val.instance_ << ", " << android::hardware::toString(val.scheme_);
+      return stream;
+}
+
+inline std::string PrintParamInstanceToString(
+        const testing::TestParamInfo<DrmHalTestParam>& info) {
+    // test names need to be unique -> index prefix
+    std::string name = std::to_string(info.index) + "/" + info.param.instance_;
+    return android::hardware::Sanitize(name);
+};
+
+}  // namespace drm_vts
+
+#endif  // DRM_VTS_HELPER_H
diff --git a/drm/1.2/vts/functional/vendor_modules.h b/drm/1.0/vts/functional/include/vendor_modules.h
similarity index 97%
rename from drm/1.2/vts/functional/vendor_modules.h
rename to drm/1.0/vts/functional/include/vendor_modules.h
index eacd2d1..3f6fa15 100644
--- a/drm/1.2/vts/functional/vendor_modules.h
+++ b/drm/1.0/vts/functional/include/vendor_modules.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -47,15 +47,15 @@
     DrmHalVTSVendorModule* getModule(const std::string& path);
 
     /**
-     * Retrieve a DrmHalVTSVendorModule given a service name.
-     */
-    DrmHalVTSVendorModule* getModuleByName(const std::string& name);
-
-    /**
      * Return the list of paths to available vendor modules.
      */
     std::vector<std::string> getPathList() const {return mPathList;}
 
+    /**
+     * Retrieve a DrmHalVTSVendorModule given a service name.
+     */
+    DrmHalVTSVendorModule* getModuleByName(const std::string& name);
+
    private:
     std::vector<std::string> mPathList;
     std::map<std::string, std::unique_ptr<SharedLibrary>> mOpenLibraries;
diff --git a/drm/1.0/vts/functional/vendor_modules.cpp b/drm/1.0/vts/functional/vendor_modules.cpp
index 98430f5..53927bd 100644
--- a/drm/1.0/vts/functional/vendor_modules.cpp
+++ b/drm/1.0/vts/functional/vendor_modules.cpp
@@ -23,6 +23,7 @@
 #include <utils/String8.h>
 #include <SharedLibrary.h>
 
+#include "drm_hal_vendor_module_api.h"
 #include "vendor_modules.h"
 
 using std::string;
@@ -69,4 +70,15 @@
     ModuleFactory moduleFactory = reinterpret_cast<ModuleFactory>(symbol);
     return (*moduleFactory)();
 }
+
+DrmHalVTSVendorModule* VendorModules::getModuleByName(const string& name) {
+    for (const auto &path : mPathList) {
+        auto module = getModule(path);
+        if (module->getServiceName() == name) {
+            return module;
+        }
+
+    }
+    return NULL;
+}
 };
diff --git a/drm/1.0/vts/functional/vendor_modules.h b/drm/1.0/vts/functional/vendor_modules.h
deleted file mode 100644
index 8330b0a..0000000
--- a/drm/1.0/vts/functional/vendor_modules.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VENDOR_MODULES_H
-#define VENDOR_MODULES_H
-
-#include <map>
-#include <vector>
-#include <string>
-
-#include <SharedLibrary.h>
-
-using ::android::hardware::drm::V1_0::helper::SharedLibrary;
-
-class DrmHalVTSVendorModule;
-
-namespace drm_vts {
-class VendorModules {
-   public:
-    /**
-     * Initialize with a file system path where the shared libraries
-     * are to be found.
-     */
-    explicit VendorModules(const std::string& dir) {
-        scanModules(dir);
-    }
-    ~VendorModules() {}
-
-    /**
-     * Retrieve a DrmHalVTSVendorModule given its full path.  The
-     * getAPIVersion method can be used to determine the versioned
-     * subclass type.
-     */
-    DrmHalVTSVendorModule* getModule(const std::string& path);
-
-    /**
-     * Return the list of paths to available vendor modules.
-     */
-    std::vector<std::string> getPathList() const {return mPathList;}
-
-   private:
-    std::vector<std::string> mPathList;
-    std::map<std::string, std::unique_ptr<SharedLibrary>> mOpenLibraries;
-
-    /**
-     * Scan the list of paths to available vendor modules.
-     */
-    void scanModules(const std::string& dir);
-
-    inline bool endsWith(const std::string& str, const std::string& suffix) const {
-        if (suffix.size() > str.size()) return false;
-        return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
-    }
-
-    VendorModules(const VendorModules&) = delete;
-    void operator=(const VendorModules&) = delete;
-};
-};
-
-#endif  // VENDOR_MODULES_H
diff --git a/drm/1.1/vts/OWNERS b/drm/1.1/vts/OWNERS
new file mode 100644
index 0000000..ecb421c
--- /dev/null
+++ b/drm/1.1/vts/OWNERS
@@ -0,0 +1,6 @@
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
diff --git a/drm/1.1/vts/functional/Android.bp b/drm/1.1/vts/functional/Android.bp
index fb09563..e08d760 100644
--- a/drm/1.1/vts/functional/Android.bp
+++ b/drm/1.1/vts/functional/Android.bp
@@ -14,21 +14,56 @@
 // limitations under the License.
 //
 
-cc_test {
-    name: "VtsHalDrmV1_1TargetTest",
+cc_library_static {
+    name: "android.hardware.drm@1.1-vts",
     defaults: ["VtsHalTargetTestDefaults"],
+    include_dirs: [
+        "hardware/interfaces/drm/1.0/vts/functional",
+    ],
+    local_include_dirs: [
+        "include",
+    ],
     srcs: [
         "drm_hal_clearkey_test.cpp",
     ],
-    static_libs: [
+    shared_libs: [
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
-        "android.hardware.drm@1.0-helper",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libhidlmemory",
         "libnativehelper",
-        "libssl",
+    ],
+    static_libs: [
+        "libdrmvtshelper",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+        "libnativehelper",
+    ],
+    export_static_lib_headers: [
+        "libdrmvtshelper",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
+
+cc_test {
+    name: "VtsHalDrmV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "drm_hal_test_main.cpp",
+    ],
+    whole_static_libs: [
+        "android.hardware.drm@1.1-vts"
+    ],
+    shared_libs: [
+        "android.hardware.drm@1.1",
     ],
     test_suites: [
         "general-tests",
diff --git a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
index bf99ef6..fba9733 100644
--- a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
@@ -16,205 +16,20 @@
 
 #define LOG_TAG "drm_hal_clearkey_test@1.1"
 
-#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.0/IDrmPlugin.h>
-#include <android/hardware/drm/1.0/types.h>
-#include <android/hardware/drm/1.1/ICryptoFactory.h>
-#include <android/hardware/drm/1.1/IDrmFactory.h>
-#include <android/hardware/drm/1.1/IDrmPlugin.h>
-#include <android/hardware/drm/1.1/types.h>
-#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/ServiceManagement.h>
-#include <hidlmemory/mapping.h>
 #include <log/log.h>
-#include <openssl/aes.h>
-#include <memory>
-#include <random>
+#include <vector>
 
-namespace drm = ::android::hardware::drm;
-using ::android::hardware::drm::V1_0::BufferType;
-using ::android::hardware::drm::V1_0::DestinationBuffer;
-using ::android::hardware::drm::V1_0::ICryptoPlugin;
-using ::android::hardware::drm::V1_0::KeyedVector;
-using ::android::hardware::drm::V1_0::KeyValue;
-using ::android::hardware::drm::V1_0::KeyType;
-using ::android::hardware::drm::V1_0::Mode;
-using ::android::hardware::drm::V1_0::Pattern;
-using ::android::hardware::drm::V1_0::SecureStop;
-using ::android::hardware::drm::V1_0::SecureStopId;
-using ::android::hardware::drm::V1_0::SessionId;
-using ::android::hardware::drm::V1_0::SharedBuffer;
-using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_0::SubSample;
-using ::android::hardware::drm::V1_0::SubSample;
+#include "android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h"
 
-using ::android::hardware::drm::V1_1::DrmMetricGroup;
-using ::android::hardware::drm::V1_1::HdcpLevel;
-using ::android::hardware::drm::V1_1::ICryptoFactory;
-using ::android::hardware::drm::V1_1::IDrmFactory;
-using ::android::hardware::drm::V1_1::IDrmPlugin;
-using ::android::hardware::drm::V1_1::KeyRequestType;
-using ::android::hardware::drm::V1_1::SecureStopRelease;
-using ::android::hardware::drm::V1_1::SecurityLevel;
-using ::android::hardware::drm::V1_1::SecurityLevel;
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace vts {
 
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::sp;
-
-using std::string;
-using std::unique_ptr;
-using std::random_device;
-using std::map;
-using std::mt19937;
-using std::vector;
-
-/**
- * These clearkey tests use white box knowledge of the legacy clearkey
- * plugin to verify that the HIDL HAL services and interfaces are working.
- * It is not intended to verify any vendor's HAL implementation. If you
- * are looking for vendor HAL tests, see drm_hal_vendor_test.cpp
- */
-#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
-#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
-
-// To be used in mpd to specify drm scheme for players
-static const uint8_t kClearKeyUUID[16] = {
+const uint8_t kClearKeyUUID[16] = {
     0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
-    0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
-
-class DrmHalClearkeyTest : public ::testing::TestWithParam<std::string> {
-  public:
-    void SetUp() override {
-        const ::testing::TestInfo* const test_info =
-                ::testing::UnitTest::GetInstance()->current_test_info();
-
-        ALOGD("DrmHalClearkeyTest: Running test %s.%s", test_info->test_case_name(),
-                test_info->name());
-
-        const std::string instance = GetParam();
-
-        sp<IDrmFactory> drmFactory = IDrmFactory::getService(instance);
-        drmPlugin = createDrmPlugin(drmFactory);
-        sp<ICryptoFactory> cryptoFactory = ICryptoFactory::getService(instance);
-        cryptoPlugin = createCryptoPlugin(cryptoFactory);
-
-        if (drmPlugin == nullptr || cryptoPlugin == nullptr) {
-            if (instance == "clearkey") {
-                ASSERT_NE(nullptr, drmPlugin.get()) << "Can't get clearkey drm@1.1 plugin";
-                ASSERT_NE(nullptr, cryptoPlugin.get()) << "Can't get clearkey crypto@1.1 plugin";
-            }
-            GTEST_SKIP() << "Instance does not support clearkey";
-        }
-    }
-
-    SessionId openSession();
-    SessionId openSession(SecurityLevel level);
-    void closeSession(const SessionId& sessionId);
-    hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
-
-  private:
-    sp<IDrmPlugin> createDrmPlugin(sp<IDrmFactory> drmFactory) {
-        if (drmFactory == nullptr) {
-            return nullptr;
-        }
-        sp<IDrmPlugin> plugin = nullptr;
-        auto res = drmFactory->createPlugin(
-                kClearKeyUUID, "", [&](Status status, const sp<drm::V1_0::IDrmPlugin>& pluginV1_0) {
-                    EXPECT_EQ(Status::OK == status, pluginV1_0 != nullptr);
-                    plugin = IDrmPlugin::castFrom(pluginV1_0);
-                });
-
-        if (!res.isOk()) {
-            ALOGE("createDrmPlugin remote call failed");
-        }
-        return plugin;
-    }
-
-    sp<ICryptoPlugin> createCryptoPlugin(sp<ICryptoFactory> cryptoFactory) {
-        if (cryptoFactory == nullptr) {
-            return nullptr;
-        }
-        sp<ICryptoPlugin> plugin = nullptr;
-        hidl_vec<uint8_t> initVec;
-        auto res = cryptoFactory->createPlugin(
-                kClearKeyUUID, initVec,
-                [&](Status status, const sp<drm::V1_0::ICryptoPlugin>& pluginV1_0) {
-                    EXPECT_EQ(Status::OK == status, pluginV1_0 != nullptr);
-                    plugin = pluginV1_0;
-                });
-        if (!res.isOk()) {
-            ALOGE("createCryptoPlugin remote call failed");
-        }
-        return plugin;
-    }
-
-protected:
- template <typename CT>
- bool ValueEquals(DrmMetricGroup::ValueType type, const std::string& expected, const CT& actual) {
-     return type == DrmMetricGroup::ValueType::STRING_TYPE && expected == actual.stringValue;
- }
-
- template <typename CT>
- bool ValueEquals(DrmMetricGroup::ValueType type, const int64_t expected, const CT& actual) {
-     return type == DrmMetricGroup::ValueType::INT64_TYPE && expected == actual.int64Value;
- }
-
- template <typename CT>
- bool ValueEquals(DrmMetricGroup::ValueType type, const double expected, const CT& actual) {
-     return type == DrmMetricGroup::ValueType::DOUBLE_TYPE && expected == actual.doubleValue;
- }
-
- template <typename AT, typename VT>
- bool ValidateMetricAttributeAndValue(const DrmMetricGroup::Metric& metric,
-                                      const std::string& attributeName, const AT& attributeValue,
-                                      const std::string& componentName, const VT& componentValue) {
-     bool validAttribute = false;
-     bool validComponent = false;
-     for (const DrmMetricGroup::Attribute& attribute : metric.attributes) {
-         if (attribute.name == attributeName &&
-             ValueEquals(attribute.type, attributeValue, attribute)) {
-             validAttribute = true;
-         }
-     }
-     for (const DrmMetricGroup::Value& value : metric.values) {
-         if (value.componentName == componentName &&
-             ValueEquals(value.type, componentValue, value)) {
-             validComponent = true;
-         }
-     }
-     return validAttribute && validComponent;
- }
-
- template <typename AT, typename VT>
- bool ValidateMetricAttributeAndValue(const hidl_vec<DrmMetricGroup>& metricGroups,
-                                      const std::string& metricName,
-                                      const std::string& attributeName, const AT& attributeValue,
-                                      const std::string& componentName, const VT& componentValue) {
-     bool foundMetric = false;
-     for (const auto& group : metricGroups) {
-         for (const auto& metric : group.metrics) {
-             if (metric.name == metricName) {
-                 foundMetric = foundMetric || ValidateMetricAttributeAndValue(
-                                                  metric, attributeName, attributeValue,
-                                                  componentName, componentValue);
-             }
-         }
-     }
-     return foundMetric;
- }
-
- sp<IDrmPlugin> drmPlugin;
- sp<ICryptoPlugin> cryptoPlugin;
+    0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E
 };
 
 /**
@@ -812,16 +627,8 @@
     EXPECT_OK(res);
 }
 
-static const std::set<std::string> kAllInstances = [] {
-    std::vector<std::string> drmInstances =
-            android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
-    std::vector<std::string> cryptoInstances =
-            android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
-    std::set<std::string> allInstances;
-    allInstances.insert(drmInstances.begin(), drmInstances.end());
-    allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
-    return allInstances;
-}();
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyTest, testing::ValuesIn(kAllInstances),
-                         android::hardware::PrintInstanceNameToString);
+}  // namespace vts
+}  // namespace V1_1
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
diff --git a/drm/1.1/vts/functional/drm_hal_test_main.cpp b/drm/1.1/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000..c6965bd
--- /dev/null
+++ b/drm/1.1/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h"
+
+using android::hardware::drm::V1_1::ICryptoFactory;
+using android::hardware::drm::V1_1::IDrmFactory;
+using android::hardware::drm::V1_1::vts::DrmHalClearkeyTest;
+using android::hardware::drm::V1_1::vts::kClearKeyUUID;
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+    std::vector<std::string> drmInstances =
+            android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+    std::vector<std::string> cryptoInstances =
+            android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+    std::set<std::string> allInstances;
+    allInstances.insert(drmInstances.begin(), drmInstances.end());
+    allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+    std::vector<DrmHalTestParam> allInstancesWithClearKeyUuid;
+    std::transform(allInstances.begin(), allInstances.end(),
+            std::back_inserter(allInstancesWithClearKeyUuid),
+            [](std::string s) { return DrmHalTestParam(s, kClearKeyUUID); });
+    return allInstancesWithClearKeyUuid;
+}();
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyTest, testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
diff --git a/drm/1.1/vts/functional/include/android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h b/drm/1.1/vts/functional/include/android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h
new file mode 100644
index 0000000..e21a2c1
--- /dev/null
+++ b/drm/1.1/vts/functional/include/android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+#ifndef V1_1_DRM_HAL_CLEARKEY_TEST_H
+#define V1_1_DRM_HAL_CLEARKEY_TEST_H
+
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+#include <android/hardware/drm/1.1/IDrmPlugin.h>
+#include <android/hardware/drm/1.1/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <string>
+
+#include "drm_vts_helper.h"
+
+namespace drm = ::android::hardware::drm;
+
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+using drm_vts::DrmHalTestParam;
+using drm_vts::PrintParamInstanceToString;
+
+/**
+ * These clearkey tests use white box knowledge of the legacy clearkey
+ * plugin to verify that the HIDL HAL services and interfaces are working.
+ * It is not intended to verify any vendor's HAL implementation. If you
+ * are looking for vendor HAL tests, see drm_hal_vendor_test.cpp
+ */
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_1 {
+namespace vts {
+
+using ::android::hardware::drm::V1_0::ICryptoPlugin;
+using ::android::hardware::drm::V1_0::KeyedVector;
+using ::android::hardware::drm::V1_0::KeyType;
+using ::android::hardware::drm::V1_0::Mode;
+using ::android::hardware::drm::V1_0::Pattern;
+using ::android::hardware::drm::V1_0::SecureStop;
+using ::android::hardware::drm::V1_0::SecureStopId;
+using ::android::hardware::drm::V1_0::SessionId;
+using ::android::hardware::drm::V1_0::Status;
+
+// To be used in mpd to specify drm scheme for players
+extern const uint8_t kClearKeyUUID[16];
+
+class DrmHalClearkeyTest : public ::testing::TestWithParam<DrmHalTestParam> {
+  public:
+    void SetUp() override {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+
+        ALOGD("DrmHalClearkeyTest: Running test %s.%s", test_info->test_case_name(),
+                test_info->name());
+
+        const std::string instance = GetParam().instance_;
+
+        sp<IDrmFactory> drmFactory = IDrmFactory::getService(instance);
+        if (!drmFactory->isCryptoSchemeSupported(kClearKeyUUID)) {
+            GTEST_SKIP() << instance << " does not support clearkey";
+        }
+        drmPlugin = createDrmPlugin(drmFactory);
+        sp<ICryptoFactory> cryptoFactory = ICryptoFactory::getService(instance);
+        cryptoPlugin = createCryptoPlugin(cryptoFactory);
+
+        if (drmPlugin == nullptr || cryptoPlugin == nullptr) {
+            if (instance == "clearkey") {
+                ASSERT_NE(nullptr, drmPlugin.get()) << "Can't get clearkey drm@1.1 plugin";
+                ASSERT_NE(nullptr, cryptoPlugin.get()) << "Can't get clearkey crypto@1.1 plugin";
+            }
+            GTEST_SKIP() << "Instance does not support clearkey";
+        }
+    }
+
+    SessionId openSession();
+    SessionId openSession(SecurityLevel level);
+    void closeSession(const SessionId& sessionId);
+    hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
+
+  private:
+    sp<IDrmPlugin> createDrmPlugin(sp<IDrmFactory> drmFactory) {
+        if (drmFactory == nullptr) {
+            return nullptr;
+        }
+        sp<IDrmPlugin> plugin = nullptr;
+        auto res = drmFactory->createPlugin(GetParam().scheme_, "",
+                [&](Status status, const sp<drm::V1_0::IDrmPlugin>& pluginV1_0) {
+                    EXPECT_EQ(Status::OK == status, pluginV1_0 != nullptr);
+                    plugin = IDrmPlugin::castFrom(pluginV1_0);
+                });
+
+        if (!res.isOk()) {
+            ALOGE("createDrmPlugin remote call failed");
+        }
+        return plugin;
+    }
+
+    sp<ICryptoPlugin> createCryptoPlugin(sp<ICryptoFactory> cryptoFactory) {
+        if (cryptoFactory == nullptr) {
+            return nullptr;
+        }
+        sp<ICryptoPlugin> plugin = nullptr;
+        hidl_vec<uint8_t> initVec;
+        auto res = cryptoFactory->createPlugin(
+                GetParam().scheme_, initVec,
+                [&](Status status, const sp<drm::V1_0::ICryptoPlugin>& pluginV1_0) {
+                    EXPECT_EQ(Status::OK == status, pluginV1_0 != nullptr);
+                    plugin = pluginV1_0;
+                });
+        if (!res.isOk()) {
+            ALOGE("createCryptoPlugin remote call failed");
+        }
+        return plugin;
+    }
+
+protected:
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const std::string& expected, const CT& actual) {
+     return type == DrmMetricGroup::ValueType::STRING_TYPE && expected == actual.stringValue;
+ }
+
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const int64_t expected, const CT& actual) {
+     return type == DrmMetricGroup::ValueType::INT64_TYPE && expected == actual.int64Value;
+ }
+
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const double expected, const CT& actual) {
+     return type == DrmMetricGroup::ValueType::DOUBLE_TYPE && expected == actual.doubleValue;
+ }
+
+ template <typename AT, typename VT>
+ bool ValidateMetricAttributeAndValue(const DrmMetricGroup::Metric& metric,
+                                      const std::string& attributeName, const AT& attributeValue,
+                                      const std::string& componentName, const VT& componentValue) {
+     bool validAttribute = false;
+     bool validComponent = false;
+     for (const DrmMetricGroup::Attribute& attribute : metric.attributes) {
+         if (attribute.name == attributeName &&
+             ValueEquals(attribute.type, attributeValue, attribute)) {
+             validAttribute = true;
+         }
+     }
+     for (const DrmMetricGroup::Value& value : metric.values) {
+         if (value.componentName == componentName &&
+             ValueEquals(value.type, componentValue, value)) {
+             validComponent = true;
+         }
+     }
+     return validAttribute && validComponent;
+ }
+
+ template <typename AT, typename VT>
+ bool ValidateMetricAttributeAndValue(const hidl_vec<DrmMetricGroup>& metricGroups,
+                                      const std::string& metricName,
+                                      const std::string& attributeName, const AT& attributeValue,
+                                      const std::string& componentName, const VT& componentValue) {
+     bool foundMetric = false;
+     for (const auto& group : metricGroups) {
+         for (const auto& metric : group.metrics) {
+             if (metric.name == metricName) {
+                 foundMetric = foundMetric || ValidateMetricAttributeAndValue(
+                                                  metric, attributeName, attributeValue,
+                                                  componentName, componentValue);
+             }
+         }
+     }
+     return foundMetric;
+ }
+
+ sp<IDrmPlugin> drmPlugin;
+ sp<ICryptoPlugin> cryptoPlugin;
+};
+
+}  // namespace vts
+}  // namespace V1_1
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
+
+#endif  // V1_1_DRM_HAL_CLEARKEY_TEST_H
diff --git a/drm/1.2/vts/OWNERS b/drm/1.2/vts/OWNERS
new file mode 100644
index 0000000..ecb421c
--- /dev/null
+++ b/drm/1.2/vts/OWNERS
@@ -0,0 +1,6 @@
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
diff --git a/drm/1.2/vts/functional/Android.bp b/drm/1.2/vts/functional/Android.bp
index 83ea104..ecc7d6c 100644
--- a/drm/1.2/vts/functional/Android.bp
+++ b/drm/1.2/vts/functional/Android.bp
@@ -14,27 +14,61 @@
 // limitations under the License.
 //
 
-cc_test {
-    name: "VtsHalDrmV1_2TargetTest",
+cc_library_static {
+    name: "android.hardware.drm@1.2-vts",
     defaults: ["VtsHalTargetTestDefaults"],
-    include_dirs: ["hardware/interfaces/drm/1.0/vts/functional"],
+    local_include_dirs: [
+        "include",
+    ],
     srcs: [
         "drm_hal_clearkey_module.cpp",
         "drm_hal_common.cpp",
         "drm_hal_test.cpp",
-        "vendor_modules.cpp",
     ],
-    static_libs: [
+    shared_libs: [
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
         "android.hardware.drm@1.2",
-        "android.hardware.drm@1.0-helper",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libhidlmemory",
         "libnativehelper",
-        "libssl",
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0-helper",
         "libcrypto_static",
+        "libdrmvtshelper",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.drm@1.2",
+    ],
+    export_static_lib_headers: [
+        "android.hardware.drm@1.0-helper",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
+
+cc_test {
+    name: "VtsHalDrmV1_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "drm_hal_test_main.cpp",
+    ],
+    whole_static_libs: [
+        "android.hardware.drm@1.2-vts",
+    ],
+    shared_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.2",
+        "android.hidl.allocator@1.0",
+        "libhidlmemory",
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0-helper",
+        "libcrypto_static",
+        "libdrmvtshelper",
     ],
     test_suites: [
         "general-tests",
diff --git a/drm/1.2/vts/functional/drm_hal_common.cpp b/drm/1.2/vts/functional/drm_hal_common.cpp
index 8a68608..d5e453c 100644
--- a/drm/1.2/vts/functional/drm_hal_common.cpp
+++ b/drm/1.2/vts/functional/drm_hal_common.cpp
@@ -26,7 +26,7 @@
 #include <random>
 
 #include "drm_hal_clearkey_module.h"
-#include "drm_hal_common.h"
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h"
 
 using ::android::hardware::drm::V1_0::BufferType;
 using ::android::hardware::drm::V1_0::DestinationBuffer;
@@ -94,7 +94,7 @@
  * DrmHalTest
  */
 
-DrmHalTest::DrmHalTest() : vendorModule(getModuleForInstance(GetParam())) {}
+DrmHalTest::DrmHalTest() : vendorModule(getModuleForInstance(GetParamService())) {}
 
 void DrmHalTest::SetUp() {
     const ::testing::TestInfo* const test_info =
@@ -102,9 +102,9 @@
 
     ALOGD("Running test %s.%s from (vendor) module %s",
           test_info->test_case_name(), test_info->name(),
-          GetParam().c_str());
+          GetParamService().c_str());
 
-    const string instance = GetParam();
+    const string instance = GetParamService();
 
     drmFactory = IDrmFactory::getService(instance);
     ASSERT_NE(drmFactory, nullptr);
@@ -124,8 +124,12 @@
     contentConfigurations = vendorModule->getContentConfigurations();
 
     // If drm scheme not installed skip subsequent tests
-    if (!drmFactory->isCryptoSchemeSupported(getVendorUUID())) {
-        GTEST_SKIP() << "vendor module drm scheme not supported";
+    if (!drmFactory->isCryptoSchemeSupported(getUUID())) {
+        if (GetParamUUID() == hidl_array<uint8_t, 16>()) {
+            GTEST_SKIP() << "vendor module drm scheme not supported";
+        } else {
+            FAIL() << "param scheme must be supported: " << android::hardware::toString(GetParamUUID());
+        }
     }
 
     ASSERT_NE(nullptr, drmPlugin.get()) << "Can't find " << vendorModule->getServiceName() <<  " drm@1.2 plugin";
@@ -140,7 +144,7 @@
     sp<IDrmPlugin> plugin = nullptr;
     hidl_string packageName("android.hardware.drm.test");
     auto res =
-            drmFactory->createPlugin(getVendorUUID(), packageName,
+            drmFactory->createPlugin(getUUID(), packageName,
                                      [&](StatusV1_0 status, const sp<IDrmPluginV1_0>& pluginV1_0) {
                                          EXPECT_EQ(StatusV1_0::OK == status, pluginV1_0 != nullptr);
                                          plugin = IDrmPlugin::castFrom(pluginV1_0);
@@ -159,7 +163,7 @@
     sp<ICryptoPlugin> plugin = nullptr;
     hidl_vec<uint8_t> initVec;
     auto res = cryptoFactory->createPlugin(
-            getVendorUUID(), initVec,
+            getUUID(), initVec,
             [&](StatusV1_0 status, const sp<ICryptoPluginV1_0>& pluginV1_0) {
                 EXPECT_EQ(StatusV1_0::OK == status, pluginV1_0 != nullptr);
                 plugin = ICryptoPlugin::castFrom(pluginV1_0);
@@ -170,6 +174,13 @@
     return plugin;
 }
 
+hidl_array<uint8_t, 16> DrmHalTest::getUUID() {
+    if (GetParamUUID() == hidl_array<uint8_t, 16>()) {
+        return getVendorUUID();
+    }
+    return GetParamUUID();
+}
+
 hidl_array<uint8_t, 16> DrmHalTest::getVendorUUID() {
     if (vendorModule == nullptr) return {};
     vector<uint8_t> uuid = vendorModule->getUUID();
@@ -509,7 +520,7 @@
 /**
  * Helper method to test decryption with invalid keys is returned
  */
-void DrmHalClearkeyTest::decryptWithInvalidKeys(
+void DrmHalClearkeyTestV1_2::decryptWithInvalidKeys(
         hidl_vec<uint8_t>& invalidResponse,
         vector<uint8_t>& iv,
         const Pattern& noPattern,
diff --git a/drm/1.2/vts/functional/drm_hal_test.cpp b/drm/1.2/vts/functional/drm_hal_test.cpp
index 71296dc..0dfff26 100644
--- a/drm/1.2/vts/functional/drm_hal_test.cpp
+++ b/drm/1.2/vts/functional/drm_hal_test.cpp
@@ -17,13 +17,13 @@
 #define LOG_TAG "drm_hal_test@1.2"
 
 #include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/ServiceManagement.h>
 #include <log/log.h>
 #include <openssl/aes.h>
+#include <vector>
 
-#include "drm_hal_common.h"
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h"
 
 using ::android::hardware::drm::V1_0::Status;
 using ::android::hardware::drm::V1_1::KeyRequestType;
@@ -34,12 +34,13 @@
 using ::android::hardware::drm::V1_2::KeyStatusType;
 using ::android::hardware::drm::V1_2::OfflineLicenseState;
 
-using ::android::hardware::drm::V1_2::vts::DrmHalClearkeyTest;
+using ::android::hardware::drm::V1_2::vts::DrmHalClearkeyTestV1_2;
 using ::android::hardware::drm::V1_2::vts::DrmHalPluginListener;
 using ::android::hardware::drm::V1_2::vts::DrmHalTest;
 using ::android::hardware::drm::V1_2::vts::kCallbackLostState;
 using ::android::hardware::drm::V1_2::vts::kCallbackKeysChange;
 
+using ::android::hardware::hidl_array;
 using ::android::hardware::hidl_string;
 
 static const char* const kVideoMp4 = "video/mp4";
@@ -54,7 +55,7 @@
  * Ensure drm factory supports module UUID Scheme
  */
 TEST_P(DrmHalTest, VendorUuidSupported) {
-    auto res = drmFactory->isCryptoSchemeSupported_1_2(getVendorUUID(), kVideoMp4, kSwSecureCrypto);
+    auto res = drmFactory->isCryptoSchemeSupported_1_2(getUUID(), kVideoMp4, kSwSecureCrypto);
     ALOGI("kVideoMp4 = %s res %d", kVideoMp4, (bool)res);
     EXPECT_TRUE(res);
 }
@@ -82,7 +83,7 @@
  * Ensure drm factory doesn't support an invalid mime type
  */
 TEST_P(DrmHalTest, BadMimeNotSupported) {
-    EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(getVendorUUID(), kBadMime, kSwSecureCrypto));
+    EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(getUUID(), kBadMime, kSwSecureCrypto));
 }
 
 /**
@@ -398,14 +399,14 @@
 /**
  * Ensure clearkey drm factory doesn't support security level higher than supported
  */
-TEST_P(DrmHalClearkeyTest, BadLevelNotSupported) {
-    EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(getVendorUUID(), kVideoMp4, kHwSecureAll));
+TEST_P(DrmHalClearkeyTestV1_2, BadLevelNotSupported) {
+    EXPECT_FALSE(drmFactory->isCryptoSchemeSupported_1_2(getUUID(), kVideoMp4, kHwSecureAll));
 }
 
 /**
  * Test resource contention during attempt to generate key request
  */
-TEST_P(DrmHalClearkeyTest, GetKeyRequestResourceContention) {
+TEST_P(DrmHalClearkeyTestV1_2, GetKeyRequestResourceContention) {
     Status status = drmPlugin->setPropertyString(kDrmErrorTestKey, kDrmErrorResourceContention);
     EXPECT_EQ(Status::OK, status);
     auto sessionId = openSession();
@@ -426,7 +427,7 @@
 /**
  * Test clearkey plugin offline key with mock error
  */
-TEST_P(DrmHalClearkeyTest, OfflineLicenseInvalidState) {
+TEST_P(DrmHalClearkeyTestV1_2, OfflineLicenseInvalidState) {
     auto sessionId = openSession();
     hidl_vec<uint8_t> keySetId = loadKeys(sessionId, KeyType::OFFLINE);
     Status status = drmPlugin->setPropertyString(kDrmErrorTestKey, kDrmErrorInvalidState);
@@ -447,7 +448,7 @@
 /**
  * Test SessionLostState is triggered on error
  */
-TEST_P(DrmHalClearkeyTest, SessionLostState) {
+TEST_P(DrmHalClearkeyTestV1_2, SessionLostState) {
     sp<DrmHalPluginListener> listener = new DrmHalPluginListener();
     auto res = drmPlugin->setListener(listener);
     EXPECT_OK(res);
@@ -467,7 +468,7 @@
 /**
  * Negative decrypt test. Decrypt with invalid key.
  */
-TEST_P(DrmHalClearkeyTest, DecryptWithEmptyKey) {
+TEST_P(DrmHalClearkeyTestV1_2, DecryptWithEmptyKey) {
     vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
     const Pattern noPattern = {0, 0};
     const uint32_t kClearBytes = 512;
@@ -504,7 +505,7 @@
 /**
  * Negative decrypt test. Decrypt with a key exceeds AES_BLOCK_SIZE.
  */
-TEST_P(DrmHalClearkeyTest, DecryptWithKeyTooLong) {
+TEST_P(DrmHalClearkeyTestV1_2, DecryptWithKeyTooLong) {
     vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
     const Pattern noPattern = {0, 0};
     const uint32_t kClearBytes = 512;
@@ -531,43 +532,3 @@
     memcpy(invalidResponse.data(), keyTooLongResponse.c_str(), kKeyTooLongResponseSize);
     decryptWithInvalidKeys(invalidResponse, iv, noPattern, subSamples);
 }
-
-/**
- * Instantiate the set of test cases for each vendor module
- */
-
-static const std::set<std::string> kAllInstances = [] {
-    using ::android::hardware::drm::V1_2::ICryptoFactory;
-    using ::android::hardware::drm::V1_2::IDrmFactory;
-
-    std::vector<std::string> drmInstances =
-            android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
-    std::vector<std::string> cryptoInstances =
-            android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
-    std::set<std::string> allInstances;
-    allInstances.insert(drmInstances.begin(), drmInstances.end());
-    allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
-    return allInstances;
-}();
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalTest, testing::ValuesIn(kAllInstances),
-                         android::hardware::PrintInstanceNameToString);
-INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyTest, testing::ValuesIn(kAllInstances),
-                         android::hardware::PrintInstanceNameToString);
-
-int main(int argc, char** argv) {
-#if defined(__LP64__)
-    const char* kModulePath = "/data/local/tmp/64/lib";
-#else
-    const char* kModulePath = "/data/local/tmp/32/lib";
-#endif
-    DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath);
-    if (DrmHalTest::gVendorModules->getPathList().size() == 0) {
-        std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
-                ", all vendor tests will be skipped" << std::endl;
-    }
-    ::testing::InitGoogleTest(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
diff --git a/drm/1.2/vts/functional/drm_hal_test_main.cpp b/drm/1.2/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000..ea6e63d
--- /dev/null
+++ b/drm/1.2/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/**
+ * Instantiate the set of test cases for each vendor module
+ */
+
+#define LOG_TAG "drm_hal_test@1.2"
+
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h"
+
+using android::hardware::drm::V1_2::vts::DrmHalTest;
+using android::hardware::drm::V1_2::vts::DrmHalClearkeyTestV1_2;
+using drm_vts::DrmHalTestParam;
+using drm_vts::PrintParamInstanceToString;
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+    using ::android::hardware::drm::V1_2::ICryptoFactory;
+    using ::android::hardware::drm::V1_2::IDrmFactory;
+
+    std::vector<std::string> drmInstances =
+            android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+    std::vector<std::string> cryptoInstances =
+            android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+    std::set<std::string> allInstances;
+    allInstances.insert(drmInstances.begin(), drmInstances.end());
+    allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+    std::vector<DrmHalTestParam> allInstanceUuidCombos;
+    auto noUUID = [](std::string s) { return DrmHalTestParam(s); };
+    std::transform(allInstances.begin(), allInstances.end(),
+            std::back_inserter(allInstanceUuidCombos), noUUID);
+    return allInstanceUuidCombos;
+}();
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalTest, testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstance, DrmHalClearkeyTestV1_2, testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+
+int main(int argc, char** argv) {
+#if defined(__LP64__)
+    const char* kModulePath = "/data/local/tmp/64/lib";
+#else
+    const char* kModulePath = "/data/local/tmp/32/lib";
+#endif
+    DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath);
+    if (DrmHalTest::gVendorModules->getPathList().size() == 0) {
+        std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
+                ", all vendor tests will be skipped" << std::endl;
+    }
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/drm/1.2/vts/functional/drm_hal_common.h b/drm/1.2/vts/functional/include/android/hardware/drm/1.2/vts/drm_hal_common.h
similarity index 92%
rename from drm/1.2/vts/functional/drm_hal_common.h
rename to drm/1.2/vts/functional/include/android/hardware/drm/1.2/vts/drm_hal_common.h
index 6b71aa4..6fee6f4 100644
--- a/drm/1.2/vts/functional/drm_hal_common.h
+++ b/drm/1.2/vts/functional/include/android/hardware/drm/1.2/vts/drm_hal_common.h
@@ -23,14 +23,19 @@
 #include <android/hardware/drm/1.2/IDrmPlugin.h>
 #include <android/hardware/drm/1.2/IDrmPluginListener.h>
 #include <android/hardware/drm/1.2/types.h>
+#include <hidl/HidlSupport.h>
 
+#include <array>
 #include <chrono>
+# include <iostream>
 #include <map>
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "drm_hal_vendor_module_api.h"
+#include "drm_vts_helper.h"
 #include "vendor_modules.h"
 #include "VtsHalHidlTargetCallbackBase.h"
 
@@ -41,13 +46,10 @@
 using ::android::hardware::drm::V1_0::Pattern;
 using ::android::hardware::drm::V1_0::SessionId;
 using ::android::hardware::drm::V1_0::SubSample;
+using ::android::hardware::drm::V1_1::SecurityLevel;
 
 using KeyStatusV1_0 = ::android::hardware::drm::V1_0::KeyStatus;
 using StatusV1_0 = ::android::hardware::drm::V1_0::Status;
-
-using ::android::hardware::drm::V1_1::ICryptoFactory;
-using ::android::hardware::drm::V1_1::SecurityLevel;
-
 using StatusV1_2 = ::android::hardware::drm::V1_2::Status;
 
 using ::android::hardware::hidl_array;
@@ -58,7 +60,11 @@
 using ::android::hidl::memory::V1_0::IMemory;
 using ::android::sp;
 
+using drm_vts::DrmHalTestParam;
+
+using std::array;
 using std::map;
+using std::pair;
 using std::string;
 using std::unique_ptr;
 using std::vector;
@@ -71,7 +77,7 @@
 namespace V1_2 {
 namespace vts {
 
-class DrmHalTest : public ::testing::TestWithParam<std::string> {
+class DrmHalTest : public ::testing::TestWithParam<DrmHalTestParam> {
    public:
     static drm_vts::VendorModules* gVendorModules;
     DrmHalTest();
@@ -79,7 +85,10 @@
     virtual void TearDown() override {}
 
    protected:
+    hidl_array<uint8_t, 16> getUUID();
     hidl_array<uint8_t, 16> getVendorUUID();
+    hidl_array<uint8_t, 16> GetParamUUID() { return GetParam().scheme_; }
+    string GetParamService() { return GetParam().instance_; }
     void provision();
     SessionId openSession(SecurityLevel level, StatusV1_0* err);
     SessionId openSession();
@@ -124,7 +133,7 @@
 
 };
 
-class DrmHalClearkeyTest : public DrmHalTest {
+class DrmHalClearkeyTestV1_2 : public DrmHalTest {
    public:
      virtual void SetUp() override {
          DrmHalTest::SetUp();
@@ -132,7 +141,7 @@
              0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
              0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
          if (!drmFactory->isCryptoSchemeSupported(kClearKeyUUID)) {
-             GTEST_SKIP() << "ClearKey not supported by " << GetParam();
+             GTEST_SKIP() << "ClearKey not supported by " << GetParamService();
          }
      }
     virtual void TearDown() override {}
diff --git a/drm/1.2/vts/functional/vendor_modules.cpp b/drm/1.2/vts/functional/vendor_modules.cpp
deleted file mode 100644
index 08131cf..0000000
--- a/drm/1.2/vts/functional/vendor_modules.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "drm-vts-vendor-modules"
-
-#include <dirent.h>
-#include <dlfcn.h>
-#include <log/log.h>
-#include <memory>
-#include <utils/String8.h>
-#include <SharedLibrary.h>
-
-#include "drm_hal_vendor_module_api.h"
-#include "vendor_modules.h"
-
-using std::string;
-using std::vector;
-using std::unique_ptr;
-using ::android::String8;
-using ::android::hardware::drm::V1_0::helper::SharedLibrary;
-
-namespace drm_vts {
-void VendorModules::scanModules(const std::string &directory) {
-    DIR* dir = opendir(directory.c_str());
-    if (dir == NULL) {
-        ALOGE("Unable to open drm VTS vendor directory %s", directory.c_str());
-    } else {
-        struct dirent* entry;
-        while ((entry = readdir(dir))) {
-            ALOGD("checking file %s", entry->d_name);
-            string fullpath = directory + "/" + entry->d_name;
-            if (endsWith(fullpath, ".so")) {
-                mPathList.push_back(fullpath);
-            }
-        }
-        closedir(dir);
-    }
-}
-
-DrmHalVTSVendorModule* VendorModules::getModule(const string& path) {
-    if (mOpenLibraries.find(path) == mOpenLibraries.end()) {
-        auto library = std::make_unique<SharedLibrary>(String8(path.c_str()));
-        if (!library) {
-            ALOGE("failed to map shared library %s", path.c_str());
-            return NULL;
-        }
-        mOpenLibraries[path] = std::move(library);
-    }
-    const unique_ptr<SharedLibrary>& library = mOpenLibraries[path];
-    void* symbol = library->lookup("vendorModuleFactory");
-    if (symbol == NULL) {
-        ALOGE("getVendorModule failed to lookup 'vendorModuleFactory' in %s: "
-              "%s", path.c_str(), library->lastError());
-        return NULL;
-    }
-    typedef DrmHalVTSVendorModule* (*ModuleFactory)();
-    ModuleFactory moduleFactory = reinterpret_cast<ModuleFactory>(symbol);
-    return (*moduleFactory)();
-}
-
-DrmHalVTSVendorModule* VendorModules::getModuleByName(const string& name) {
-    for (const auto &path : mPathList) {
-        auto module = getModule(path);
-        if (module->getServiceName() == name) {
-            return module;
-        }
-    }
-    return NULL;
-}
-};
diff --git a/drm/1.3/vts/OWNERS b/drm/1.3/vts/OWNERS
new file mode 100644
index 0000000..3a0672e
--- /dev/null
+++ b/drm/1.3/vts/OWNERS
@@ -0,0 +1,9 @@
+conglin@google.com
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+juce@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
+sigquit@google.com
diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..4be1575
--- /dev/null
+++ b/drm/1.3/vts/functional/Android.bp
@@ -0,0 +1,78 @@
+//
+// 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.
+//
+
+cc_library_static {
+    name: "android.hardware.drm@1.3-vts",
+    defaults: ["VtsHalTargetTestDefaults"],
+    local_include_dirs: [
+        "include",
+    ],
+    srcs: [
+        "drm_hal_test.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
+        "android.hardware.drm@1.3",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+        "libnativehelper",
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0-helper",
+        "libcrypto_static",
+        "libdrmvtshelper",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
+
+cc_test {
+    name: "VtsHalDrmV1_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    include_dirs: ["hardware/interfaces/drm/1.0/vts/functional"],
+    srcs: [
+        "drm_hal_test_main.cpp",
+    ],
+    whole_static_libs: [
+        "android.hardware.drm@1.0-vts",
+        "android.hardware.drm@1.1-vts",
+        "android.hardware.drm@1.2-vts",
+        "android.hardware.drm@1.3-vts",
+    ],
+    shared_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
+        "android.hardware.drm@1.3",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+        "libnativehelper",
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0-helper",
+        "libcrypto_static",
+        "libdrmvtshelper",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/drm/1.3/vts/functional/drm_hal_test.cpp b/drm/1.3/vts/functional/drm_hal_test.cpp
new file mode 100644
index 0000000..738f5b2
--- /dev/null
+++ b/drm/1.3/vts/functional/drm_hal_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 "drm_hal_test@1.3"
+
+#include "android/hardware/drm/1.3/vts/drm_hal_test.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_3 {
+namespace vts {
+
+TEST_P(DrmHalTestV1_3, SchemeSupported) {
+    EXPECT_TRUE(drmFactory_->isCryptoSchemeSupported(GetParam().scheme_));
+}
+
+TEST_P(DrmHalTestV1_3, SignRsaNotAllowed) {
+    hidl_array<uint8_t, 16> kWidevineUUID ({
+        0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
+        0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED
+    });
+
+    if (!drmFactory_->isCryptoSchemeSupported(kWidevineUUID)) {
+        GTEST_SKIP() << "Widevine only test";
+    }
+
+    // signRSA
+    const hidl_vec<uint8_t>& sessionId{};
+    const hidl_string& algorithm{};
+    const hidl_vec<uint8_t>& message{};
+    const hidl_vec<uint8_t>& wrappedKey{};
+    auto res = drmPlugin_->signRSA(
+        sessionId, algorithm, message, wrappedKey,
+        [&](StatusV1_0 status, const hidl_vec<uint8_t>& signature) {
+            EXPECT_EQ(status, StatusV1_0::ERROR_DRM_UNKNOWN);
+            EXPECT_EQ(signature.size(), 0);
+        }
+    );
+    EXPECT_TRUE(res.isOk());
+}
+
+}  // namespace vts
+}  // namespace V1_3
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
diff --git a/drm/1.3/vts/functional/drm_hal_test_main.cpp b/drm/1.3/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000..02b45ea
--- /dev/null
+++ b/drm/1.3/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+/**
+ * Instantiate the set of test cases for each vendor module
+ */
+
+#define LOG_TAG "drm_hal_test@1.3"
+
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h" // V1_0 tests
+#include "android/hardware/drm/1.0/vts/drm_hal_vendor_test.h"   // V1_0 tests
+#include "android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h" // V1_1 tests
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h"        // V1_2 tests
+#include "android/hardware/drm/1.3/vts/drm_hal_test.h"          // V1_3 tests
+
+using drm_vts::DrmHalTestParam;
+using drm_vts::PrintParamInstanceToString;
+
+using android::hardware::drm::V1_0::vts::DrmHalVendorFactoryTest;
+using android::hardware::drm::V1_0::vts::DrmHalVendorPluginTest;
+using android::hardware::drm::V1_0::vts::DrmHalVendorDecryptTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyFactoryTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyPluginTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyDecryptTest;
+using android::hardware::drm::V1_1::vts::DrmHalClearkeyTest;
+using android::hardware::drm::V1_2::vts::DrmHalTest;
+using android::hardware::drm::V1_2::vts::DrmHalClearkeyTestV1_2;
+using android::hardware::drm::V1_3::vts::DrmHalTestV1_3;
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+    using ::android::hardware::drm::V1_3::ICryptoFactory;
+    using ::android::hardware::drm::V1_3::IDrmFactory;
+
+    std::vector<std::string> drmInstances =
+            android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+    std::vector<std::string> cryptoInstances =
+            android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+    std::set<std::string> allInstances;
+    allInstances.insert(drmInstances.begin(), drmInstances.end());
+    allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+    std::vector<DrmHalTestParam> allInstanceUuidCombos;
+    for (const auto &instance : allInstances) {
+        auto drmFactory = IDrmFactory::getService(instance);
+        if (drmFactory == nullptr) {
+            continue;
+        }
+        drmFactory->getSupportedCryptoSchemes(
+            [&](const hidl_vec<hidl_array<uint8_t, 16>>& schemes) {
+                for (const auto &scheme : schemes) {
+                    allInstanceUuidCombos.push_back(DrmHalTestParam(instance, scheme));
+                }
+            });
+    }
+    return allInstanceUuidCombos;
+}();
+
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorFactoryTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorPluginTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorDecryptTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyFactoryTest,
+                         testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyPluginTest,
+                         testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyDecryptTest,
+                         testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_1, DrmHalClearkeyTest,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalTest,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalClearkeyTestV1_2,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_3, DrmHalTestV1_3,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+
+int main(int argc, char** argv) {
+#if defined(__LP64__)
+    const char* kModulePath = "/data/local/tmp/64/lib";
+#else
+    const char* kModulePath = "/data/local/tmp/32/lib";
+#endif
+    DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath);
+    if (DrmHalTest::gVendorModules->getPathList().size() == 0) {
+        std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
+                ", all vendor tests will be skipped" << std::endl;
+    }
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h
new file mode 100644
index 0000000..d8f5277
--- /dev/null
+++ b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef DRM_HAL_TEST_V1_3_H
+#define DRM_HAL_TEST_V1_3_H
+
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "drm_hal_vendor_module_api.h"
+#include "drm_vts_helper.h"
+#include "vendor_modules.h"
+#include "VtsHalHidlTargetCallbackBase.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_3 {
+namespace vts {
+
+using android::hardware::hidl_array;
+using android::hardware::hidl_string;
+
+using drm_vts::DrmHalTestParam;
+
+using IDrmFactoryV1_3 = android::hardware::drm::V1_3::IDrmFactory;
+using IDrmPluginV1_0 = android::hardware::drm::V1_0::IDrmPlugin;
+using StatusV1_0 = android::hardware::drm::V1_0::Status;
+
+class DrmHalTestV1_3 : public ::testing::TestWithParam<DrmHalTestParam> {
+public:
+    DrmHalTestV1_3()
+        : drmFactory_(IDrmFactoryV1_3::getService(GetParam().instance_)) {}
+
+    virtual void SetUp() override {
+        ASSERT_NE(drmFactory_, nullptr);
+
+        // create plugin
+        hidl_string packageName("android.hardware.drm.V1_3.vts");
+        auto res = drmFactory_->createPlugin(
+            GetParam().scheme_, packageName,
+            [&](StatusV1_0 status, const sp<IDrmPluginV1_0>& pluginV1_0) {
+                EXPECT_EQ(StatusV1_0::OK, status);
+                drmPlugin_ = pluginV1_0;
+            });
+        EXPECT_TRUE(res.isOk());
+        ASSERT_NE(drmPlugin_, nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+protected:
+    sp<IDrmFactoryV1_3> drmFactory_;
+    sp<IDrmPluginV1_0> drmPlugin_;
+};
+
+}  // namespace vts
+}  // namespace V1_3
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
+
+#endif  // DRM_HAL_TEST_V1_3_H
diff --git a/dumpstate/1.1/IDumpstateDevice.hal b/dumpstate/1.1/IDumpstateDevice.hal
index 24831b3..183404d 100644
--- a/dumpstate/1.1/IDumpstateDevice.hal
+++ b/dumpstate/1.1/IDumpstateDevice.hal
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.hardware.dumpstate@1.1;
 
 import @1.0::IDumpstateDevice;
@@ -28,17 +29,23 @@
      * The 1.0 version of #dumpstateBoard(handle) should just delegate to this new method and pass
      * DumpstateMode::DEFAULT and a timeout of 30,000ms (30 seconds).
      *
+     * This method may still be called by the dumpstate routine even if getVerboseLoggingEnabled
+     * returns false. In this case, it may include essential information but must not include
+     * information that identifies the user.
+     *
      * @param h A native handle with one or two valid file descriptors. The first FD is for text
      *     output, the second (if present) is for binary output.
      * @param mode A mode value to restrict dumped content.
      * @param timeoutMillis An approximate "budget" for how much time this call has been allotted.
      *     If execution runs longer than this, the IDumpstateDevice service may be killed and only
      *     partial information will be included in the report.
+     * @return status A DumpstateStatus value indicating the final result.
      */
-    dumpstateBoard_1_1(handle h, DumpstateMode mode, uint64_t timeoutMillis);
+    dumpstateBoard_1_1(handle h, DumpstateMode mode, uint64_t timeoutMillis)
+        generates (DumpstateStatus status);
 
     /**
-     * Turns device vendor logging on or off.
+     * Turns verbose device vendor logging on or off.
      *
      * The setting should be persistent across reboots. Underlying implementations may need to start
      * vendor logging daemons, set system properties, or change logging masks, for example. Given
@@ -46,8 +53,21 @@
      * memory/storage/battery impacts, calling this method on a user build should only be done after
      * user consent has been obtained, e.g. from a toggle in developer settings.
      *
-     * @param enable Whether to enable or disable device vendor logging.
-     * @return success Whether or not the change took effect.
+     * Even if verbose logging has been disabled, dumpstateBoard may still be called by the
+     * dumpstate routine, and essential information that does not identify the user may be included.
+     *
+     * @param enable Whether to enable or disable verbose vendor logging.
      */
-    setDeviceLoggingEnabled(bool enable) generates (bool success);
+    setVerboseLoggingEnabled(bool enable);
+
+    /**
+     * Queries the current state of verbose device logging. Primarily for UI and informative
+     * purposes.
+     *
+     * Even if verbose logging has been disabled, dumpstateBoard may still be called by the
+     * dumpstate routine, and essential information that does not identify the user may be included.
+     *
+     * @return enabled Whether or not verbose vendor logging is currently enabled.
+     */
+    getVerboseLoggingEnabled() generates (bool enabled);
 };
diff --git a/dumpstate/1.1/types.hal b/dumpstate/1.1/types.hal
index a6f391a..c522f7c 100644
--- a/dumpstate/1.1/types.hal
+++ b/dumpstate/1.1/types.hal
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.hardware.dumpstate@1.1;
 
 /**
@@ -23,22 +24,18 @@
      * Takes a bug report without user interference.
      */
     FULL = 0,
-
     /**
      * Interactive bug report, i.e. triggered by the user.
      */
     INTERACTIVE = 1,
-
     /**
      * Remote bug report triggered by DevicePolicyManager, for example.
      */
     REMOTE = 2,
-
     /**
      * Bug report triggered on a wear device.
      */
     WEAR = 3,
-
     /**
      * Bug report limited to only connectivity info (cellular, wifi, and networking). Sometimes
      * called "telephony" in legacy contexts.
@@ -49,14 +46,41 @@
      * user application traffic.
      */
     CONNECTIVITY = 4,
-
     /**
      * Bug report limited to only wifi info.
      */
     WIFI = 5,
-
     /**
-     * Default mode.
+     * Default mode, essentially analogous to calling @1.0::IDumpstateDevice.dumpstateBoard(handle).
+     * This mode MUST be supported if the dumpstate HAL is implemented.
      */
-    DEFAULT = 6
+    DEFAULT = 6,
+    /**
+     * Takes a report in protobuf.
+     *
+     * The content, if implemented, must be a binary protobuf message written to the first file
+     * descriptor of the native handle. The protobuf schema shall be defined by the vendor.
+     */
+    PROTO = 7,
+};
+
+/**
+ * A simple return enum for use with dumpstateBoard_1_1.
+ */
+enum DumpstateStatus : uint32_t {
+    OK = 0,
+    /**
+     * Returned for cases where the device doesn't support the given DumpstateMode (e.g. a phone
+     * trying to use DumpstateMode::WEAR).
+     */
+    UNSUPPORTED_MODE = 1,
+    /**
+     * Returned for cases where an IllegalArgumentException is typically appropriate, e.g. missing
+     * file descriptors.
+     */
+    ILLEGAL_ARGUMENT = 2,
+    /**
+     * Returned when device logging is not enabled.
+     */
+    DEVICE_LOGGING_NOT_ENABLED = 3,
 };
diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
index 3b6051c..cbdd87b 100644
--- a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
+++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
@@ -18,6 +18,8 @@
 
 #include <fcntl.h>
 #include <unistd.h>
+
+#include <functional>
 #include <vector>
 
 #include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
@@ -28,24 +30,61 @@
 #include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
+namespace {
+
 using ::android::sp;
 using ::android::hardware::Return;
 using ::android::hardware::dumpstate::V1_1::DumpstateMode;
+using ::android::hardware::dumpstate::V1_1::DumpstateStatus;
 using ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
+using ::android::hardware::dumpstate::V1_1::toString;
 
 class DumpstateHidl1_1Test : public ::testing::TestWithParam<std::string> {
-  public:
-    virtual void SetUp() override {
+  protected:
+    virtual void SetUp() override { GetService(); }
+
+    void GetService() {
         dumpstate = IDumpstateDevice::getService(GetParam());
         ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance";
     }
 
+    void ToggleVerboseLogging(bool enable) {
+        Return<void> status = dumpstate->setVerboseLoggingEnabled(enable);
+        ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+
+        if (!dumpstate->ping().isOk()) {
+            ALOGW("IDumpstateDevice service appears to have exited lazily, attempting to get "
+                  "again");
+            GetService();
+        }
+
+        Return<bool> logging_enabled = dumpstate->getVerboseLoggingEnabled();
+        ASSERT_TRUE(logging_enabled.isOk())
+                << "Status should be ok: " << logging_enabled.description();
+        ASSERT_EQ(logging_enabled, enable)
+                << "Verbose logging should now be " << (enable ? "enabled" : "disabled");
+
+        if (!dumpstate->ping().isOk()) {
+            ALOGW("IDumpstateDevice service appears to have exited lazily, attempting to get "
+                  "again");
+            GetService();
+        }
+    }
+
+    void EnableVerboseLogging() { ToggleVerboseLogging(true); }
+
+    void DisableVerboseLogging() { ToggleVerboseLogging(false); }
+
     sp<IDumpstateDevice> dumpstate;
 };
 
 #define TEST_FOR_DUMPSTATE_MODE(name, body, mode) \
     TEST_P(DumpstateHidl1_1Test, name##_##mode) { body(DumpstateMode::mode); }
 
+// We use a macro to define individual test cases instead of hidl_enum_range<> because some HAL
+// implementations are lazy and may call exit() at the end of dumpstateBoard(), which would cause
+// DEAD_OBJECT errors after the first iteration. Separate cases re-get the service each time as part
+// of SetUp(), and also provide better separation of concerns when specific modes are problematic.
 #define TEST_FOR_ALL_DUMPSTATE_MODES(name, body)       \
     TEST_FOR_DUMPSTATE_MODE(name, body, FULL);         \
     TEST_FOR_DUMPSTATE_MODE(name, body, INTERACTIVE);  \
@@ -53,25 +92,56 @@
     TEST_FOR_DUMPSTATE_MODE(name, body, WEAR);         \
     TEST_FOR_DUMPSTATE_MODE(name, body, CONNECTIVITY); \
     TEST_FOR_DUMPSTATE_MODE(name, body, WIFI);         \
-    TEST_FOR_DUMPSTATE_MODE(name, body, DEFAULT);
+    TEST_FOR_DUMPSTATE_MODE(name, body, DEFAULT);      \
+    TEST_FOR_DUMPSTATE_MODE(name, body, PROTO);
 
-const uint64_t kDefaultTimeoutMillis = 30 * 1000;  // 30 seconds
+constexpr uint64_t kDefaultTimeoutMillis = 30 * 1000;  // 30 seconds
+
+// Will only execute additional_assertions when status == expected.
+void AssertStatusForMode(const DumpstateMode mode, const Return<DumpstateStatus>& status,
+                         const DumpstateStatus expected,
+                         std::function<void()> additional_assertions = nullptr) {
+    ASSERT_TRUE(status.isOk()) << "Status should be ok and return a more specific DumpstateStatus: "
+                               << status.description();
+    if (mode == DumpstateMode::DEFAULT) {
+        ASSERT_EQ(expected, status) << "Required mode (DumpstateMode::" << toString(mode)
+                                    << "): status should be DumpstateStatus::" << toString(expected)
+                                    << ", but got DumpstateStatus::" << toString(status);
+    } else {
+        // The rest of the modes are optional to support, but they MUST return either the expected
+        // value or UNSUPPORTED_MODE.
+        ASSERT_TRUE(status == expected || status == DumpstateStatus::UNSUPPORTED_MODE)
+                << "Optional mode (DumpstateMode::" << toString(mode)
+                << "): status should be DumpstateStatus::" << toString(expected)
+                << " or DumpstateStatus::UNSUPPORTED_MODE, but got DumpstateStatus::"
+                << toString(status);
+    }
+    if (status == expected && additional_assertions != nullptr) {
+        additional_assertions();
+    }
+}
 
 // Negative test: make sure dumpstateBoard() doesn't crash when passed a null pointer.
 TEST_FOR_ALL_DUMPSTATE_MODES(TestNullHandle, [this](DumpstateMode mode) {
-    Return<void> status = dumpstate->dumpstateBoard_1_1(nullptr, mode, kDefaultTimeoutMillis);
+    EnableVerboseLogging();
 
-    ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+    Return<DumpstateStatus> status =
+            dumpstate->dumpstateBoard_1_1(nullptr, mode, kDefaultTimeoutMillis);
+
+    AssertStatusForMode(mode, status, DumpstateStatus::ILLEGAL_ARGUMENT);
 });
 
 // Negative test: make sure dumpstateBoard() ignores a handle with no FD.
 TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithNoFd, [this](DumpstateMode mode) {
+    EnableVerboseLogging();
+
     native_handle_t* handle = native_handle_create(0, 0);
     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
 
-    Return<void> status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+    Return<DumpstateStatus> status =
+            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
 
-    ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+    AssertStatusForMode(mode, status, DumpstateStatus::ILLEGAL_ARGUMENT);
 
     native_handle_close(handle);
     native_handle_delete(handle);
@@ -79,6 +149,8 @@
 
 // Positive test: make sure dumpstateBoard() writes something to the FD.
 TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) {
+    EnableVerboseLogging();
+
     // Index 0 corresponds to the read end of the pipe; 1 to the write end.
     int fds[2];
     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
@@ -87,12 +159,14 @@
     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
     handle->data[0] = fds[1];
 
-    Return<void> status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
-    ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+    Return<DumpstateStatus> status =
+            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
 
-    // Check that at least one byte was written
-    char buff;
-    ASSERT_EQ(1, read(fds[0], &buff, 1)) << "dumped nothing";
+    AssertStatusForMode(mode, status, DumpstateStatus::OK, [&fds]() {
+        // Check that at least one byte was written.
+        char buff;
+        ASSERT_EQ(1, read(fds[0], &buff, 1)) << "Dumped nothing";
+    });
 
     native_handle_close(handle);
     native_handle_delete(handle);
@@ -100,6 +174,8 @@
 
 // Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
 TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) {
+    EnableVerboseLogging();
+
     int fds1[2];
     int fds2[2];
     ASSERT_EQ(0, pipe2(fds1, O_NONBLOCK)) << errno;
@@ -110,8 +186,17 @@
     handle->data[0] = fds1[1];
     handle->data[1] = fds2[1];
 
-    Return<void> status = dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
-    ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+    Return<DumpstateStatus> status =
+            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+
+    AssertStatusForMode(mode, status, DumpstateStatus::OK, [&fds1, &fds2]() {
+        // Check that at least one byte was written to one of the FDs.
+        char buff;
+        size_t read1 = read(fds1[0], &buff, 1);
+        size_t read2 = read(fds2[0], &buff, 1);
+        // Sometimes read returns -1, so we can't just add them together and expect >= 1.
+        ASSERT_TRUE(read1 == 1 || read2 == 1) << "Dumped nothing";
+    });
 
     native_handle_close(handle);
     native_handle_delete(handle);
@@ -119,6 +204,8 @@
 
 // Make sure dumpstateBoard_1_1 actually validates its arguments.
 TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Negative) {
+    EnableVerboseLogging();
+
     int fds[2];
     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
 
@@ -126,16 +213,21 @@
     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
     handle->data[0] = fds[1];
 
-    Return<void> status = dumpstate->dumpstateBoard_1_1(handle, static_cast<DumpstateMode>(-100),
-                                                        kDefaultTimeoutMillis);
-    ASSERT_FALSE(status.isOk()) << "Status should not be ok with invalid mode param: "
-                                << status.description();
+    Return<DumpstateStatus> status = dumpstate->dumpstateBoard_1_1(
+            handle, static_cast<DumpstateMode>(-100), kDefaultTimeoutMillis);
+
+    ASSERT_TRUE(status.isOk()) << "Status should be ok and return a more specific DumpstateStatus: "
+                               << status.description();
+    ASSERT_EQ(status, DumpstateStatus::ILLEGAL_ARGUMENT)
+            << "Should return DumpstateStatus::ILLEGAL_ARGUMENT for invalid mode param";
 
     native_handle_close(handle);
     native_handle_delete(handle);
 }
 
 TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Undefined) {
+    EnableVerboseLogging();
+
     int fds[2];
     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
 
@@ -143,29 +235,89 @@
     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
     handle->data[0] = fds[1];
 
-    Return<void> status = dumpstate->dumpstateBoard_1_1(handle, static_cast<DumpstateMode>(9001),
-                                                        kDefaultTimeoutMillis);
-    ASSERT_FALSE(status.isOk()) << "Status should not be ok with invalid mode param: "
-                                << status.description();
+    Return<DumpstateStatus> status = dumpstate->dumpstateBoard_1_1(
+            handle, static_cast<DumpstateMode>(9001), kDefaultTimeoutMillis);
+
+    ASSERT_TRUE(status.isOk()) << "Status should be ok and return a more specific DumpstateStatus: "
+                               << status.description();
+    ASSERT_EQ(status, DumpstateStatus::ILLEGAL_ARGUMENT)
+            << "Should return DumpstateStatus::ILLEGAL_ARGUMENT for invalid mode param";
 
     native_handle_close(handle);
     native_handle_delete(handle);
 }
 
-// Make sure toggling device logging doesn't crash.
-TEST_P(DumpstateHidl1_1Test, TestEnableDeviceLogging) {
-    Return<bool> status = dumpstate->setDeviceLoggingEnabled(true);
+// Positive test: make sure dumpstateBoard() from 1.0 doesn't fail.
+TEST_P(DumpstateHidl1_1Test, Test1_0MethodOk) {
+    EnableVerboseLogging();
+
+    int fds[2];
+    ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+    native_handle_t* handle = native_handle_create(1, 0);
+    ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+    handle->data[0] = fds[1];
+
+    Return<void> status = dumpstate->dumpstateBoard(handle);
 
     ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+
+    // Check that at least one byte was written.
+    char buff;
+    ASSERT_EQ(1, read(fds[0], &buff, 1)) << "Dumped nothing";
+
+    native_handle_close(handle);
+    native_handle_delete(handle);
 }
 
-TEST_P(DumpstateHidl1_1Test, TestDisableDeviceLogging) {
-    Return<bool> status = dumpstate->setDeviceLoggingEnabled(false);
+// Make sure disabling verbose logging behaves correctly. Some info is still allowed to be emitted,
+// but it can't have privacy/storage/battery impacts.
+TEST_FOR_ALL_DUMPSTATE_MODES(TestVerboseLoggingDisabled, [this](DumpstateMode mode) {
+    DisableVerboseLogging();
 
-    ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
+    // Index 0 corresponds to the read end of the pipe; 1 to the write end.
+    int fds[2];
+    ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+    native_handle_t* handle = native_handle_create(1, 0);
+    ASSERT_NE(handle, nullptr) << "Could not create native_handle";
+    handle->data[0] = fds[1];
+
+    Return<DumpstateStatus> status =
+            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+
+    // We don't include additional assertions here about the file passed in. If verbose logging is
+    // disabled, the OEM may choose to include nothing at all, but it is allowed to include some
+    // essential information based on the mode as long as it isn't private user information.
+    AssertStatusForMode(mode, status, DumpstateStatus::OK);
+
+    native_handle_close(handle);
+    native_handle_delete(handle);
+});
+
+// Double-enable is perfectly valid, but the second call shouldn't do anything.
+TEST_P(DumpstateHidl1_1Test, TestRepeatedEnable) {
+    EnableVerboseLogging();
+    EnableVerboseLogging();
+}
+
+// Double-disable is perfectly valid, but the second call shouldn't do anything.
+TEST_P(DumpstateHidl1_1Test, TestRepeatedDisable) {
+    DisableVerboseLogging();
+    DisableVerboseLogging();
+}
+
+// Toggling in short order is perfectly valid.
+TEST_P(DumpstateHidl1_1Test, TestRepeatedToggle) {
+    EnableVerboseLogging();
+    DisableVerboseLogging();
+    EnableVerboseLogging();
+    DisableVerboseLogging();
 }
 
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, DumpstateHidl1_1Test,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)),
         android::hardware::PrintInstanceNameToString);
+
+}  // namespace
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index 6183a1a..c04b4d0 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -26,6 +26,8 @@
 #include <condition_variable>
 #include <mutex>
 
+#include <cutils/properties.h>
+
 using android::hardware::Return;
 using android::hardware::Void;
 
@@ -37,6 +39,12 @@
 using android::hardware::gnss::V1_0::IGnssMeasurement;
 using android::sp;
 
+static bool IsAutomotiveDevice() {
+    char buffer[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware.type", buffer, "");
+    return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
 #define TIMEOUT_SEC 2  // for basic commands/responses
 
 // for command line argument on how strictly to run the test
@@ -473,9 +481,9 @@
 
   auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
   ASSERT_TRUE(gnssDebug.isOk());
-  if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
-    sp<IGnssDebug> iGnssDebug = gnssDebug;
-    EXPECT_NE(iGnssDebug, nullptr);
+  if (!IsAutomotiveDevice() && info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
+      sp<IGnssDebug> iGnssDebug = gnssDebug;
+      EXPECT_NE(iGnssDebug, nullptr);
   }
 }
 
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index e0d8b54..8530ffb 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -19,6 +19,7 @@
 #include <gnss_hal_test.h>
 
 #include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+#include <cutils/properties.h>
 #include <gtest/gtest.h>
 
 using android::hardware::hidl_vec;
@@ -32,6 +33,12 @@
 using android::hardware::gnss::V1_1::IGnssConfiguration;
 using android::hardware::gnss::V1_1::IGnssMeasurement;
 
+static bool IsAutomotiveDevice() {
+    char buffer[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware.type", buffer, "");
+    return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
 /*
  * SetupTeardownCreateCleanup:
  * Requests the gnss HAL then calls cleanup
@@ -524,7 +531,8 @@
 TEST_P(GnssHalTest, GnssDebugValuesSanityTest) {
     auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
     ASSERT_TRUE(gnssDebug.isOk());
-    if (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017) {
+    if (!IsAutomotiveDevice() && gnss_cb_->info_cbq_.calledCount() > 0 &&
+        gnss_cb_->last_info_.yearOfHw >= 2017) {
         sp<IGnssDebug> iGnssDebug = gnssDebug;
         EXPECT_NE(iGnssDebug, nullptr);
 
diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp
index 7efc4a6..2122399 100644
--- a/gnss/2.1/Android.bp
+++ b/gnss/2.1/Android.bp
@@ -9,6 +9,8 @@
     srcs: [
         "types.hal",
         "IGnss.hal",
+        "IGnssAntennaInfo.hal",
+        "IGnssAntennaInfoCallback.hal",
         "IGnssCallback.hal",
         "IGnssMeasurement.hal",
         "IGnssMeasurementCallback.hal",
diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal
index ce37647..a880b3f 100644
--- a/gnss/2.1/IGnss.hal
+++ b/gnss/2.1/IGnss.hal
@@ -18,10 +18,10 @@
 
 import android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections;
 import @2.0::IGnss;
-
 import IGnssCallback;
 import IGnssMeasurement;
 import IGnssConfiguration;
+import IGnssAntennaInfo;
 
 /**
  * Represents the standard GNSS (Global Navigation Satellite System) interface.
@@ -45,9 +45,9 @@
     /**
      * This method returns the IGnssMeasurement interface.
      *
-     * At least one of getExtensionGnssMeasurement(), getExtensionGnssMeasurement_1_1(),
+     * getExtensionGnssMeasurement(), getExtensionGnssMeasurement_1_1(),
      * getExtensionGnssMeasurement_2_0(), and getExtensionGnssMeasurement_2_1() methods must return
-     * a non-null handle, and the other methods must return nullptr.
+     * non-null. They can all return the same, latest version of IGnssMeasurement.
      *
      * @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
      */
@@ -56,9 +56,9 @@
     /**
      * This method returns the IGnssConfiguration interface.
      *
-     * At least one of getExtensionGnssConfiguration(), getExtensionGnssConfiguration_1_1(),
+     * getExtensionGnssConfiguration(), getExtensionGnssConfiguration_1_1(),
      * getExtensionGnssConfiguration_2_0(), and getExtensionGnssConfiguration_2_1() methods must
-     * return a non-null handle, and the other methods must return nullptr.
+     * return non-null. They can all return the same, latest version of IGnssConfiguration.
      *
      * @return gnssConfigurationIface Handle to the IGnssConfiguration interface.
      */
@@ -72,5 +72,15 @@
      *
      * @return measurementCorrectionsIface Handle to the IMeasurementCorrections interface.
      */
-     getExtensionMeasurementCorrections_1_1() generates (IMeasurementCorrections measurementCorrectionsIface);
-};
\ No newline at end of file
+    getExtensionMeasurementCorrections_1_1()
+        generates (IMeasurementCorrections measurementCorrectionsIface);
+
+    /**
+     * This method returns the IGnssAntennaInfo interface.
+     *
+     * This method must return non-null.
+     *
+     * @return gnssAntennaInfoIface Handle to the IGnssAntennaInfo interface.
+     */
+    getExtensionGnssAntennaInfo() generates (IGnssAntennaInfo gnssAntennaInfoIface);
+};
diff --git a/gnss/2.1/IGnssAntennaInfo.hal b/gnss/2.1/IGnssAntennaInfo.hal
new file mode 100644
index 0000000..f77d874
--- /dev/null
+++ b/gnss/2.1/IGnssAntennaInfo.hal
@@ -0,0 +1,46 @@
+/*
+ * 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.gnss@2.1;
+
+import IGnssAntennaInfoCallback;
+
+/**
+ * Extended interface for GNSS antenna information support.
+ */
+interface IGnssAntennaInfo {
+    enum GnssAntennaInfoStatus : int32_t {
+        SUCCESS = 0,
+        ERROR_ALREADY_INIT = -100,
+        ERROR_GENERIC = -101,
+    };
+
+    /**
+     * Registers the callback routines with the HAL.
+     *
+     * @param callback Handle to the GnssAntennaInfo callback interface.
+     */
+    setCallback(IGnssAntennaInfoCallback callback) generates (GnssAntennaInfoStatus initRet);
+
+    /**
+     * Stops updates from the HAL, and unregisters the callback routines.
+     * After a call to close(), the previously registered callbacks must be
+     * considered invalid by the HAL.
+     * If close() is invoked without a previous setCallback, this function must perform
+     * no work.
+     */
+    close();
+};
diff --git a/gnss/2.1/IGnssAntennaInfoCallback.hal b/gnss/2.1/IGnssAntennaInfoCallback.hal
new file mode 100644
index 0000000..883111e
--- /dev/null
+++ b/gnss/2.1/IGnssAntennaInfoCallback.hal
@@ -0,0 +1,136 @@
+/*
+ * 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.gnss@2.1;
+
+/**
+ * The callback interface to report GNSS antenna information from the HAL.
+ */
+interface IGnssAntennaInfoCallback {
+    /**
+     * A row of doubles. This is used to represent a row in a 2D array, which are used to
+     * characterize the phase center variation corrections and signal gain corrections.
+     */
+    struct Row {
+        vec<double> row;
+    };
+
+    /**
+     * A point in 3D space, with associated uncertainty.
+     */
+    struct Coord {
+        double x;
+
+        double xUncertainty;
+
+        double y;
+
+        double yUncertainty;
+
+        double z;
+
+        double zUncertainty;
+    };
+
+    struct GnssAntennaInfo {
+        /**
+         * The carrier frequency in MHz.
+         */
+        double carrierFrequencyMHz;
+
+        /**
+         * Phase center offset (PCO) with associated 1-sigma uncertainty. PCO is defined with
+         * respect to the origin of the Android sensor coordinate system, e.g., center of primary
+         * screen for mobiles - see sensor or form factor documents for details.
+         */
+        Coord phaseCenterOffsetCoordinateMillimeters;
+
+        /**
+         * 2D vectors representing the phase center variation (PCV) corrections, in
+         * millimeters, at regularly spaced azimuthal angle (theta) and zenith angle
+         * (phi). The PCV correction is added to the phase measurement to obtain the
+         * corrected value.
+         *
+         * The azimuthal angle, theta, is defined with respect to the X axis of the
+         * Android sensor coordinate system, increasing toward the Y axis. The zenith
+         * angle, phi, is defined with respect to the Z axis of the Android Sensor
+         * coordinate system, increasing toward the X-Y plane.
+         *
+         * Each row vector (outer vectors) represents a fixed theta. The first row
+         * corresponds to a theta angle of 0 degrees. The last row corresponds to a
+         * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular
+         * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows).
+         *
+         * The columns (inner vectors) represent fixed zenith angles, beginning at 0
+         * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular
+         * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1).
+         *
+         * This field is optional, i.e., an empty vector.
+         */
+        vec<Row> phaseCenterVariationCorrectionMillimeters;
+
+        /**
+         * 2D vectors of 1-sigma uncertainty in millimeters associated with the PCV
+         * correction values.
+         *
+         * This field is optional, i.e., an empty vector.
+         */
+        vec<Row> phaseCenterVariationCorrectionUncertaintyMillimeters;
+
+        /**
+         * 2D vectors representing the signal gain corrections at regularly spaced
+         * azimuthal angle (theta) and zenith angle (phi). The values are calculated or
+         * measured at the antenna feed point without considering the radio and receiver
+         * noise figure and path loss contribution, in dBi, i.e., decibel over isotropic
+         * antenna with the same total power. The signal gain correction is added the
+         * signal gain measurement to obtain the corrected value.
+         *
+         * The azimuthal angle, theta, is defined with respect to the X axis of the
+         * Android sensor coordinate system, increasing toward the Y axis. The zenith
+         * angle, phi, is defined with respect to the Z axis of the Android Sensor
+         * coordinate system, increasing toward the X-Y plane.
+         *
+         * Each row vector (outer vectors) represents a fixed theta. The first row
+         * corresponds to a theta angle of 0 degrees. The last row corresponds to a
+         * theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular
+         * spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows).
+         *
+         * The columns (inner vectors) represent fixed zenith angles, beginning at 0
+         * degrees and ending at 180 degrees. They are separated by deltaPhi, the regular
+         * spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1).
+         *
+         * This field is optional, i.e., an empty vector.
+         */
+        vec<Row> signalGainCorrectionDbi;
+
+        /**
+         * 2D vectors of 1-sigma uncertainty in dBi associated with the signal
+         * gain correction values.
+         *
+         * This field is optional, i.e., an empty vector.
+         */
+        vec<Row> signalGainCorrectionUncertaintyDbi;
+    };
+
+    /**
+     * Called when on connection, and on known-change to these values, such as upon a known
+     * GNSS RF antenna tuning change, or a foldable device state change.
+     *
+     * This is optional. It can never be called if the GNSS antenna information is not
+     * available.
+     */
+    gnssAntennaInfoCb(vec<GnssAntennaInfo> gnssAntennaInfos);
+};
diff --git a/gnss/2.1/IGnssCallback.hal b/gnss/2.1/IGnssCallback.hal
index da70742..94be915 100644
--- a/gnss/2.1/IGnssCallback.hal
+++ b/gnss/2.1/IGnssCallback.hal
@@ -24,8 +24,27 @@
  * the interfaces and passes a handle to the HAL.
  */
 interface IGnssCallback extends @2.0::IGnssCallback {
+    /**
+     * Flags for the gnssSetCapabilities callback.
+     */
+    @export(name = "", value_prefix = "GPS_CAPABILITY_")
+    enum Capabilities : @2.0::IGnssCallback.Capabilities {
+        /**
+         * GNSS supports measurement corrections
+         */
+        ANTENNA_INFO = 1 << 11,
+    };
 
-    /** Extends a GnssSvInfo, adding a basebandCN0DbHz. */
+    /**
+     * Callback to inform framework of the GNSS HAL implementation's capabilities.
+     *
+     * @param capabilities Capability parameter is a bit field of the Capabilities enum.
+     */
+    gnssSetCapabilitiesCb_2_1(bitfield<Capabilities> capabilities);
+
+    /**
+     * Extends a GnssSvInfo, adding a basebandCN0DbHz.
+     */
     struct GnssSvInfo {
         /**
          * GNSS satellite information for a single satellite and frequency.
diff --git a/gnss/2.1/IGnssConfiguration.hal b/gnss/2.1/IGnssConfiguration.hal
index 8360ba9..550f325 100644
--- a/gnss/2.1/IGnssConfiguration.hal
+++ b/gnss/2.1/IGnssConfiguration.hal
@@ -65,4 +65,4 @@
      * @return success Whether the HAL accepts and abides by the provided blacklist.
      */
     setBlacklist_2_1(vec<BlacklistedSource> blacklist) generates (bool success);
-};
\ No newline at end of file
+};
diff --git a/gnss/2.1/IGnssMeasurement.hal b/gnss/2.1/IGnssMeasurement.hal
index d2c76e6..49ba7eb 100644
--- a/gnss/2.1/IGnssMeasurement.hal
+++ b/gnss/2.1/IGnssMeasurement.hal
@@ -25,7 +25,6 @@
  * Extended interface for GNSS Measurements support.
  */
 interface IGnssMeasurement extends @2.0::IGnssMeasurement {
-
     /**
      * Initializes the interface and registers the callback routines with the HAL. After a
      * successful call to 'setCallback_2_1' the HAL must begin to provide updates at an average
@@ -47,5 +46,5 @@
      *     error code.
      */
     setCallback_2_1(IGnssMeasurementCallback callback, bool enableFullTracking)
-         generates (GnssMeasurementStatus initRet);
+        generates (GnssMeasurementStatus initRet);
 };
diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal
index 0385abd..0e6abbd 100644
--- a/gnss/2.1/IGnssMeasurementCallback.hal
+++ b/gnss/2.1/IGnssMeasurementCallback.hal
@@ -21,36 +21,32 @@
 import @2.0::ElapsedRealtime;
 import GnssSignalType;
 
-/** The callback interface to report measurements from the HAL. */
+/**
+ * The callback interface to report measurements from the HAL.
+ */
 interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback {
-
     /**
      * Flags to indicate what fields in GnssMeasurement are valid.
      */
-    enum GnssMeasurementFlags : uint32_t {
-        /** A valid 'snr' is stored in the data structure. */
-        HAS_SNR                           = 1 << 0,
-        /** A valid 'carrier frequency' is stored in the data structure. */
-        HAS_CARRIER_FREQUENCY             = 1 << 9,
-        /** A valid 'carrier cycles' is stored in the data structure. */
-        HAS_CARRIER_CYCLES                = 1 << 10,
-        /** A valid 'carrier phase' is stored in the data structure. */
-        HAS_CARRIER_PHASE                 = 1 << 11,
-        /** A valid 'carrier phase uncertainty' is stored in the data structure. */
-        HAS_CARRIER_PHASE_UNCERTAINTY     = 1 << 12,
-        /** A valid automatic gain control is stored in the data structure. */
-        HAS_AUTOMATIC_GAIN_CONTROL        = 1 << 13,
-        /** A valid receiver inter-signal bias is stored in the data structure. */
-        HAS_RECEIVER_ISB                  = 1 << 16,
-        /** A valid receiver inter-signal bias uncertainty is stored in the data structure. */
-        HAS_RECEIVER_ISB_UNCERTAINTY      = 1 << 17,
-        /** A valid satellite inter-signal bias is stored in the data structure. */
-        HAS_SATELLITE_ISB                 = 1 << 18,
-        /** A valid satellite inter-signal bias uncertainty is stored in the data structure. */
-        HAS_SATELLITE_ISB_UNCERTAINTY     = 1 << 19
+    enum GnssMeasurementFlags : @1.0::IGnssMeasurementCallback.GnssMeasurementFlags {
+        /**
+         * A valid receiver inter-signal bias is stored in the data structure.
+         */
+        HAS_RECEIVER_ISB = 1 << 16,
+        /**
+         * A valid receiver inter-signal bias uncertainty is stored in the data structure.
+         */
+        HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17,
+        /**
+         * A valid satellite inter-signal bias is stored in the data structure.
+         */
+        HAS_SATELLITE_ISB = 1 << 18,
+        /**
+         * A valid satellite inter-signal bias uncertainty is stored in the data structure.
+         */
+        HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19,
     };
 
-
     /**
      * Extends a GNSS Measurement, adding basebandCN0DbHz, GnssMeasurementFlags,
      * receiverInterSignalBiasNs, receiverInterSignalBiasUncertaintyNs, satelliteInterSignalBiasNs
@@ -84,8 +80,8 @@
          * The receiver inter-signal bias (ISB) in nanoseconds.
          *
          * This value is the estimated receiver-side inter-system (different from the constellation
-         * in GnssClock.referenceSignalForIsb) bias and inter-frequency (different from the carrier
-         * frequency in GnssClock.referenceSignalForIsb) bias. The reported receiver ISB
+         * in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different from the
+         * carrier frequency in GnssClock.referenceSignalTypeForIsb) bias. The reported receiver ISB
          * must include signal delays caused by
          *
          * - Receiver inter-constellation bias
@@ -94,7 +90,7 @@
          *
          * The value does not include the inter-frequency Ionospheric bias.
          *
-         * The receiver ISB of GnssClock.referenceSignalForIsb is defined to be 0.0 nanoseconds.
+         * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
          */
         double receiverInterSignalBiasNs;
 
@@ -107,8 +103,8 @@
          * The satellite inter-signal bias in nanoseconds.
          *
          * This value is the satellite-and-control-segment-side inter-system (different from the
-         * constellation in GnssClock.referenceSignalForIsb) bias and inter-frequency (different
-         * from the carrier frequency in GnssClock.referenceSignalForIsb) bias, including:
+         * constellation in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different
+         * from the carrier frequency in GnssClock.referenceSignalTypeForIsb) bias, including:
          *
          * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps),
          *   BDS-GLO Time Offset (BGTO))
@@ -116,7 +112,7 @@
          * - Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only),
          *   and satellite inter-code bias (e.g., Differential Code Bias (DCB)).
          *
-         * The receiver ISB of GnssClock.referenceSignalForIsb is defined to be 0.0 nanoseconds.
+         * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
          */
         double satelliteInterSignalBiasNs;
 
@@ -160,10 +156,14 @@
      * Complete set of GNSS Measurement data, same as 2.0 with additional fields in measurements.
      */
     struct GnssData {
-        /** The full set of satellite measurement observations. */
+        /**
+         * The full set of satellite measurement observations.
+         */
         vec<GnssMeasurement> measurements;
 
-        /** The GNSS clock time reading. */
+        /**
+         * The GNSS clock time reading.
+         */
         GnssClock clock;
 
         /**
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index 1f1078e..c4dc8fd 100644
--- a/gnss/2.1/default/Android.bp
+++ b/gnss/2.1/default/Android.bp
@@ -22,6 +22,7 @@
     vintf_fragments: ["android.hardware.gnss@2.1-service.xml"],
     srcs: [
         "Gnss.cpp",
+        "GnssAntennaInfo.cpp",
         "GnssDebug.cpp",
         "GnssMeasurement.cpp",
         "GnssMeasurementCorrections.cpp",
diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp
index 679eb35..2b327a9 100644
--- a/gnss/2.1/default/Gnss.cpp
+++ b/gnss/2.1/default/Gnss.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "Gnss"
 
 #include "Gnss.h"
+#include "GnssAntennaInfo.h"
 #include "GnssDebug.h"
 #include "GnssMeasurement.h"
 #include "GnssMeasurementCorrections.h"
@@ -334,10 +335,11 @@
 
     sGnssCallback_2_1 = callback;
 
-    using Capabilities = V2_0::IGnssCallback::Capabilities;
+    using Capabilities = V2_1::IGnssCallback::Capabilities;
     const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
-                              Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST;
-    auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_0(capabilities);
+                              Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST |
+                              Capabilities::ANTENNA_INFO;
+    auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_1(capabilities);
     if (!ret.isOk()) {
         ALOGE("%s: Unable to invoke callback", __func__);
     }
@@ -374,6 +376,11 @@
     return new GnssMeasurementCorrections();
 }
 
+Return<sp<V2_1::IGnssAntennaInfo>> Gnss::getExtensionGnssAntennaInfo() {
+    ALOGD("Gnss::getExtensionGnssAntennaInfo");
+    return new GnssAntennaInfo();
+}
+
 void Gnss::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
     std::unique_lock<std::mutex> lock(mMutex);
     // TODO(skz): update this to call 2_0 callback if non-null
diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h
index c47206a..bd5e6e8 100644
--- a/gnss/2.1/default/Gnss.h
+++ b/gnss/2.1/default/Gnss.h
@@ -22,6 +22,7 @@
 #include <atomic>
 #include <mutex>
 #include <thread>
+#include "GnssAntennaInfo.h"
 #include "GnssConfiguration.h"
 
 namespace android {
@@ -91,6 +92,7 @@
     Return<sp<V2_1::IGnssConfiguration>> getExtensionGnssConfiguration_2_1() override;
     Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
     getExtensionMeasurementCorrections_1_1() override;
+    Return<sp<V2_1::IGnssAntennaInfo>> getExtensionGnssAntennaInfo() override;
 
   private:
     void reportLocation(const V2_0::GnssLocation&) const;
diff --git a/gnss/2.1/default/GnssAntennaInfo.cpp b/gnss/2.1/default/GnssAntennaInfo.cpp
new file mode 100644
index 0000000..d32a0af
--- /dev/null
+++ b/gnss/2.1/default/GnssAntennaInfo.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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 "GnssAntennaInfo"
+
+#include "GnssAntennaInfo.h"
+#include "Utils.h"
+
+#include <log/log.h>
+
+using ::android::hardware::gnss::common::Utils;
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+sp<IGnssAntennaInfoCallback> GnssAntennaInfo::sCallback = nullptr;
+
+GnssAntennaInfo::GnssAntennaInfo() : mMinIntervalMillis(1000) {}
+
+GnssAntennaInfo::~GnssAntennaInfo() {
+    stop();
+}
+
+// Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow.
+Return<GnssAntennaInfo::GnssAntennaInfoStatus> GnssAntennaInfo::setCallback(
+        const sp<IGnssAntennaInfoCallback>& callback) {
+    ALOGD("setCallback");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = callback;
+
+    if (mIsActive) {
+        ALOGW("GnssAntennaInfo callback already set. Resetting the callback...");
+        stop();
+    }
+    start();
+
+    return GnssAntennaInfoStatus::SUCCESS;
+}
+
+Return<void> GnssAntennaInfo::close() {
+    ALOGD("close");
+    std::unique_lock<std::mutex> lock(mMutex);
+    stop();
+    sCallback = nullptr;
+    return Void();
+}
+
+// Private methods
+void GnssAntennaInfo::start() {
+    ALOGD("start");
+    mIsActive = true;
+    mThread = std::thread([this]() {
+        while (mIsActive == true) {
+            if (sCallback != nullptr) {
+                auto antennaInfos = Utils::getMockAntennaInfos();
+                this->reportAntennaInfo(antennaInfos);
+            }
+
+            /** For mock implementation this is good. On real device, we should only report
+                antennaInfo at start and when there is a configuration change. **/
+            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
+        }
+    });
+}
+
+void GnssAntennaInfo::stop() {
+    ALOGD("stop");
+    mIsActive = false;
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void GnssAntennaInfo::reportAntennaInfo(
+        const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+
+    if (sCallback == nullptr) {
+        ALOGE("%s: No non-null callback", __func__);
+        return;
+    }
+
+    auto ret = sCallback->gnssAntennaInfoCb(antennaInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/gnss/2.1/default/GnssAntennaInfo.h b/gnss/2.1/default/GnssAntennaInfo.h
new file mode 100644
index 0000000..f4bfd24
--- /dev/null
+++ b/gnss/2.1/default/GnssAntennaInfo.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
+#define ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
+
+#include <android/hardware/gnss/2.1/IGnssAntennaInfo.h>
+
+#include <mutex>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct GnssAntennaInfo : public IGnssAntennaInfo {
+    GnssAntennaInfo();
+    ~GnssAntennaInfo();
+
+    // Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow.
+    Return<GnssAntennaInfoStatus> setCallback(
+            const sp<IGnssAntennaInfoCallback>& callback) override;
+    Return<void> close() override;
+
+  private:
+    void start();
+    void stop();
+    void reportAntennaInfo(
+            const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const;
+
+    static sp<IGnssAntennaInfoCallback> sCallback;
+    std::atomic<long> mMinIntervalMillis;
+    std::atomic<bool> mIsActive;
+    std::thread mThread;
+    mutable std::mutex mMutex;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
\ No newline at end of file
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/2.1/default/GnssMeasurementCorrections.cpp
index 9dedbf6..accf62b 100644
--- a/gnss/2.1/default/GnssMeasurementCorrections.cpp
+++ b/gnss/2.1/default/GnssMeasurementCorrections.cpp
@@ -82,19 +82,20 @@
           static_cast<int>(corrections.v1_0.satCorrections.size()),
           corrections.hasEnvironmentBearing, corrections.environmentBearingDegrees,
           corrections.environmentBearingUncertaintyDegrees);
-    for (auto singleSatCorrection : corrections.v1_0.satCorrections) {
+    for (auto singleSatCorrection : corrections.satCorrections) {
         ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d, cfHz: %f, probLos: %f,"
               " epl: %f, eplUnc: %f",
-              static_cast<int>(singleSatCorrection.singleSatCorrectionFlags),
+              static_cast<int>(singleSatCorrection.v1_0.singleSatCorrectionFlags),
               static_cast<int>(singleSatCorrection.constellation),
-              static_cast<int>(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz,
-              singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
-              singleSatCorrection.excessPathLengthUncertaintyMeters);
+              static_cast<int>(singleSatCorrection.v1_0.svid),
+              singleSatCorrection.v1_0.carrierFrequencyHz, singleSatCorrection.v1_0.probSatIsLos,
+              singleSatCorrection.v1_0.excessPathLengthMeters,
+              singleSatCorrection.v1_0.excessPathLengthUncertaintyMeters);
         ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
-              singleSatCorrection.reflectingPlane.latitudeDegrees,
-              singleSatCorrection.reflectingPlane.longitudeDegrees,
-              singleSatCorrection.reflectingPlane.altitudeMeters,
-              singleSatCorrection.reflectingPlane.azimuthDegrees);
+              singleSatCorrection.v1_0.reflectingPlane.latitudeDegrees,
+              singleSatCorrection.v1_0.reflectingPlane.longitudeDegrees,
+              singleSatCorrection.v1_0.reflectingPlane.altitudeMeters,
+              singleSatCorrection.v1_0.reflectingPlane.azimuthDegrees);
     }
 
     return true;
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp
index 93f89f5..da7a62b 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp
@@ -215,6 +215,12 @@
     return Void();
 }
 
+Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) {
+    ALOGI("Capabilities (v2.1) received %d", capabilities);
+    capabilities_cbq_.store(capabilities);
+    return Void();
+}
+
 Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
     ALOGI("Name received: %s", name.c_str());
     name_cbq_.store(name);
@@ -262,4 +268,11 @@
     ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities);
     capabilities_cbq_.store(capabilities);
     return Void();
+}
+
+Return<void> GnssHalTest::GnssAntennaInfoCallback::gnssAntennaInfoCb(
+        const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
+    ALOGD("GnssAntennaInfo v2.1 received. Size = %d", (int)gnssAntennaInfos.size());
+    antenna_info_cbq_.store(gnssAntennaInfos);
+    return Void();
 }
\ No newline at end of file
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h
index b99cf23..9e6e162 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test.h
+++ b/gnss/2.1/vts/functional/gnss_hal_test.h
@@ -31,6 +31,8 @@
 using android::hardware::gnss::V1_0::GnssLocationFlags;
 using android::hardware::gnss::V2_0::GnssConstellationType;
 using android::hardware::gnss::V2_1::IGnss;
+using android::hardware::gnss::V2_1::IGnssAntennaInfo;
+using android::hardware::gnss::V2_1::IGnssAntennaInfoCallback;
 
 using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation;
 using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation;
@@ -107,6 +109,7 @@
         // New in v2.1
         Return<void> gnssSvStatusCb_2_1(
                 const hidl_vec<IGnssCallback_2_1::GnssSvInfo>& svInfoList) override;
+        Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
 
       private:
         Return<void> gnssLocationCbImpl(const GnssLocation_2_0& location);
@@ -152,6 +155,20 @@
         Return<void> setCapabilitiesCb(uint32_t capabilities) override;
     };
 
+    /* Callback class for GnssAntennaInfo. */
+    class GnssAntennaInfoCallback : public IGnssAntennaInfoCallback {
+      public:
+        GnssCallbackEventQueue<hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>>
+                antenna_info_cbq_;
+
+        GnssAntennaInfoCallback() : antenna_info_cbq_("info"){};
+        virtual ~GnssAntennaInfoCallback() = default;
+
+        // Methods from V2_1::GnssAntennaInfoCallback follow.
+        Return<void> gnssAntennaInfoCb(
+                const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
+    };
+
     /*
      * SetUpGnssCallback:
      *   Set GnssCallback and verify the result.
diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
index 9ac9436..7b054c0 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -139,7 +139,7 @@
             std::string codeType = lastMeasurement.clock.referenceSignalTypeForIsb.codeType;
 
             ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
-                        referenceConstellation >= GnssConstellationType::IRNSS);
+                        referenceConstellation <= GnssConstellationType::IRNSS);
             ASSERT_TRUE(carrierFrequencyHz > 0);
             ASSERT_TRUE(codeType != "");
 
@@ -154,6 +154,85 @@
 }
 
 /*
+ * TestGnssAntennaInfo:
+ * Sets a GnssAntennaInfoCallback, waits for report, and verifies
+ * 1. phaseCenterOffsetCoordinateMillimeters is valid
+ * 2. phaseCenterOffsetCoordinateUncertaintyMillimeters is valid.
+ * PhaseCenterVariationCorrections and SignalGainCorrections are optional.
+ */
+TEST_P(GnssHalTest, TestGnssAntennaInfo) {
+    const int kAntennaInfoTimeoutSeconds = 2;
+
+    auto gnssAntennaInfo = gnss_hal_->getExtensionGnssAntennaInfo();
+    ASSERT_TRUE(gnssAntennaInfo.isOk());
+
+    // Skip test if GnssAntennaInfo v2.1 is not supported
+    sp<IGnssAntennaInfo> iGnssAntennaInfo = gnssAntennaInfo;
+    if (!(gnss_cb_->last_capabilities_ & IGnssCallback_2_1::Capabilities::ANTENNA_INFO) ||
+        iGnssAntennaInfo == nullptr) {
+        ALOGD("GnssAntennaInfo v2.1 is not supported.");
+        return;
+    }
+
+    sp<GnssAntennaInfoCallback> callback = new GnssAntennaInfoCallback();
+    auto result = iGnssAntennaInfo->setCallback(callback);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_EQ(result, IGnssAntennaInfo::GnssAntennaInfoStatus::SUCCESS);
+
+    hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo> antennaInfos;
+    ASSERT_TRUE(callback->antenna_info_cbq_.retrieve(antennaInfos, kAntennaInfoTimeoutSeconds));
+    EXPECT_EQ(callback->antenna_info_cbq_.calledCount(), 1);
+    ASSERT_TRUE(antennaInfos.size() > 0);
+
+    for (auto antennaInfo : antennaInfos) {
+        // Remaining fields are optional
+        if (antennaInfo.phaseCenterVariationCorrectionMillimeters != NULL) {
+            int numRows = antennaInfo.phaseCenterVariationCorrectionMillimeters.size();
+            int numColumns = antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size();
+            // Must have at least 1 row and 2 columns
+            ASSERT_TRUE(numRows >= 1 && numColumns >= 2);
+
+            // Corrections and uncertainties must have same dimensions
+            ASSERT_TRUE(antennaInfo.phaseCenterVariationCorrectionMillimeters.size() ==
+                        antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.size());
+            ASSERT_TRUE(
+                    antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size() ==
+                    antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters[0].row.size());
+
+            // Must be rectangular
+            for (auto row : antennaInfo.phaseCenterVariationCorrectionMillimeters) {
+                ASSERT_TRUE(row.row.size() == numColumns);
+            }
+            for (auto row : antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters) {
+                ASSERT_TRUE(row.row.size() == numColumns);
+            }
+        }
+        if (antennaInfo.signalGainCorrectionDbi != NULL) {
+            int numRows = antennaInfo.signalGainCorrectionDbi.size();
+            int numColumns = antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size();
+            // Must have at least 1 row and 2 columns
+            ASSERT_TRUE(numRows >= 1 && numColumns >= 2);
+
+            // Corrections and uncertainties must have same dimensions
+            ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi.size() ==
+                        antennaInfo.signalGainCorrectionUncertaintyDbi.size());
+            ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi[0].row.size() ==
+                        antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size());
+
+            // Must be rectangular
+            for (auto row : antennaInfo.signalGainCorrectionDbi) {
+                ASSERT_TRUE(row.row.size() == numColumns);
+            }
+            for (auto row : antennaInfo.signalGainCorrectionUncertaintyDbi) {
+                ASSERT_TRUE(row.row.size() == numColumns);
+            }
+        }
+    }
+
+    iGnssAntennaInfo->close();
+}
+
+/*
  * TestGnssSvInfoFields:
  * Gets 1 location and a GnssSvInfo, and verifies
  * 1. basebandCN0DbHz is valid.
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index 0cdc865..2e5b873 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -235,6 +235,58 @@
     return svInfo;
 }
 
+hidl_vec<GnssAntennaInfo> Utils::getMockAntennaInfos() {
+    GnssAntennaInfo mockAntennaInfo_1 = {
+            .carrierFrequencyMHz = 123412.12,
+            .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 1,
+                                                            .xUncertainty = 0.1,
+                                                            .y = 2,
+                                                            .yUncertainty = 0.1,
+                                                            .z = 3,
+                                                            .zUncertainty = 0.1},
+            .phaseCenterVariationCorrectionMillimeters =
+                    {
+                            Row{hidl_vec<double>{1, -1, 5, -2, 3, -1}},
+                            Row{hidl_vec<double>{-2, 3, 2, 0, 1, 2}},
+                            Row{hidl_vec<double>{1, 3, 2, -1, -3, 5}},
+                    },
+            .phaseCenterVariationCorrectionUncertaintyMillimeters =
+                    {
+                            Row{hidl_vec<double>{0.1, 0.2, 0.4, 0.1, 0.2, 0.3}},
+                            Row{hidl_vec<double>{0.3, 0.2, 0.3, 0.6, 0.1, 0.1}},
+                            Row{hidl_vec<double>{0.1, 0.1, 0.4, 0.2, 0.5, 0.3}},
+                    },
+            .signalGainCorrectionDbi =
+                    {
+                            Row{hidl_vec<double>{2, -3, 1, -3, 0, -4}},
+                            Row{hidl_vec<double>{1, 0, -4, 1, 3, -2}},
+                            Row{hidl_vec<double>{3, -2, 0, -2, 3, 0}},
+                    },
+            .signalGainCorrectionUncertaintyDbi =
+                    {
+                            Row{hidl_vec<double>{0.3, 0.1, 0.2, 0.6, 0.1, 0.3}},
+                            Row{hidl_vec<double>{0.1, 0.1, 0.5, 0.2, 0.3, 0.1}},
+                            Row{hidl_vec<double>{0.2, 0.4, 0.2, 0.1, 0.1, 0.2}},
+                    },
+    };
+
+    GnssAntennaInfo mockAntennaInfo_2 = {
+            .carrierFrequencyMHz = 532324.23,
+            .phaseCenterOffsetCoordinateMillimeters = Coord{.x = 5,
+                                                            .xUncertainty = 0.1,
+                                                            .y = 6,
+                                                            .yUncertainty = 0.1,
+                                                            .z = 7,
+                                                            .zUncertainty = 0.1},
+    };
+
+    hidl_vec<GnssAntennaInfo> mockAntennaInfos = {
+            mockAntennaInfo_1,
+            mockAntennaInfo_2,
+    };
+    return mockAntennaInfos;
+}
+
 }  // namespace common
 }  // namespace gnss
 }  // namespace hardware
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index e0c61a4..d9ad5a5 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -33,6 +33,9 @@
 using GnssSvInfoV1_0 = V1_0::IGnssCallback::GnssSvInfo;
 using GnssSvInfoV2_0 = V2_0::IGnssCallback::GnssSvInfo;
 using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo;
+using GnssAntennaInfo = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo;
+using Row = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::Row;
+using Coord = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback::Coord;
 
 struct Utils {
     static GnssDataV2_0 getMockMeasurementV2_0();
@@ -46,6 +49,7 @@
     static GnssSvInfoV1_0 getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type,
                                             float cN0DbHz, float elevationDegrees,
                                             float azimuthDegrees);
+    static hidl_vec<GnssAntennaInfo> getMockAntennaInfos();
 };
 
 }  // namespace common
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index b6c3f5e..4b5a50f 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -22,7 +22,9 @@
 namespace gnss {
 namespace common {
 
-using V1_0::GnssConstellationType;
+using GnssConstellationType_V1_0 = V1_0::GnssConstellationType;
+using GnssConstellationType_V2_0 = V2_0::GnssConstellationType;
+
 using V1_0::GnssLocationFlags;
 
 void Utils::checkLocation(const GnssLocation& location, bool check_speed,
@@ -100,12 +102,12 @@
             .azimuthDegrees = 203.0,
     };
 
-    SingleSatCorrection singleSatCorrection1 = {
+    SingleSatCorrection_V1_0 singleSatCorrection1 = {
             .singleSatCorrectionFlags = GnssSingleSatCorrectionFlags::HAS_SAT_IS_LOS_PROBABILITY |
                                         GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH |
                                         GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH_UNC |
                                         GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE,
-            .constellation = GnssConstellationType::GPS,
+            .constellation = GnssConstellationType_V1_0::GPS,
             .svid = 12,
             .carrierFrequencyHz = 1.59975e+09,
             .probSatIsLos = 0.50001,
@@ -113,11 +115,11 @@
             .excessPathLengthUncertaintyMeters = 25.5,
             .reflectingPlane = reflectingPlane,
     };
-    SingleSatCorrection singleSatCorrection2 = {
+    SingleSatCorrection_V1_0 singleSatCorrection2 = {
             .singleSatCorrectionFlags = GnssSingleSatCorrectionFlags::HAS_SAT_IS_LOS_PROBABILITY |
                                         GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH |
                                         GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH_UNC,
-            .constellation = GnssConstellationType::GPS,
+            .constellation = GnssConstellationType_V1_0::GPS,
             .svid = 9,
             .carrierFrequencyHz = 1.59975e+09,
             .probSatIsLos = 0.873,
@@ -125,8 +127,8 @@
             .excessPathLengthUncertaintyMeters = 10.0,
     };
 
-    hidl_vec<SingleSatCorrection> singleSatCorrections = {singleSatCorrection1,
-                                                          singleSatCorrection2};
+    hidl_vec<SingleSatCorrection_V1_0> singleSatCorrections = {singleSatCorrection1,
+                                                               singleSatCorrection2};
     MeasurementCorrections_1_0 mockCorrections = {
             .latitudeDegrees = 37.4219999,
             .longitudeDegrees = -122.0840575,
@@ -142,11 +144,27 @@
 const MeasurementCorrections_1_1 Utils::getMockMeasurementCorrections_1_1() {
     MeasurementCorrections_1_0 mockCorrections_1_0 = getMockMeasurementCorrections();
 
+    SingleSatCorrection_V1_1 singleSatCorrection1 = {
+            .v1_0 = mockCorrections_1_0.satCorrections[0],
+            .constellation = GnssConstellationType_V2_0::IRNSS,
+    };
+    SingleSatCorrection_V1_1 singleSatCorrection2 = {
+            .v1_0 = mockCorrections_1_0.satCorrections[1],
+            .constellation = GnssConstellationType_V2_0::IRNSS,
+    };
+
+    mockCorrections_1_0.satCorrections[0].constellation = GnssConstellationType_V1_0::UNKNOWN;
+    mockCorrections_1_0.satCorrections[1].constellation = GnssConstellationType_V1_0::UNKNOWN;
+
+    hidl_vec<SingleSatCorrection_V1_1> singleSatCorrections = {singleSatCorrection1,
+                                                               singleSatCorrection2};
+
     MeasurementCorrections_1_1 mockCorrections_1_1 = {
             .v1_0 = mockCorrections_1_0,
             .hasEnvironmentBearing = true,
             .environmentBearingDegrees = 45.0,
             .environmentBearingUncertaintyDegrees = 4.0,
+            .satCorrections = singleSatCorrections,
     };
     return mockCorrections_1_1;
 }
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index 781ad42..c3cdd18 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -29,6 +29,11 @@
 using MeasurementCorrections_1_1 =
         android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;
 
+using SingleSatCorrection_V1_0 =
+        android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
+using SingleSatCorrection_V1_1 =
+        android::hardware::gnss::measurement_corrections::V1_1::SingleSatCorrection;
+
 namespace android {
 namespace hardware {
 namespace gnss {
diff --git a/gnss/measurement_corrections/1.0/types.hal b/gnss/measurement_corrections/1.0/types.hal
index edf26bf..3d7ab0f 100644
--- a/gnss/measurement_corrections/1.0/types.hal
+++ b/gnss/measurement_corrections/1.0/types.hal
@@ -92,16 +92,16 @@
     double altitudeMeters;
 
     /**
-     * Represents the horizontal uncertainty (68% confidence) in meters on the device position at
-     * which the corrections are provided.
+     * Represents the horizontal uncertainty (63% to 68% confidence) in meters on the device
+     * position at which the corrections are provided.
      *
      * This value is useful for example to judge how accurate the provided corrections are.
      */
     double horizontalPositionUncertaintyMeters;
 
     /**
-     * Represents the vertical uncertainty (68% confidence) in meters on the device position at
-     * which the corrections are provided.
+     * Represents the vertical uncertainty (63% to 68% confidence) in meters on the device position
+     * at which the corrections are provided.
      *
      * This value is useful for example to judge how accurate the provided corrections are.
      */
diff --git a/gnss/measurement_corrections/1.1/Android.bp b/gnss/measurement_corrections/1.1/Android.bp
index 1d69f20..d279af6 100644
--- a/gnss/measurement_corrections/1.1/Android.bp
+++ b/gnss/measurement_corrections/1.1/Android.bp
@@ -12,6 +12,7 @@
     ],
     interfaces: [
         "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss@2.0",
         "android.hardware.gnss@1.0",
         "android.hidl.base@1.0",
     ],
diff --git a/gnss/measurement_corrections/1.1/types.hal b/gnss/measurement_corrections/1.1/types.hal
index 40b6f52..e98be13 100644
--- a/gnss/measurement_corrections/1.1/types.hal
+++ b/gnss/measurement_corrections/1.1/types.hal
@@ -17,11 +17,14 @@
 package android.hardware.gnss.measurement_corrections@1.1;
 
 import @1.0::MeasurementCorrections;
+import @1.0::SingleSatCorrection;
+import android.hardware.gnss@2.0::GnssConstellationType;
 
 /**
  * A struct containing a set of measurement corrections for all used GNSS satellites at the location
  * specified by latitudeDegrees, longitudeDegrees, altitudeMeters and at the time of week specified
- * toaGpsNanosecondsOfWeek
+ * toaGpsNanosecondsOfWeek. The v1_0.satCorrections field is deprecated and is no longer used by
+ * framework.
  */
 struct MeasurementCorrections {
     @1.0::MeasurementCorrections v1_0;
@@ -48,11 +51,41 @@
      * If the road is curved in the vicinity of the user location, then
      * environmentBearingUncertaintyDegrees will include the amount by which the road direction
      * changes in the area of position uncertainty.
+     *
+     * hasEnvironmentBearing should be checked to verify the environment bearing is available
+     * before calling this method. The value is undefined if hasEnvironmentBearing is false.
      */
     float environmentBearingDegrees;
 
     /**
-     * Bearing uncertainty [0 to 180].
+     * Environment bearing uncertainty [0 to 180]. It represents the standard deviation of the
+     * physical structure in the circle of position uncertainty. hasEnvironmentBearing becomes false
+     * as the uncertainty value passes a predefined threshold depending on the physical structure
+     * around the user.
+     *
+     * hasEnvironmentBearing should be checked to verify the environment bearing is available
+     * before calling this method. The value is undefined if hasEnvironmentBearing is false.
      */
     float environmentBearingUncertaintyDegrees;
-};
\ No newline at end of file
+
+    /**
+     * A set of SingleSatCorrection each containing measurement corrections for a satellite in view
+     */
+    vec<SingleSatCorrection> satCorrections;
+};
+
+/**
+ * A struct with measurement corrections for a single visible satellites, updating the
+ * GnssConstellationType to 2.0, which supports IRNSS. The v1_0.constellation is deprecated and is
+ * no longer used by framework.
+ *
+ * The bit mask singleSatCorrectionFlags indicates which correction values are valid in the struct
+ */
+struct SingleSatCorrection {
+    @1.0::SingleSatCorrection v1_0;
+
+    /**
+     * Defines the constellation of the given satellite.
+     */
+    GnssConstellationType constellation;
+};
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index cdc0f35..3b0911f 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -23,14 +23,13 @@
         "TestCommandReader.cpp",
     ],
     static_libs: [
-        "VtsHalHidlTargetTestBase",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libgtest",
     ],
     export_static_lib_headers: [
-        "VtsHalHidlTargetTestBase",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@3.0-vts",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index a8e1480..4b6b7c8 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
 
 #include <composer-vts/2.1/ComposerVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -25,11 +23,6 @@
 namespace V2_1 {
 namespace vts {
 
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
-    : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
 Composer::Composer(const sp<IComposer>& composer) : mComposer(composer) {
     // ASSERT_* can only be used in functions returning void.
     [this] {
diff --git a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
index 454a89c..0506f3a 100644
--- a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
+++ b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
@@ -29,63 +29,68 @@
     mErrors.clear();
     mCompositionChanges.clear();
     while (!isEmpty()) {
-        IComposerClient::Command command;
+        int32_t command;
         uint16_t length;
         ASSERT_TRUE(beginCommand(&command, &length));
 
-        switch (command) {
-            case IComposerClient::Command::SELECT_DISPLAY:
-                ASSERT_EQ(2, length);
-                read64();  // display
-                break;
-            case IComposerClient::Command::SET_ERROR: {
-                ASSERT_EQ(2, length);
-                auto loc = read();
-                auto err = readSigned();
-                std::pair<uint32_t, uint32_t> error(loc, err);
-                mErrors.push_back(error);
-            } break;
-            case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
-                ASSERT_EQ(0, length % 3);
-                for (uint16_t count = 0; count < length / 3; ++count) {
-                    uint64_t layerId = read64();
-                    uint32_t composition = read();
-
-                    std::pair<uint64_t, uint32_t> compositionChange(layerId, composition);
-                    mCompositionChanges.push_back(compositionChange);
-                }
-                break;
-            case IComposerClient::Command::SET_DISPLAY_REQUESTS:
-                ASSERT_EQ(1, length % 3);
-                read();  // displayRequests, ignored for now
-                for (uint16_t count = 0; count < (length - 1) / 3; ++count) {
-                    read64();  // layer
-                    // silently eat requests to clear the client target, since we won't be testing
-                    // client composition anyway
-                    ASSERT_EQ(1u, read());
-                }
-                break;
-            case IComposerClient::Command::SET_PRESENT_FENCE:
-                ASSERT_EQ(1, length);
-                close(readFence());
-                break;
-            case IComposerClient::Command::SET_RELEASE_FENCES:
-                ASSERT_EQ(0, length % 3);
-                for (uint16_t count = 0; count < length / 3; ++count) {
-                    read64();
-                    close(readFence());
-                }
-                break;
-            default:
-                GTEST_FAIL() << "unexpected return command " << std::hex
-                             << static_cast<int>(command);
-                break;
-        }
+        parseSingleCommand(command, length);
 
         endCommand();
     }
 }
 
+void TestCommandReader::parseSingleCommand(int32_t commandRaw, uint16_t length) {
+    IComposerClient::Command command = static_cast<IComposerClient::Command>(commandRaw);
+
+    switch (command) {
+        case IComposerClient::Command::SELECT_DISPLAY:
+            ASSERT_EQ(2, length);
+            read64();  // display
+            break;
+        case IComposerClient::Command::SET_ERROR: {
+            ASSERT_EQ(2, length);
+            auto loc = read();
+            auto err = readSigned();
+            std::pair<uint32_t, uint32_t> error(loc, err);
+            mErrors.push_back(error);
+        } break;
+        case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
+            ASSERT_EQ(0, length % 3);
+            for (uint16_t count = 0; count < length / 3; ++count) {
+                uint64_t layerId = read64();
+                uint32_t composition = read();
+
+                std::pair<uint64_t, uint32_t> compositionChange(layerId, composition);
+                mCompositionChanges.push_back(compositionChange);
+            }
+            break;
+        case IComposerClient::Command::SET_DISPLAY_REQUESTS:
+            ASSERT_EQ(1, length % 3);
+            read();  // displayRequests, ignored for now
+            for (uint16_t count = 0; count < (length - 1) / 3; ++count) {
+                read64();  // layer
+                // silently eat requests to clear the client target, since we won't be testing
+                // client composition anyway
+                ASSERT_EQ(1u, read());
+            }
+            break;
+        case IComposerClient::Command::SET_PRESENT_FENCE:
+            ASSERT_EQ(1, length);
+            close(readFence());
+            break;
+        case IComposerClient::Command::SET_RELEASE_FENCES:
+            ASSERT_EQ(0, length % 3);
+            for (uint16_t count = 0; count < length / 3; ++count) {
+                read64();
+                close(readFence());
+            }
+            break;
+        default:
+            GTEST_FAIL() << "unexpected return command " << std::hex << static_cast<int>(command);
+            break;
+    }
+}
+
 }  // namespace vts
 }  // namespace V2_1
 }  // namespace composer
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
index c12debe..40d347a 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
@@ -29,12 +29,16 @@
 // returned.
 class TestCommandReader : public CommandReaderBase {
    public:
-    // Parse all commands in the return command queue.  Call GTEST_FAIL() for
-    // unexpected errors or commands.
-    void parse();
+     virtual ~TestCommandReader() = default;
+     // Parse all commands in the return command queue.  Call GTEST_FAIL() for
+     // unexpected errors or commands.
+     void parse();
 
-    std::vector<std::pair<uint32_t, uint32_t>> mErrors;
-    std::vector<std::pair<uint64_t, uint32_t>> mCompositionChanges;
+     std::vector<std::pair<uint32_t, uint32_t>> mErrors;
+     std::vector<std::pair<uint64_t, uint32_t>> mCompositionChanges;
+
+   protected:
+     virtual void parseSingleCommand(int32_t commandRaw, uint16_t length);
 };
 
 }  // namespace vts
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 5432882..a8bb1a2 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -26,11 +26,11 @@
         "libui",
     ],
     static_libs: [
-        "VtsHalHidlTargetTestBase",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.mapper@2.1-vts",
         "libarect",
+        "libgtest",
         "libmath",
         "libnativewindow",
         "librenderengine",
@@ -40,7 +40,6 @@
         "android.hardware.graphics.mapper@4.0-vts",
     ],
     export_static_lib_headers: [
-        "VtsHalHidlTargetTestBase",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.mapper@2.1-vts",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index 93b67f0..a526137 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -16,7 +16,6 @@
 
 #include <composer-vts/2.2/ComposerVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <hidl/HidlTransportUtils.h>
 
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index a23d72c..c78c358 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -33,6 +33,10 @@
     mRenderEngine = renderengine::RenderEngine::create(args);
 }
 
+TestRenderEngine::~TestRenderEngine() {
+    mRenderEngine.release();
+}
+
 void TestRenderEngine::setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers) {
     sort(layers.begin(), layers.end(),
          [](const std::shared_ptr<TestLayer>& lhs, const std::shared_ptr<TestLayer>& rhs) -> bool {
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 5d22305..6bc2732 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -22,7 +22,6 @@
 #include <unordered_set>
 #include <vector>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android/hardware/graphics/composer/2.2/IComposer.h>
 #include <android/hardware/graphics/composer/2.2/IComposerClient.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
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 7519a64..d5eedf1 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
@@ -142,7 +142,7 @@
     const native_handle_t* mBufferHandle = nullptr;
 };
 
-class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase {
+class ReadbackHelper {
   public:
     static std::string getColorModeString(ColorMode mode);
 
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 b936cab..f2d5f19 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
@@ -24,8 +24,6 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -43,7 +41,7 @@
     static constexpr uint32_t sMaxFrameBufferAcquireBuffers = 2;
 
     TestRenderEngine(const RenderEngineCreationArgs& args);
-    ~TestRenderEngine() = default;
+    ~TestRenderEngine();
 
     void setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers);
     void initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint64_t usage);
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index f987516..e38af00 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -19,7 +19,7 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
-        "VtsHalGraphicsComposerV2_2TargetTest.cpp"
+        "VtsHalGraphicsComposerV2_2TargetTest.cpp",
     ],
 
     // TODO(b/64437680): Assume these libs are always available on the device.
@@ -51,12 +51,16 @@
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0",
         "android.hardware.graphics.mapper@4.0-vts",
-        "librenderengine"
+        "libgtest",
+        "librenderengine",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 044bd96..cb43e64 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -932,7 +932,7 @@
 
 class GraphicsBlendModeCompositionTest
     : public GraphicsCompositionTestBase,
-      public testing::WithParamInterface<std::tuple<string, string>> {
+      public testing::WithParamInterface<std::tuple<std::string, std::string>> {
   public:
     void SetUp() override {
         SetUpBase(std::get<0>(GetParam()));
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index f65a9c4..3d81e8f 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -23,6 +23,7 @@
     static_libs: [
         "android.hardware.graphics.composer@2.2-vts",
         "android.hardware.graphics.composer@2.3",
+        "libgtest",
     ],
     export_static_lib_headers: [
         "android.hardware.graphics.composer@2.2-vts",
diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
index d4f5b3a..d73a3b0 100644
--- a/graphics/composer/2.3/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
 
 #include <composer-vts/2.3/ComposerVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -27,11 +25,6 @@
 
 using V2_1::Error;
 
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
-    : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
 Composer::Composer(const sp<IComposer>& composer)
     : V2_2::vts::Composer(composer), mComposer(composer) {}
 
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
index e5ac842..dae9ab4 100644
--- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -19,7 +19,6 @@
 #include <memory>
 #include <vector>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android/hardware/graphics/composer/2.3/IComposer.h>
 #include <android/hardware/graphics/composer/2.3/IComposerClient.h>
 #include <composer-vts/2.2/ComposerVts.h>
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
index 673c15e..fc13c2a 100644
--- a/graphics/composer/2.4/utils/vts/Android.bp
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -20,19 +20,21 @@
     srcs: [
         "ComposerVts.cpp",
         "GraphicsComposerCallback.cpp",
+        "TestCommandReader.cpp",
     ],
     static_libs: [
-        "VtsHalHidlTargetTestBase",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3-vts",
         "android.hardware.graphics.composer@2.3",
         "android.hardware.graphics.composer@2.4",
+        "libgtest",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
         "android.hardware.graphics.composer@2.3-command-buffer",
+        "android.hardware.graphics.composer@2.4-command-buffer",
     ],
     cflags: [
         "-O0",
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
index 8cdc452..b3f3374 100644
--- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
 
 #include <composer-vts/2.4/ComposerVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -27,11 +25,6 @@
 
 using V2_4::Error;
 
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
-    : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
 Composer::Composer(const sp<IComposer>& composer)
     : V2_3::vts::Composer(composer), mComposer(composer) {}
 
@@ -139,6 +132,38 @@
     return error;
 }
 
+void ComposerClient::execute(TestCommandReader* reader, CommandWriterBase* writer) {
+    bool queueChanged = false;
+    uint32_t commandLength = 0;
+    hidl_vec<hidl_handle> commandHandles;
+    ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
+
+    if (queueChanged) {
+        auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor());
+        ASSERT_EQ(V2_1::Error::NONE, ret);
+    }
+
+    mClient->executeCommands_2_3(
+            commandLength, commandHandles,
+            [&](const auto& tmpError, const auto& tmpOutQueueChanged, const auto& tmpOutLength,
+                const auto& tmpOutHandles) {
+                ASSERT_EQ(V2_1::Error::NONE, tmpError);
+
+                if (tmpOutQueueChanged) {
+                    mClient->getOutputCommandQueue(
+                            [&](const auto& tmpError, const auto& tmpDescriptor) {
+                                ASSERT_EQ(V2_3::Error::NONE, tmpError);
+                                reader->setMQDescriptor(tmpDescriptor);
+                            });
+                }
+
+                ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
+                reader->parse();
+            });
+    reader->reset();
+    writer->reset();
+}
+
 }  // namespace vts
 }  // namespace V2_4
 }  // namespace composer
diff --git a/graphics/composer/2.4/utils/vts/TestCommandReader.cpp b/graphics/composer/2.4/utils/vts/TestCommandReader.cpp
new file mode 100644
index 0000000..a1ca628
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/TestCommandReader.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <composer-vts/2.4/TestCommandReader.h>
+
+#include <gtest/gtest.h>
+
+namespace android::hardware::graphics::composer::V2_4::vts {
+
+void TestCommandReader::parseSingleCommand(int32_t commandRaw, uint16_t length) {
+    IComposerClient::Command command = static_cast<IComposerClient::Command>(commandRaw);
+
+    switch (command) {
+        case IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY:
+            ASSERT_EQ(2, length);
+            read();
+            close(readFence());
+            break;
+        default:
+            return android::hardware::graphics::composer::V2_1::vts::TestCommandReader::
+                    parseSingleCommand(commandRaw, length);
+    }
+}
+
+}  // namespace android::hardware::graphics::composer::V2_4::vts
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
index 3dd8e50..28e17b4 100644
--- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -19,10 +19,10 @@
 #include <memory>
 #include <vector>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android/hardware/graphics/composer/2.4/IComposer.h>
 #include <android/hardware/graphics/composer/2.4/IComposerClient.h>
 #include <composer-vts/2.3/ComposerVts.h>
+#include <composer-vts/2.4/TestCommandReader.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -93,6 +93,8 @@
 
     Error setContentType(Display display, IComposerClient::ContentType contentType);
 
+    void execute(TestCommandReader* reader, CommandWriterBase* writer);
+
     Error getLayerGenericMetadataKeys(
             std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys);
 
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/TestCommandReader.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/TestCommandReader.h
new file mode 100644
index 0000000..5736fa6
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/TestCommandReader.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+
+namespace android::hardware::graphics::composer::V2_4::vts {
+
+// A command parser that checks that no error nor unexpected commands are
+// returned.
+class TestCommandReader
+    : public android::hardware::graphics::composer::V2_1::vts::TestCommandReader {
+  protected:
+    void parseSingleCommand(int32_t commandRaw, uint16_t length) override;
+};
+
+}  // namespace android::hardware::graphics::composer::V2_4::vts
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index f6b46ff..b6343d3 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -23,9 +23,9 @@
 #include <android-base/logging.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
-#include <composer-vts/2.1/TestCommandReader.h>
 #include <composer-vts/2.4/ComposerVts.h>
 #include <composer-vts/2.4/GraphicsComposerCallback.h>
+#include <composer-vts/2.4/TestCommandReader.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -42,6 +42,8 @@
 namespace vts {
 namespace {
 
+using namespace std::chrono_literals;
+
 using common::V1_0::BufferUsage;
 using common::V1_1::RenderIntent;
 using common::V1_2::ColorMode;
@@ -75,7 +77,7 @@
         mComposerCallback->setVsyncAllowed(false);
 
         mWriter = std::make_unique<CommandWriterBase>(1024);
-        mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+        mReader = std::make_unique<TestCommandReader>();
     }
 
     void TearDown() override {
@@ -151,7 +153,7 @@
     Display mPrimaryDisplay;
     Display mInvalidDisplayId;
     std::unique_ptr<CommandWriterBase> mWriter;
-    std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+    std::unique_ptr<TestCommandReader> mReader;
 
   private:
     Display waitForFirstDisplay() {
@@ -182,7 +184,7 @@
                 mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT);
 
         mWriter = std::make_unique<CommandWriterBase>(1024);
-        mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+        mReader = std::make_unique<TestCommandReader>();
     }
 
     void TearDown() override {
@@ -209,7 +211,7 @@
                                   int64_t newPeriodNanos);
 
     std::unique_ptr<CommandWriterBase> mWriter;
-    std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+    std::unique_ptr<TestCommandReader> mReader;
     int32_t mDisplayWidth;
     int32_t mDisplayHeight;
 
@@ -526,7 +528,7 @@
             EXPECT_EQ(Error::UNSUPPORTED,
                       mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
             GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display "
-                            << to_string(display) << ", skipping test";
+                            << std::to_string(display) << ", skipping test";
             return;
         }
 
@@ -580,7 +582,7 @@
     if (!contentTypeSupport) {
         EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setContentType(display, contentType));
         GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display "
-                        << to_string(display) << ", skipping test";
+                        << std::to_string(display) << ", skipping test";
         return;
     }
 
@@ -626,7 +628,7 @@
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
         android::hardware::PrintInstanceNameToString);
 
-TEST_F(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
+TEST_P(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
     std::vector<IComposerClient::LayerGenericMetadataKey> keys;
     mComposerClient->getLayerGenericMetadataKeys(&keys);
 
diff --git a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h
index 8540068..13df3bc 100644
--- a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h
+++ b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h
@@ -49,7 +49,12 @@
                  mModule, bufferHandle, descriptorInfo.width, descriptorInfo.height,
                  static_cast<int32_t>(descriptorInfo.format),
                  static_cast<uint64_t>(descriptorInfo.usage), stride);
-         return static_cast<Error>(ret);
+         if (ret == -EINVAL) {
+             return Error::BAD_BUFFER;
+         } else if (ret < 0) {
+             return Error::BAD_VALUE;
+         }
+         return Error::NONE;
      }
      Error getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
                             uint32_t* outNumInts) override {
diff --git a/health/2.0/default/Health.cpp b/health/2.0/default/Health.cpp
index 4225fd8..65eada8 100644
--- a/health/2.0/default/Health.cpp
+++ b/health/2.0/default/Health.cpp
@@ -156,7 +156,7 @@
     const HealthInfo_1_0& health_info = battery_monitor_->getHealthInfo_1_0();
     struct BatteryProperties props;
     convertFromHealthInfo(health_info, &props);
-    bool log = healthd_board_battery_update(&props);
+    bool log = (healthd_board_battery_update(&props) == 0);
     if (log) {
         battery_monitor_->logValues();
     }
diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
index 49891b7..352a990 100644
--- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
+++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
@@ -315,9 +315,7 @@
 TEST_P(HealthHidlTest, getChargeStatus) {
     SKIP_IF_SKIPPED();
     EXPECT_OK(mHealth->getChargeStatus([](auto result, auto value) {
-        EXPECT_VALID_OR_UNSUPPORTED_PROP(
-            result, toString(value),
-            value != BatteryStatus::UNKNOWN && verifyEnum<BatteryStatus>(value));
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyEnum<BatteryStatus>(value));
     }));
 }
 
diff --git a/health/2.1/README.md b/health/2.1/README.md
index bfcf13b..8390570 100644
--- a/health/2.1/README.md
+++ b/health/2.1/README.md
@@ -24,6 +24,9 @@
         ```mk
         # Install default passthrough implementation to vendor.
         PRODUCT_PACKAGES += android.hardware.health@2.1-impl
+
+        # For non-A/B devices, install default passthrough implementation to recovery.
+        PRODUCT_PACKAGES += android.hardware.health@2.1-impl.recovery
         ```
 
         You are done. Otherwise, go to the next step.
@@ -42,6 +45,8 @@
               implementation, See
               [Upgrading from Health HAL 2.0](#update-from-2-0).
 
+        1. [Install the implementation](#install).
+
         1. [Update necessary SELinux permissions](#selinux).
 
         1. [Fix `/charger` symlink](#charger-symlink).
@@ -95,15 +100,22 @@
   `HealthImpl::getHealthInfo` or `HealthImpl::getHealthInfo_2_1` because they call
   `getDiskStats` and `getStorageInfo` to retrieve storage information.
 
+# Install the implementation {#install}
+
+In `device.mk`:
+
+```mk
+# Install the passthrough implementation to vendor.
+PRODUCT_PACKAGES += android.hardware.health@2.1-impl-<device>
+
+# For non-A/B devices, also install the passthrough implementation to recovery.
+PRODUCT_PACKAGES += android.hardware.health@2.1-impl-<device>.recovery
+```
+
 # Update necessary SELinux permissions {#selinux}
 
 For example (replace `<device>` with the device name):
 ```
-# device/<manufacturer>/<device>/sepolicy/vendor/file_contexts
-# Required for charger to open passthrough implementation. Replace <device> with the proper device
-# name. File name must be consistent with `stem` of the implementation module.
-/vendor/lib(64)?/hw/android\.hardware\.health@2\.0-impl-2\.1-<device>\.so u:object_r:same_process_hal_file:s0
-
 # device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
 # Add device specific permissions to hal_health_default domain, especially
 # if a device-specific libhealthd is used and/or device-specific storage related
diff --git a/health/2.1/default/android.hardware.health@2.1-service.rc b/health/2.1/default/android.hardware.health@2.1-service.rc
index 917f1c2..b6d9e3b 100644
--- a/health/2.1/default/android.hardware.health@2.1-service.rc
+++ b/health/2.1/default/android.hardware.health@2.1-service.rc
@@ -1,5 +1,5 @@
 service health-hal-2-1 /vendor/bin/hw/android.hardware.health@2.1-service
-    class hal
+    class hal charger
     user system
     group system
     capabilities WAKE_ALARM
diff --git a/health/2.1/types.hal b/health/2.1/types.hal
index efd8d6f..d775491 100644
--- a/health/2.1/types.hal
+++ b/health/2.1/types.hal
@@ -19,6 +19,10 @@
 import @1.0::HealthConfig;
 import @2.0::HealthInfo;
 
+enum Constants : int64_t {
+    BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED = -1,
+};
+
 /**
  * Battery capacity level. This enum provides additional information along side
  * with the battery capacity.
@@ -27,11 +31,17 @@
  */
 enum BatteryCapacityLevel : int32_t {
     /**
+     * Battery capacity level is unsupported.
+     * Battery capacity level must be set to this value if and only if the
+     * implementation is unsupported.
+     */
+    UNSUPPORTED = -1,
+    /**
      * Battery capacity level is unknown.
      * Battery capacity level must be set to this value if and only if battery
-     * is not present.
+     * is not present or the battery capacity level is unknown/uninitialized.
      */
-    UNKNOWN = 0,
+    UNKNOWN,
     /**
      * Battery is at critical level. The Android framework must schedule a
      * shutdown when it sees this value from the HAL.
@@ -78,18 +88,21 @@
 
     /**
      * Estimated time to fully charge the device (in seconds).
+     * Value must be BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED if and
+     * only if the implementation is unsupported.
      * Value must be 0 if and only if batteryCapacityLevel is FULL or UNKNOWN.
      * Otherwise, value must be positive.
      */
     int64_t batteryChargeTimeToFullNowSeconds;
 
     /**
-     * Estimated battery full capacity (in microamp hours, uAh).
+     * Estimated battery full charge design capacity (in microamp hours, uAh).
      * Value must be 0 if unknown.
-     * Value must be positive if known, and must be between [50%, 120%] of
-     * batteryFullCharge (the designed capacity).
+     * Value must be positive if known.
+     * Value must be greater than 100 000 uAh.
+     * Value must be less than 100 000 000 uAh.
      */
-    int32_t batteryFullCapacityUah;
+    int32_t batteryFullChargeDesignCapacityUah;
 };
 
 /**
diff --git a/health/2.1/vts/functional/Android.bp b/health/2.1/vts/functional/Android.bp
index 5aa873a..17472fa 100644
--- a/health/2.1/vts/functional/Android.bp
+++ b/health/2.1/vts/functional/Android.bp
@@ -25,5 +25,8 @@
         "android.hardware.health@2.0",
         "android.hardware.health@2.1",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp b/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
index da9f5bb..deb1a29 100644
--- a/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
+++ b/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
@@ -219,6 +219,9 @@
     return AssertionFailure() << static_cast<std::underlying_type_t<T>>(value) << " is not valid";
 }
 
+#define FULL_CHARGE_DESIGN_CAP_MIN ((long)100 * 1000)
+#define FULL_CHARGE_DESIGN_CAP_MAX ((long)100000 * 1000)
+
 /*
  * Tests the values returned by getHealthInfo() from interface IHealth.
  */
@@ -228,14 +231,18 @@
             return;
         }
         ASSERT_EQ(Result::SUCCESS, result);
-        const auto& legacy = value.legacy.legacy;
 
         EXPECT_TRUE(IsEnum(value.batteryCapacityLevel)) << " BatteryCapacityLevel";
         EXPECT_GE(value.batteryChargeTimeToFullNowSeconds, 0);
 
-        EXPECT_GE(value.batteryFullCapacityUah, 0) << "batteryFullCapacityUah is unknown";
-        EXPECT_GE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 0.50);
-        EXPECT_LE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 1.20);
+        EXPECT_GE(value.batteryFullChargeDesignCapacityUah, 0)
+                << "batteryFullChargeDesignCapacityUah should not be negative";
+
+        EXPECT_GT((long)value.batteryFullChargeDesignCapacityUah, FULL_CHARGE_DESIGN_CAP_MIN)
+                << "batteryFullChargeDesignCapacityUah should be greater than 100 mAh";
+
+        EXPECT_LT((long)value.batteryFullChargeDesignCapacityUah, FULL_CHARGE_DESIGN_CAP_MAX)
+                << "batteryFullChargeDesignCapacityUah should be less than 100,000 mAh";
     })));
 }
 
diff --git a/health/storage/1.0/vts/functional/Android.bp b/health/storage/1.0/vts/functional/Android.bp
index a30cdde..4c703c5 100644
--- a/health/storage/1.0/vts/functional/Android.bp
+++ b/health/storage/1.0/vts/functional/Android.bp
@@ -22,6 +22,9 @@
     shared_libs: [
         "libhidlbase",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+    test_config: "VtsHalHealthStorageV1_0TargetTest.config",
 }
-
diff --git a/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.config b/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.config
new file mode 100644
index 0000000..0cd1c11
--- /dev/null
+++ b/health/storage/1.0/vts/functional/VtsHalHealthStorageV1_0TargetTest.config
@@ -0,0 +1,33 @@
+<?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 VtsHalHealthStorageV1_0TargetTest.">
+    <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="VtsHalHealthStorageV1_0TargetTest->/data/local/tmp/VtsHalHealthStorageV1_0TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalHealthStorageV1_0TargetTest" />
+        <option name="native-test-timeout" value="3m" />
+    </test>
+</configuration>
diff --git a/health/utils/libhealthloop/utils.cpp b/health/utils/libhealthloop/utils.cpp
index ebfd8d8..053fd19 100644
--- a/health/utils/libhealthloop/utils.cpp
+++ b/health/utils/libhealthloop/utils.cpp
@@ -42,6 +42,7 @@
             .batteryCycleCountPath = String8(String8::kEmptyString),
             .batteryCapacityLevelPath = String8(String8::kEmptyString),
             .batteryChargeTimeToFullNowPath = String8(String8::kEmptyString),
+            .batteryFullChargeDesignCapacityUahPath = String8(String8::kEmptyString),
             .energyCounter = NULL,
             .boot_min_cap = 0,
             .screen_on = NULL,
diff --git a/identity/1.0/Android.bp b/identity/1.0/Android.bp
deleted file mode 100644
index e0a6332..0000000
--- a/identity/1.0/Android.bp
+++ /dev/null
@@ -1,20 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-hidl_interface {
-    name: "android.hardware.identity@1.0",
-    root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
-    srcs: [
-        "types.hal",
-        "IIdentityCredential.hal",
-        "IIdentityCredentialStore.hal",
-        "IWritableIdentityCredential.hal",
-    ],
-    interfaces: [
-        "android.hardware.keymaster@4.0",
-        "android.hidl.base@1.0",
-    ],
-    gen_java: false,
-}
diff --git a/identity/1.0/default/Android.bp b/identity/1.0/default/Android.bp
deleted file mode 100644
index d2b2966..0000000
--- a/identity/1.0/default/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_binary {
-    name: "android.hardware.identity@1.0-service.example",
-    init_rc: ["android.hardware.identity@1.0-service.example.rc"],
-    vendor: true,
-    relative_install_path: "hw",
-    cflags: [
-        "-Wall",
-        "-Wextra",
-    ],
-    srcs: [
-        "service.cpp",
-        "IdentityCredential.cpp",
-        "IdentityCredentialStore.cpp",
-        "WritableIdentityCredential.cpp",
-    ],
-    shared_libs: [
-        "android.hardware.identity@1.0",
-        "android.hardware.identity-support-lib",
-        "android.hardware.keymaster@4.0",
-        "libcppbor",
-        "libcrypto",
-        "libbase",
-        "libhidlbase",
-        "liblog",
-        "libutils",
-    ],
-}
diff --git a/identity/1.0/default/IdentityCredential.cpp b/identity/1.0/default/IdentityCredential.cpp
deleted file mode 100644
index b0a5e56..0000000
--- a/identity/1.0/default/IdentityCredential.cpp
+++ /dev/null
@@ -1,773 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "IdentityCredential"
-
-#include "IdentityCredential.h"
-#include "IdentityCredentialStore.h"
-
-#include <android/hardware/identity/support/IdentityCredentialSupport.h>
-
-#include <string.h>
-
-#include <android-base/logging.h>
-
-#include <cppbor.h>
-#include <cppbor_parse.h>
-
-namespace android {
-namespace hardware {
-namespace identity {
-namespace implementation {
-
-using ::android::hardware::keymaster::V4_0::Timestamp;
-using ::std::optional;
-
-Return<void> IdentityCredential::deleteCredential(deleteCredential_cb _hidl_cb) {
-    cppbor::Array array = {"ProofOfDeletion", docType_, testCredential_};
-    vector<uint8_t> proofOfDeletion = array.encode();
-
-    optional<vector<uint8_t>> proofOfDeletionSignature =
-            support::coseSignEcDsa(credentialPrivKey_,
-                                   proofOfDeletion,  // payload
-                                   {},               // additionalData
-                                   {});              // certificateChain
-    if (!proofOfDeletionSignature) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error signing data"), {});
-        return Void();
-    }
-
-    _hidl_cb(support::resultOK(), proofOfDeletionSignature.value());
-    return Void();
-}
-
-Return<void> IdentityCredential::createEphemeralKeyPair(createEphemeralKeyPair_cb _hidl_cb) {
-    optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
-    if (!keyPair) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error creating ephemeral key pair"), {});
-        return Void();
-    }
-
-    // Stash public key of this key-pair for later check in startRetrieval().
-    optional<vector<uint8_t>> publicKey = support::ecKeyPairGetPublicKey(keyPair.value());
-    if (!publicKey) {
-        _hidl_cb(support::result(ResultCode::FAILED,
-                                 "Error getting public part of ephemeral key pair"),
-                 {});
-        return Void();
-    }
-    ephemeralPublicKey_ = publicKey.value();
-
-    _hidl_cb(support::resultOK(), keyPair.value());
-    return Void();
-}
-
-Return<void> IdentityCredential::setReaderEphemeralPublicKey(
-        const hidl_vec<uint8_t>& publicKey, setReaderEphemeralPublicKey_cb _hidl_cb) {
-    readerPublicKey_ = publicKey;
-    _hidl_cb(support::resultOK());
-    return Void();
-}
-
-ResultCode IdentityCredential::initialize() {
-    auto [item, _, message] = cppbor::parse(credentialData_);
-    if (item == nullptr) {
-        LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
-        return ResultCode::INVALID_DATA;
-    }
-
-    const cppbor::Array* arrayItem = item->asArray();
-    if (arrayItem == nullptr || arrayItem->size() != 3) {
-        LOG(ERROR) << "CredentialData is not an array with three elements";
-        return ResultCode::INVALID_DATA;
-    }
-
-    const cppbor::Tstr* docTypeItem = (*arrayItem)[0]->asTstr();
-    const cppbor::Bool* testCredentialItem =
-            ((*arrayItem)[1]->asSimple() != nullptr ? ((*arrayItem)[1]->asSimple()->asBool())
-                                                    : nullptr);
-    const cppbor::Bstr* encryptedCredentialKeysItem = (*arrayItem)[2]->asBstr();
-    if (docTypeItem == nullptr || testCredentialItem == nullptr ||
-        encryptedCredentialKeysItem == nullptr) {
-        LOG(ERROR) << "CredentialData unexpected item types";
-        return ResultCode::INVALID_DATA;
-    }
-
-    docType_ = docTypeItem->value();
-    testCredential_ = testCredentialItem->value();
-
-    vector<uint8_t> hardwareBoundKey;
-    if (testCredential_) {
-        hardwareBoundKey = support::getTestHardwareBoundKey();
-    } else {
-        hardwareBoundKey = support::getHardwareBoundKey();
-    }
-
-    const vector<uint8_t>& encryptedCredentialKeys = encryptedCredentialKeysItem->value();
-    const vector<uint8_t> docTypeVec(docType_.begin(), docType_.end());
-    optional<vector<uint8_t>> decryptedCredentialKeys =
-            support::decryptAes128Gcm(hardwareBoundKey, encryptedCredentialKeys, docTypeVec);
-    if (!decryptedCredentialKeys) {
-        LOG(ERROR) << "Error decrypting CredentialKeys";
-        return ResultCode::INVALID_DATA;
-    }
-
-    auto [dckItem, dckPos, dckMessage] = cppbor::parse(decryptedCredentialKeys.value());
-    if (dckItem == nullptr) {
-        LOG(ERROR) << "Decrypted CredentialKeys is not valid CBOR: " << dckMessage;
-        return ResultCode::INVALID_DATA;
-    }
-    const cppbor::Array* dckArrayItem = dckItem->asArray();
-    if (dckArrayItem == nullptr || dckArrayItem->size() != 2) {
-        LOG(ERROR) << "Decrypted CredentialKeys is not an array with two elements";
-        return ResultCode::INVALID_DATA;
-    }
-    const cppbor::Bstr* storageKeyItem = (*dckArrayItem)[0]->asBstr();
-    const cppbor::Bstr* credentialPrivKeyItem = (*dckArrayItem)[1]->asBstr();
-    if (storageKeyItem == nullptr || credentialPrivKeyItem == nullptr) {
-        LOG(ERROR) << "CredentialKeys unexpected item types";
-        return ResultCode::INVALID_DATA;
-    }
-    storageKey_ = storageKeyItem->value();
-    credentialPrivKey_ = credentialPrivKeyItem->value();
-
-    return ResultCode::OK;
-}
-
-Return<void> IdentityCredential::createAuthChallenge(createAuthChallenge_cb _hidl_cb) {
-    uint64_t challenge = 0;
-    while (challenge == 0) {
-        optional<vector<uint8_t>> bytes = support::getRandom(8);
-        if (!bytes) {
-            _hidl_cb(support::result(ResultCode::FAILED, "Error getting random data for challenge"),
-                     0);
-            return Void();
-        }
-
-        challenge = 0;
-        for (size_t n = 0; n < bytes.value().size(); n++) {
-            challenge |= ((bytes.value())[n] << (n * 8));
-        }
-    }
-
-    authChallenge_ = challenge;
-    _hidl_cb(support::resultOK(), challenge);
-    return Void();
-}
-
-// TODO: this could be a lot faster if we did all the splitting and pubkey extraction
-// ahead of time.
-bool checkReaderAuthentication(const SecureAccessControlProfile& profile,
-                               const vector<uint8_t>& readerCertificateChain) {
-    optional<vector<uint8_t>> acpPubKey =
-            support::certificateChainGetTopMostKey(profile.readerCertificate);
-    if (!acpPubKey) {
-        LOG(ERROR) << "Error extracting public key from readerCertificate in profile";
-        return false;
-    }
-
-    optional<vector<vector<uint8_t>>> certificatesInChain =
-            support::certificateChainSplit(readerCertificateChain);
-    if (!certificatesInChain) {
-        LOG(ERROR) << "Error splitting readerCertificateChain";
-        return false;
-    }
-    for (const vector<uint8_t>& certInChain : certificatesInChain.value()) {
-        optional<vector<uint8_t>> certPubKey = support::certificateChainGetTopMostKey(certInChain);
-        if (!certPubKey) {
-            LOG(ERROR)
-                    << "Error extracting public key from certificate in chain presented by reader";
-            return false;
-        }
-        if (acpPubKey.value() == certPubKey.value()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-Timestamp clockGetTime() {
-    struct timespec time;
-    clock_gettime(CLOCK_MONOTONIC, &time);
-    return time.tv_sec * 1000 + time.tv_nsec / 1000000;
-}
-
-bool checkUserAuthentication(const SecureAccessControlProfile& profile,
-                             const HardwareAuthToken& authToken, uint64_t authChallenge) {
-    if (profile.secureUserId != authToken.userId) {
-        LOG(ERROR) << "secureUserId in profile (" << profile.secureUserId
-                   << ") differs from userId in authToken (" << authToken.userId << ")";
-        return false;
-    }
-
-    if (profile.timeoutMillis == 0) {
-        if (authToken.challenge == 0) {
-            LOG(ERROR) << "No challenge in authToken";
-            return false;
-        }
-
-        if (authToken.challenge != authChallenge) {
-            LOG(ERROR) << "Challenge in authToken doesn't match the challenge we created";
-            return false;
-        }
-        return true;
-    }
-
-    // Note that the Epoch for timestamps in HardwareAuthToken is at the
-    // discretion of the vendor:
-    //
-    //   "[...] since some starting point (generally the most recent device
-    //    boot) which all of the applications within one secure environment
-    //    must agree upon."
-    //
-    // Therefore, if this software implementation is used on a device which isn't
-    // the emulator then the assumption that the epoch is the same as used in
-    // clockGetTime above will not hold. This is OK as this software
-    // implementation should never be used on a real device.
-    //
-    Timestamp now = clockGetTime();
-    if (authToken.timestamp > now) {
-        LOG(ERROR) << "Timestamp in authToken (" << authToken.timestamp
-                   << ") is in the future (now: " << now << ")";
-        return false;
-    }
-    if (now > authToken.timestamp + profile.timeoutMillis) {
-        LOG(ERROR) << "Deadline for authToken (" << authToken.timestamp << " + "
-                   << profile.timeoutMillis << " = "
-                   << (authToken.timestamp + profile.timeoutMillis)
-                   << ") is in the past (now: " << now << ")";
-        return false;
-    }
-
-    return true;
-}
-
-Return<void> IdentityCredential::startRetrieval(
-        const hidl_vec<SecureAccessControlProfile>& accessControlProfiles,
-        const HardwareAuthToken& authToken, const hidl_vec<uint8_t>& itemsRequest,
-        const hidl_vec<uint8_t>& sessionTranscript, const hidl_vec<uint8_t>& readerSignature,
-        const hidl_vec<uint16_t>& requestCounts, startRetrieval_cb _hidl_cb) {
-    if (sessionTranscript.size() > 0) {
-        auto [item, _, message] = cppbor::parse(sessionTranscript);
-        if (item == nullptr) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                     "SessionTranscript contains invalid CBOR"));
-            return Void();
-        }
-        sessionTranscriptItem_ = std::move(item);
-    }
-    if (numStartRetrievalCalls_ > 0) {
-        if (sessionTranscript_ != vector<uint8_t>(sessionTranscript)) {
-            _hidl_cb(support::result(
-                    ResultCode::SESSION_TRANSCRIPT_MISMATCH,
-                    "Passed-in SessionTranscript doesn't match previously used SessionTranscript"));
-            return Void();
-        }
-    }
-    sessionTranscript_ = sessionTranscript;
-
-    // If there is a signature, validate that it was made with the top-most key in the
-    // certificate chain embedded in the COSE_Sign1 structure.
-    optional<vector<uint8_t>> readerCertificateChain;
-    if (readerSignature.size() > 0) {
-        readerCertificateChain = support::coseSignGetX5Chain(readerSignature);
-        if (!readerCertificateChain) {
-            _hidl_cb(support::result(ResultCode::READER_SIGNATURE_CHECK_FAILED,
-                                     "Unable to get reader certificate chain from COSE_Sign1"));
-            return Void();
-        }
-
-        if (!support::certificateChainValidate(readerCertificateChain.value())) {
-            _hidl_cb(support::result(ResultCode::READER_SIGNATURE_CHECK_FAILED,
-                                     "Error validating reader certificate chain"));
-            return Void();
-        }
-
-        optional<vector<uint8_t>> readerPublicKey =
-                support::certificateChainGetTopMostKey(readerCertificateChain.value());
-        if (!readerPublicKey) {
-            _hidl_cb(support::result(ResultCode::READER_SIGNATURE_CHECK_FAILED,
-                                     "Unable to get public key from reader certificate chain"));
-            return Void();
-        }
-
-        const vector<uint8_t>& itemsRequestBytes = itemsRequest;
-        vector<uint8_t> dataThatWasSigned = cppbor::Array()
-                                                    .add("ReaderAuthentication")
-                                                    .add(sessionTranscriptItem_->clone())
-                                                    .add(cppbor::Semantic(24, itemsRequestBytes))
-                                                    .encode();
-        if (!support::coseCheckEcDsaSignature(readerSignature,
-                                              dataThatWasSigned,  // detached content
-                                              readerPublicKey.value())) {
-            _hidl_cb(support::result(ResultCode::READER_SIGNATURE_CHECK_FAILED,
-                                     "readerSignature check failed"));
-            return Void();
-        }
-    }
-
-    // Here's where we would validate the passed-in |authToken| to assure ourselves
-    // that it comes from the e.g. biometric hardware and wasn't made up by an attacker.
-    //
-    // However this involves calculating the MAC. However this requires access
-    // to the key needed to a pre-shared key which we don't have...
-    //
-
-    // To prevent replay-attacks, we check that the public part of the ephemeral
-    // key we previously created, is present in the DeviceEngagement part of
-    // SessionTranscript as a COSE_Key, in uncompressed form.
-    //
-    // We do this by just searching for the X and Y coordinates.
-    if (sessionTranscript.size() > 0) {
-        const cppbor::Array* array = sessionTranscriptItem_->asArray();
-        if (array == nullptr || array->size() != 2) {
-            _hidl_cb(support::result(ResultCode::EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
-                                     "SessionTranscript is not an array with two items"));
-            return Void();
-        }
-        const cppbor::Semantic* taggedEncodedDE = (*array)[0]->asSemantic();
-        if (taggedEncodedDE == nullptr || taggedEncodedDE->value() != 24) {
-            _hidl_cb(support::result(ResultCode::EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
-                                     "First item in SessionTranscript array is not a "
-                                     "semantic with value 24"));
-            return Void();
-        }
-        const cppbor::Bstr* encodedDE = (taggedEncodedDE->child())->asBstr();
-        if (encodedDE == nullptr) {
-            _hidl_cb(support::result(ResultCode::EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
-                                     "Child of semantic in first item in SessionTranscript "
-                                     "array is not a bstr"));
-            return Void();
-        }
-        const vector<uint8_t>& bytesDE = encodedDE->value();
-
-        auto [getXYSuccess, ePubX, ePubY] = support::ecPublicKeyGetXandY(ephemeralPublicKey_);
-        if (!getXYSuccess) {
-            _hidl_cb(support::result(ResultCode::EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
-                                     "Error extracting X and Y from ePub"));
-            return Void();
-        }
-        if (sessionTranscript.size() > 0 &&
-            !(memmem(bytesDE.data(), bytesDE.size(), ePubX.data(), ePubX.size()) != nullptr &&
-              memmem(bytesDE.data(), bytesDE.size(), ePubY.data(), ePubY.size()) != nullptr)) {
-            _hidl_cb(support::result(ResultCode::EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
-                                     "Did not find ephemeral public key's X and Y coordinates in "
-                                     "SessionTranscript (make sure leading zeroes are not used)"));
-            return Void();
-        }
-    }
-
-    // itemsRequest: If non-empty, contains request data that may be signed by the
-    // reader.  The content can be defined in the way appropriate for the
-    // credential, but there are three requirements that must be met to work with
-    // this HAL:
-    if (itemsRequest.size() > 0) {
-        // 1. The content must be a CBOR-encoded structure.
-        auto [item, _, message] = cppbor::parse(itemsRequest);
-        if (item == nullptr) {
-            _hidl_cb(support::result(ResultCode::INVALID_ITEMS_REQUEST_MESSAGE,
-                                     "Error decoding CBOR in itemsRequest: %s", message.c_str()));
-            return Void();
-        }
-
-        // 2. The CBOR structure must be a map.
-        const cppbor::Map* map = item->asMap();
-        if (map == nullptr) {
-            _hidl_cb(support::result(ResultCode::INVALID_ITEMS_REQUEST_MESSAGE,
-                                     "itemsRequest is not a CBOR map"));
-            return Void();
-        }
-
-        // 3. The map must contain a key "nameSpaces" whose value contains a map, as described in
-        //    the example below.
-        //
-        //   NameSpaces = {
-        //     + NameSpace => DataElements ; Requested data elements for each NameSpace
-        //   }
-        //
-        //   NameSpace = tstr
-        //
-        //   DataElements = {
-        //     + DataElement => IntentToRetain
-        //   }
-        //
-        //   DataElement = tstr
-        //   IntentToRetain = bool
-        //
-        // Here's an example of an |itemsRequest| CBOR value satisfying above requirements 1.
-        // through 3.:
-        //
-        //    {
-        //        'docType' : 'org.iso.18013-5.2019',
-        //        'nameSpaces' : {
-        //            'org.iso.18013-5.2019' : {
-        //                'Last name' : false,
-        //                'Birth date' : false,
-        //                'First name' : false,
-        //                'Home address' : true
-        //            },
-        //            'org.aamva.iso.18013-5.2019' : {
-        //                'Real Id' : false
-        //            }
-        //        }
-        //    }
-        //
-        const cppbor::Map* nsMap = nullptr;
-        for (size_t n = 0; n < map->size(); n++) {
-            const auto& [keyItem, valueItem] = (*map)[n];
-            if (keyItem->type() == cppbor::TSTR && keyItem->asTstr()->value() == "nameSpaces" &&
-                valueItem->type() == cppbor::MAP) {
-                nsMap = valueItem->asMap();
-                break;
-            }
-        }
-        if (nsMap == nullptr) {
-            _hidl_cb(support::result(ResultCode::INVALID_ITEMS_REQUEST_MESSAGE,
-                                     "No nameSpaces map in top-most map"));
-            return Void();
-        }
-
-        for (size_t n = 0; n < nsMap->size(); n++) {
-            auto [nsKeyItem, nsValueItem] = (*nsMap)[n];
-            const cppbor::Tstr* nsKey = nsKeyItem->asTstr();
-            const cppbor::Map* nsInnerMap = nsValueItem->asMap();
-            if (nsKey == nullptr || nsInnerMap == nullptr) {
-                _hidl_cb(support::result(ResultCode::INVALID_ITEMS_REQUEST_MESSAGE,
-                                         "Type mismatch in nameSpaces map"));
-                return Void();
-            }
-            string requestedNamespace = nsKey->value();
-            vector<string> requestedKeys;
-            for (size_t m = 0; m < nsInnerMap->size(); m++) {
-                const auto& [innerMapKeyItem, innerMapValueItem] = (*nsInnerMap)[m];
-                const cppbor::Tstr* nameItem = innerMapKeyItem->asTstr();
-                const cppbor::Simple* simple = innerMapValueItem->asSimple();
-                const cppbor::Bool* intentToRetainItem =
-                        (simple != nullptr) ? simple->asBool() : nullptr;
-                if (nameItem == nullptr || intentToRetainItem == nullptr) {
-                    _hidl_cb(support::result(ResultCode::INVALID_ITEMS_REQUEST_MESSAGE,
-                                             "Type mismatch in value in nameSpaces map"));
-                    return Void();
-                }
-                requestedKeys.push_back(nameItem->value());
-            }
-            requestedNameSpacesAndNames_[requestedNamespace] = requestedKeys;
-        }
-    }
-
-    // Finally, validate all the access control profiles in the requestData.
-    bool haveAuthToken = (authToken.mac.size() > 0);
-    for (const auto& profile : accessControlProfiles) {
-        if (!support::secureAccessControlProfileCheckMac(profile, storageKey_)) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                     "Error checking MAC for profile with id %d", int(profile.id)));
-            return Void();
-        }
-        ResultCode accessControlCheck = ResultCode::OK;
-        if (profile.userAuthenticationRequired) {
-            if (!haveAuthToken || !checkUserAuthentication(profile, authToken, authChallenge_)) {
-                accessControlCheck = ResultCode::USER_AUTHENTICATION_FAILED;
-            }
-        } else if (profile.readerCertificate.size() > 0) {
-            if (!readerCertificateChain ||
-                !checkReaderAuthentication(profile, readerCertificateChain.value())) {
-                accessControlCheck = ResultCode::READER_AUTHENTICATION_FAILED;
-            }
-        }
-        profileIdToAccessCheckResult_[profile.id] = accessControlCheck;
-    }
-
-    deviceNameSpacesMap_ = cppbor::Map();
-    currentNameSpaceDeviceNameSpacesMap_ = cppbor::Map();
-
-    requestCountsRemaining_ = requestCounts;
-    currentNameSpace_ = "";
-
-    itemsRequest_ = itemsRequest;
-
-    numStartRetrievalCalls_ += 1;
-    _hidl_cb(support::resultOK());
-    return Void();
-}
-
-Return<void> IdentityCredential::startRetrieveEntryValue(
-        const hidl_string& nameSpace, const hidl_string& name, uint32_t entrySize,
-        const hidl_vec<uint16_t>& accessControlProfileIds, startRetrieveEntryValue_cb _hidl_cb) {
-    if (name.empty()) {
-        _hidl_cb(support::result(ResultCode::INVALID_DATA, "Name cannot be empty"));
-        return Void();
-    }
-    if (nameSpace.empty()) {
-        _hidl_cb(support::result(ResultCode::INVALID_DATA, "Name space cannot be empty"));
-        return Void();
-    }
-
-    if (requestCountsRemaining_.size() == 0) {
-        _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                 "No more name spaces left to go through"));
-        return Void();
-    }
-
-    if (currentNameSpace_ == "") {
-        // First call.
-        currentNameSpace_ = nameSpace;
-    }
-
-    if (nameSpace == currentNameSpace_) {
-        // Same namespace.
-        if (requestCountsRemaining_[0] == 0) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                     "No more entries to be retrieved in current name space"));
-            return Void();
-        }
-        requestCountsRemaining_[0] -= 1;
-    } else {
-        // New namespace.
-        if (requestCountsRemaining_[0] != 0) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                     "Moved to new name space but %d entries need to be retrieved "
-                                     "in current name space",
-                                     int(requestCountsRemaining_[0])));
-            return Void();
-        }
-        if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) {
-            deviceNameSpacesMap_.add(currentNameSpace_,
-                                     std::move(currentNameSpaceDeviceNameSpacesMap_));
-        }
-        currentNameSpaceDeviceNameSpacesMap_ = cppbor::Map();
-
-        requestCountsRemaining_.erase(requestCountsRemaining_.begin());
-        currentNameSpace_ = nameSpace;
-    }
-
-    // It's permissible to have an empty itemsRequest... but if non-empty you can
-    // only request what was specified in said itemsRequest. Enforce that.
-    if (itemsRequest_.size() > 0) {
-        const auto& it = requestedNameSpacesAndNames_.find(nameSpace);
-        if (it == requestedNameSpacesAndNames_.end()) {
-            _hidl_cb(support::result(ResultCode::NOT_IN_REQUEST_MESSAGE,
-                                     "Name space '%s' was not requested in startRetrieval",
-                                     nameSpace.c_str()));
-            return Void();
-        }
-        const auto& dataItemNames = it->second;
-        if (std::find(dataItemNames.begin(), dataItemNames.end(), name) == dataItemNames.end()) {
-            _hidl_cb(support::result(
-                    ResultCode::NOT_IN_REQUEST_MESSAGE,
-                    "Data item name '%s' in name space '%s' was not requested in startRetrieval",
-                    name.c_str(), nameSpace.c_str()));
-            return Void();
-        }
-    }
-
-    // Enforce access control.
-    //
-    // Access is granted if at least one of the profiles grants access.
-    //
-    // If an item is configured without any profiles, access is denied.
-    //
-    ResultCode accessControl = ResultCode::NO_ACCESS_CONTROL_PROFILES;
-    for (auto id : accessControlProfileIds) {
-        auto search = profileIdToAccessCheckResult_.find(id);
-        if (search == profileIdToAccessCheckResult_.end()) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                     "Requested entry with unvalidated profile id %d", (int(id))));
-            return Void();
-        }
-        ResultCode accessControlForProfile = search->second;
-        if (accessControlForProfile == ResultCode::OK) {
-            accessControl = ResultCode::OK;
-            break;
-        }
-        accessControl = accessControlForProfile;
-    }
-    if (accessControl != ResultCode::OK) {
-        _hidl_cb(support::result(accessControl, "Access control check failed"));
-        return Void();
-    }
-
-    entryAdditionalData_ =
-            support::entryCreateAdditionalData(nameSpace, name, accessControlProfileIds);
-
-    currentName_ = name;
-    entryRemainingBytes_ = entrySize;
-    entryValue_.resize(0);
-
-    _hidl_cb(support::resultOK());
-    return Void();
-}
-
-Return<void> IdentityCredential::retrieveEntryValue(const hidl_vec<uint8_t>& encryptedContent,
-                                                    retrieveEntryValue_cb _hidl_cb) {
-    optional<vector<uint8_t>> content =
-            support::decryptAes128Gcm(storageKey_, encryptedContent, entryAdditionalData_);
-    if (!content) {
-        _hidl_cb(support::result(ResultCode::INVALID_DATA, "Error decrypting data"), {});
-        return Void();
-    }
-
-    size_t chunkSize = content.value().size();
-
-    if (chunkSize > entryRemainingBytes_) {
-        LOG(ERROR) << "Retrieved chunk of size " << chunkSize
-                   << " is bigger than remaining space of size " << entryRemainingBytes_;
-        _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                 "Retrieved chunk of size %zd is bigger than remaining space "
-                                 "of size %zd",
-                                 chunkSize, entryRemainingBytes_),
-                 {});
-        return Void();
-    }
-
-    entryRemainingBytes_ -= chunkSize;
-    if (entryRemainingBytes_ > 0) {
-        if (chunkSize != IdentityCredentialStore::kGcmChunkSize) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                     "Retrieved non-final chunk of size %zd but expected "
-                                     "kGcmChunkSize which is %zd",
-                                     chunkSize, IdentityCredentialStore::kGcmChunkSize),
-                     {});
-            return Void();
-        }
-    }
-
-    entryValue_.insert(entryValue_.end(), content.value().begin(), content.value().end());
-
-    if (entryRemainingBytes_ == 0) {
-        auto [entryValueItem, _, message] = cppbor::parse(entryValue_);
-        if (entryValueItem == nullptr) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA, "Retrieved data invalid CBOR"), {});
-            return Void();
-        }
-        currentNameSpaceDeviceNameSpacesMap_.add(currentName_, std::move(entryValueItem));
-    }
-
-    _hidl_cb(support::resultOK(), content.value());
-    return Void();
-}
-
-Return<void> IdentityCredential::finishRetrieval(const hidl_vec<uint8_t>& signingKeyBlob,
-                                                 finishRetrieval_cb _hidl_cb) {
-    if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) {
-        deviceNameSpacesMap_.add(currentNameSpace_,
-                                 std::move(currentNameSpaceDeviceNameSpacesMap_));
-    }
-    vector<uint8_t> encodedDeviceNameSpaces = deviceNameSpacesMap_.encode();
-
-    // If there's no signing key or no sessionTranscript or no reader ephemeral
-    // public key, we return the empty MAC.
-    optional<vector<uint8_t>> mac;
-    if (signingKeyBlob.size() > 0 && sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0) {
-        cppbor::Array array;
-        array.add("DeviceAuthentication");
-        array.add(sessionTranscriptItem_->clone());
-        array.add(docType_);
-        array.add(cppbor::Semantic(24, encodedDeviceNameSpaces));
-        vector<uint8_t> encodedDeviceAuthentication = array.encode();
-
-        vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
-        optional<vector<uint8_t>> signingKey =
-                support::decryptAes128Gcm(storageKey_, signingKeyBlob, docTypeAsBlob);
-        if (!signingKey) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA, "Error decrypting signingKeyBlob"),
-                     {}, {});
-            return Void();
-        }
-
-        optional<vector<uint8_t>> sharedSecret =
-                support::ecdh(readerPublicKey_, signingKey.value());
-        if (!sharedSecret) {
-            _hidl_cb(support::result(ResultCode::FAILED, "Error doing ECDH"), {}, {});
-            return Void();
-        }
-
-        vector<uint8_t> salt = {0x00};
-        vector<uint8_t> info = {};
-        optional<vector<uint8_t>> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32);
-        if (!derivedKey) {
-            _hidl_cb(support::result(ResultCode::FAILED, "Error deriving key from shared secret"),
-                     {}, {});
-            return Void();
-        }
-
-        mac = support::coseMac0(derivedKey.value(), {},        // payload
-                                encodedDeviceAuthentication);  // additionalData
-        if (!mac) {
-            _hidl_cb(support::result(ResultCode::FAILED, "Error MACing data"), {}, {});
-            return Void();
-        }
-    }
-
-    _hidl_cb(support::resultOK(), mac.value_or(vector<uint8_t>({})), encodedDeviceNameSpaces);
-    return Void();
-}
-
-Return<void> IdentityCredential::generateSigningKeyPair(generateSigningKeyPair_cb _hidl_cb) {
-    string serialDecimal = "0";  // TODO: set serial to something unique
-    string issuer = "Android Open Source Project";
-    string subject = "Android IdentityCredential Reference Implementation";
-    time_t validityNotBefore = time(nullptr);
-    time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
-
-    optional<vector<uint8_t>> signingKeyPKCS8 = support::createEcKeyPair();
-    if (!signingKeyPKCS8) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error creating signingKey"), {}, {});
-        return Void();
-    }
-
-    optional<vector<uint8_t>> signingPublicKey =
-            support::ecKeyPairGetPublicKey(signingKeyPKCS8.value());
-    if (!signingPublicKey) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error getting public part of signingKey"), {},
-                 {});
-        return Void();
-    }
-
-    optional<vector<uint8_t>> signingKey = support::ecKeyPairGetPrivateKey(signingKeyPKCS8.value());
-    if (!signingKey) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error getting private part of signingKey"),
-                 {}, {});
-        return Void();
-    }
-
-    optional<vector<uint8_t>> certificate = support::ecPublicKeyGenerateCertificate(
-            signingPublicKey.value(), credentialPrivKey_, serialDecimal, issuer, subject,
-            validityNotBefore, validityNotAfter);
-    if (!certificate) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error creating signingKey"), {}, {});
-        return Void();
-    }
-
-    optional<vector<uint8_t>> nonce = support::getRandom(12);
-    if (!nonce) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error getting random"), {}, {});
-        return Void();
-    }
-    vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
-    optional<vector<uint8_t>> encryptedSigningKey = support::encryptAes128Gcm(
-            storageKey_, nonce.value(), signingKey.value(), docTypeAsBlob);
-    if (!encryptedSigningKey) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error encrypting signingKey"), {}, {});
-        return Void();
-    }
-    _hidl_cb(support::resultOK(), encryptedSigningKey.value(), certificate.value());
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace identity
-}  // namespace hardware
-}  // namespace android
diff --git a/identity/1.0/default/IdentityCredential.h b/identity/1.0/default/IdentityCredential.h
deleted file mode 100644
index eb8787b..0000000
--- a/identity/1.0/default/IdentityCredential.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIAL_H
-#define ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIAL_H
-
-#include <android/hardware/identity/1.0/IIdentityCredential.h>
-
-#include <android/hardware/identity/support/IdentityCredentialSupport.h>
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#include <cppbor/cppbor.h>
-
-namespace android {
-namespace hardware {
-namespace identity {
-namespace implementation {
-
-using ::std::map;
-using ::std::string;
-using ::std::vector;
-
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::identity::V1_0::IIdentityCredential;
-using ::android::hardware::identity::V1_0::Result;
-using ::android::hardware::identity::V1_0::ResultCode;
-using ::android::hardware::identity::V1_0::SecureAccessControlProfile;
-using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
-
-using MapStringToVectorOfStrings = map<string, vector<string>>;
-
-class IdentityCredential : public IIdentityCredential {
-  public:
-    IdentityCredential(const hidl_vec<uint8_t>& credentialData)
-        : credentialData_(credentialData), numStartRetrievalCalls_(0), authChallenge_(0) {}
-
-    // Parses and decrypts credentialData_, return false on failure. Must be
-    // called right after construction.
-    ResultCode initialize();
-
-    // Methods from ::android::hardware::identity::IIdentityCredential follow.
-
-    Return<void> deleteCredential(deleteCredential_cb _hidl_cb) override;
-    Return<void> createEphemeralKeyPair(createEphemeralKeyPair_cb _hidl_cb) override;
-
-    Return<void> setReaderEphemeralPublicKey(const hidl_vec<uint8_t>& publicKey,
-                                             setReaderEphemeralPublicKey_cb _hidl_cb) override;
-
-    Return<void> createAuthChallenge(createAuthChallenge_cb _hidl_cb) override;
-
-    Return<void> startRetrieval(const hidl_vec<SecureAccessControlProfile>& accessControlProfiles,
-                                const HardwareAuthToken& authToken,
-                                const hidl_vec<uint8_t>& itemsRequest,
-                                const hidl_vec<uint8_t>& sessionTranscript,
-                                const hidl_vec<uint8_t>& readerSignature,
-                                const hidl_vec<uint16_t>& requestCounts,
-                                startRetrieval_cb _hidl_cb) override;
-    Return<void> startRetrieveEntryValue(const hidl_string& nameSpace, const hidl_string& name,
-                                         uint32_t entrySize,
-                                         const hidl_vec<uint16_t>& accessControlProfileIds,
-                                         startRetrieveEntryValue_cb _hidl_cb) override;
-    Return<void> retrieveEntryValue(const hidl_vec<uint8_t>& encryptedContent,
-                                    retrieveEntryValue_cb _hidl_cb) override;
-    Return<void> finishRetrieval(const hidl_vec<uint8_t>& signingKeyBlob,
-                                 finishRetrieval_cb _hidl_cb) override;
-
-    Return<void> generateSigningKeyPair(generateSigningKeyPair_cb _hidl_cb) override;
-
-  private:
-    // Set by constructor
-    vector<uint8_t> credentialData_;
-    int numStartRetrievalCalls_;
-
-    // Set by initialize()
-    string docType_;
-    bool testCredential_;
-    vector<uint8_t> storageKey_;
-    vector<uint8_t> credentialPrivKey_;
-
-    // Set by createEphemeralKeyPair()
-    vector<uint8_t> ephemeralPublicKey_;
-
-    // Set by setReaderEphemeralPublicKey()
-    vector<uint8_t> readerPublicKey_;
-
-    // Set by createAuthChallenge()
-    uint64_t authChallenge_;
-
-    // Set at startRetrieval() time.
-    map<uint16_t, ResultCode> profileIdToAccessCheckResult_;
-    vector<uint8_t> sessionTranscript_;
-    std::unique_ptr<cppbor::Item> sessionTranscriptItem_;
-    vector<uint8_t> itemsRequest_;
-    vector<uint16_t> requestCountsRemaining_;
-    MapStringToVectorOfStrings requestedNameSpacesAndNames_;
-    cppbor::Map deviceNameSpacesMap_;
-    cppbor::Map currentNameSpaceDeviceNameSpacesMap_;
-
-    // Set at startRetrieveEntryValue() time.
-    string currentNameSpace_;
-    string currentName_;
-    size_t entryRemainingBytes_;
-    vector<uint8_t> entryValue_;
-    vector<uint8_t> entryAdditionalData_;
-};
-
-}  // namespace implementation
-}  // namespace identity
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIAL_H
diff --git a/identity/1.0/default/IdentityCredentialStore.cpp b/identity/1.0/default/IdentityCredentialStore.cpp
deleted file mode 100644
index 9eb1e70..0000000
--- a/identity/1.0/default/IdentityCredentialStore.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "IdentityCredentialStore"
-
-#include "IdentityCredentialStore.h"
-#include "IdentityCredential.h"
-#include "WritableIdentityCredential.h"
-
-#include <android-base/logging.h>
-
-namespace android {
-namespace hardware {
-namespace identity {
-namespace implementation {
-
-// Methods from ::android::hardware::identity::IIdentityCredentialStore follow.
-
-Return<void> IdentityCredentialStore::getHardwareInformation(getHardwareInformation_cb _hidl_cb) {
-    _hidl_cb(support::resultOK(), "IdentityCredential Reference Implementation", "Google",
-             kGcmChunkSize, false /* isDirectAccess */, {} /* supportedDocTypes */);
-    return Void();
-}
-
-Return<void> IdentityCredentialStore::createCredential(const hidl_string& docType,
-                                                       bool testCredential,
-                                                       createCredential_cb _hidl_cb) {
-    auto writable_credential = new WritableIdentityCredential(docType, testCredential);
-    if (!writable_credential->initialize()) {
-        _hidl_cb(support::result(ResultCode::FAILED,
-                                 "Error initializing WritableIdentityCredential"),
-                 writable_credential);
-        return Void();
-    }
-    _hidl_cb(support::resultOK(), writable_credential);
-    return Void();
-}
-
-Return<void> IdentityCredentialStore::getCredential(const hidl_vec<uint8_t>& credentialData,
-                                                    getCredential_cb _hidl_cb) {
-    auto credential = new IdentityCredential(credentialData);
-    // We only support CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 right now.
-    auto ret = credential->initialize();
-    if (ret != ResultCode::OK) {
-        _hidl_cb(support::result(ret, "Error initializing IdentityCredential"), credential);
-        return Void();
-    }
-    _hidl_cb(support::resultOK(), credential);
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace identity
-}  // namespace hardware
-}  // namespace android
diff --git a/identity/1.0/default/IdentityCredentialStore.h b/identity/1.0/default/IdentityCredentialStore.h
deleted file mode 100644
index ad75360..0000000
--- a/identity/1.0/default/IdentityCredentialStore.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIALSTORE_H
-#define ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIALSTORE_H
-
-#include <android/hardware/identity/1.0/IIdentityCredentialStore.h>
-
-namespace android {
-namespace hardware {
-namespace identity {
-namespace implementation {
-
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::identity::V1_0::IIdentityCredentialStore;
-using ::android::hardware::identity::V1_0::Result;
-using ::android::hardware::identity::V1_0::ResultCode;
-
-class IdentityCredentialStore : public IIdentityCredentialStore {
-  public:
-    IdentityCredentialStore() {}
-
-    // The GCM chunk size used by this implementation is 64 KiB.
-    static constexpr size_t kGcmChunkSize = 64 * 1024;
-
-    // Methods from ::android::hardware::identity::IIdentityCredentialStore follow.
-    Return<void> getHardwareInformation(getHardwareInformation_cb _hidl_cb) override;
-    Return<void> createCredential(const hidl_string& docType, bool testCredential,
-                                  createCredential_cb _hidl_cb) override;
-    Return<void> getCredential(const hidl_vec<uint8_t>& credentialData,
-                               getCredential_cb _hidl_cb) override;
-};
-
-}  // namespace implementation
-}  // namespace identity
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIALSTORE_H
diff --git a/identity/1.0/default/OWNERS b/identity/1.0/default/OWNERS
deleted file mode 100644
index 6969910..0000000
--- a/identity/1.0/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-swillden@google.com
-zeuthen@google.com
diff --git a/identity/1.0/default/WritableIdentityCredential.cpp b/identity/1.0/default/WritableIdentityCredential.cpp
deleted file mode 100644
index 548b4c0..0000000
--- a/identity/1.0/default/WritableIdentityCredential.cpp
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "WritableIdentityCredential"
-
-#include "WritableIdentityCredential.h"
-#include "IdentityCredentialStore.h"
-
-#include <android/hardware/identity/support/IdentityCredentialSupport.h>
-
-#include <android-base/logging.h>
-
-#include <cppbor/cppbor.h>
-#include <cppbor/cppbor_parse.h>
-
-namespace android {
-namespace hardware {
-namespace identity {
-namespace implementation {
-
-using ::std::optional;
-
-// Writes CBOR-encoded structure to |credentialKeys| containing |storageKey| and
-// |credentialPrivKey|.
-static bool generateCredentialKeys(const vector<uint8_t>& storageKey,
-                                   const vector<uint8_t>& credentialPrivKey,
-                                   vector<uint8_t>& credentialKeys) {
-    if (storageKey.size() != 16) {
-        LOG(ERROR) << "Size of storageKey is not 16";
-        return false;
-    }
-
-    cppbor::Array array;
-    array.add(cppbor::Bstr(storageKey));
-    array.add(cppbor::Bstr(credentialPrivKey));
-    credentialKeys = array.encode();
-    return true;
-}
-
-// Writes CBOR-encoded structure to |credentialData| containing |docType|,
-// |testCredential| and |credentialKeys|. The latter element will be stored in
-// encrypted form, using |hardwareBoundKey| as the encryption key.
-bool generateCredentialData(const vector<uint8_t>& hardwareBoundKey, const string& docType,
-                            bool testCredential, const vector<uint8_t>& credentialKeys,
-                            vector<uint8_t>& credentialData) {
-    optional<vector<uint8_t>> nonce = support::getRandom(12);
-    if (!nonce) {
-        LOG(ERROR) << "Error getting random";
-        return false;
-    }
-    vector<uint8_t> docTypeAsVec(docType.begin(), docType.end());
-    optional<vector<uint8_t>> credentialBlob = support::encryptAes128Gcm(
-            hardwareBoundKey, nonce.value(), credentialKeys, docTypeAsVec);
-    if (!credentialBlob) {
-        LOG(ERROR) << "Error encrypting CredentialKeys blob";
-        return false;
-    }
-
-    cppbor::Array array;
-    array.add(docType);
-    array.add(testCredential);
-    array.add(cppbor::Bstr(credentialBlob.value()));
-    credentialData = array.encode();
-    return true;
-}
-
-bool WritableIdentityCredential::initialize() {
-    optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
-    if (!keyPair) {
-        LOG(ERROR) << "Error creating credentialKey";
-        return false;
-    }
-
-    optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
-    if (!pubKey) {
-        LOG(ERROR) << "Error getting public part of credentialKey";
-        return false;
-    }
-    credentialPubKey_ = pubKey.value();
-
-    optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
-    if (!privKey) {
-        LOG(ERROR) << "Error getting private part of credentialKey";
-        return false;
-    }
-    credentialPrivKey_ = privKey.value();
-
-    optional<vector<uint8_t>> random = support::getRandom(16);
-    if (!random) {
-        LOG(ERROR) << "Error creating storageKey";
-        return false;
-    }
-    storageKey_ = random.value();
-
-    return true;
-}
-
-Return<void> WritableIdentityCredential::getAttestationCertificate(
-        const hidl_vec<uint8_t>& /* attestationChallenge */,
-        getAttestationCertificate_cb _hidl_cb) {
-    // For now, we dynamically generate an attestion key on each and every
-    // request and use that to sign CredentialKey. In a real implementation this
-    // would look very differently.
-    optional<vector<uint8_t>> attestationKeyPair = support::createEcKeyPair();
-    if (!attestationKeyPair) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error creating attestationKey"), {});
-        return Void();
-    }
-
-    optional<vector<uint8_t>> attestationPubKey =
-            support::ecKeyPairGetPublicKey(attestationKeyPair.value());
-    if (!attestationPubKey) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error getting public part of attestationKey"),
-                 {});
-        return Void();
-    }
-
-    optional<vector<uint8_t>> attestationPrivKey =
-            support::ecKeyPairGetPrivateKey(attestationKeyPair.value());
-    if (!attestationPrivKey) {
-        _hidl_cb(
-                support::result(ResultCode::FAILED, "Error getting private part of attestationKey"),
-                {});
-        return Void();
-    }
-
-    string serialDecimal;
-    string issuer;
-    string subject;
-    time_t validityNotBefore = time(nullptr);
-    time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
-
-    // First create a certificate for |credentialPubKey| which is signed by
-    // |attestationPrivKey|.
-    //
-    serialDecimal = "0";  // TODO: set serial to |attestationChallenge|
-    issuer = "Android Open Source Project";
-    subject = "Android IdentityCredential CredentialKey";
-    optional<vector<uint8_t>> credentialPubKeyCertificate = support::ecPublicKeyGenerateCertificate(
-            credentialPubKey_, attestationPrivKey.value(), serialDecimal, issuer, subject,
-            validityNotBefore, validityNotAfter);
-    if (!credentialPubKeyCertificate) {
-        _hidl_cb(support::result(ResultCode::FAILED,
-                                 "Error creating certificate for credentialPubKey"),
-                 {});
-        return Void();
-    }
-
-    // This is followed by a certificate for |attestationPubKey| self-signed by
-    // |attestationPrivKey|.
-    serialDecimal = "0";  // TODO: set serial
-    issuer = "Android Open Source Project";
-    subject = "Android IdentityCredential AttestationKey";
-    optional<vector<uint8_t>> attestationKeyCertificate = support::ecPublicKeyGenerateCertificate(
-            attestationPubKey.value(), attestationPrivKey.value(), serialDecimal, issuer, subject,
-            validityNotBefore, validityNotAfter);
-    if (!attestationKeyCertificate) {
-        _hidl_cb(support::result(ResultCode::FAILED,
-                                 "Error creating certificate for attestationPubKey"),
-                 {});
-        return Void();
-    }
-
-    // Concatenate the certificates to form the chain.
-    vector<uint8_t> certificateChain;
-    certificateChain.insert(certificateChain.end(), credentialPubKeyCertificate.value().begin(),
-                            credentialPubKeyCertificate.value().end());
-    certificateChain.insert(certificateChain.end(), attestationKeyCertificate.value().begin(),
-                            attestationKeyCertificate.value().end());
-
-    _hidl_cb(support::resultOK(), certificateChain);
-    return Void();
-}
-
-Return<void> WritableIdentityCredential::startPersonalization(uint16_t accessControlProfileCount,
-                                                              const hidl_vec<uint16_t>& entryCounts,
-                                                              startPersonalization_cb _hidl_cb) {
-    numAccessControlProfileRemaining_ = accessControlProfileCount;
-    remainingEntryCounts_ = entryCounts;
-    entryNameSpace_ = "";
-
-    signedDataAccessControlProfiles_ = cppbor::Array();
-    signedDataNamespaces_ = cppbor::Map();
-    signedDataCurrentNamespace_ = cppbor::Array();
-
-    _hidl_cb(support::resultOK());
-    return Void();
-}
-
-Return<void> WritableIdentityCredential::addAccessControlProfile(
-        uint16_t id, const hidl_vec<uint8_t>& readerCertificate, bool userAuthenticationRequired,
-        uint64_t timeoutMillis, uint64_t secureUserId, addAccessControlProfile_cb _hidl_cb) {
-    SecureAccessControlProfile profile;
-
-    if (numAccessControlProfileRemaining_ == 0) {
-        _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                 "numAccessControlProfileRemaining_ is 0 and expected non-zero"),
-                 profile);
-        return Void();
-    }
-
-    // Spec requires if |userAuthenticationRequired| is false, then |timeoutMillis| must also
-    // be zero.
-    if (!userAuthenticationRequired && timeoutMillis != 0) {
-        _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                 "userAuthenticationRequired is false but timeout is non-zero"),
-                 profile);
-        return Void();
-    }
-
-    profile.id = id;
-    profile.readerCertificate = readerCertificate;
-    profile.userAuthenticationRequired = userAuthenticationRequired;
-    profile.timeoutMillis = timeoutMillis;
-    profile.secureUserId = secureUserId;
-    optional<vector<uint8_t>> mac =
-            support::secureAccessControlProfileCalcMac(profile, storageKey_);
-    if (!mac) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error calculating MAC for profile"), profile);
-        return Void();
-    }
-    profile.mac = mac.value();
-
-    cppbor::Map profileMap;
-    profileMap.add("id", profile.id);
-    if (profile.readerCertificate.size() > 0) {
-        profileMap.add("readerCertificate", cppbor::Bstr(profile.readerCertificate));
-    }
-    if (profile.userAuthenticationRequired) {
-        profileMap.add("userAuthenticationRequired", profile.userAuthenticationRequired);
-        profileMap.add("timeoutMillis", profile.timeoutMillis);
-    }
-    signedDataAccessControlProfiles_.add(std::move(profileMap));
-
-    numAccessControlProfileRemaining_--;
-
-    _hidl_cb(support::resultOK(), profile);
-    return Void();
-}
-
-Return<void> WritableIdentityCredential::beginAddEntry(
-        const hidl_vec<uint16_t>& accessControlProfileIds, const hidl_string& nameSpace,
-        const hidl_string& name, uint32_t entrySize, beginAddEntry_cb _hidl_cb) {
-    if (numAccessControlProfileRemaining_ != 0) {
-        LOG(ERROR) << "numAccessControlProfileRemaining_ is " << numAccessControlProfileRemaining_
-                   << " and expected zero";
-        _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                 "numAccessControlProfileRemaining_ is %zd and expected zero",
-                                 numAccessControlProfileRemaining_));
-        return Void();
-    }
-
-    if (remainingEntryCounts_.size() == 0) {
-        _hidl_cb(support::result(ResultCode::INVALID_DATA, "No more namespaces to add to"));
-        return Void();
-    }
-
-    // Handle initial beginEntry() call.
-    if (entryNameSpace_ == "") {
-        entryNameSpace_ = nameSpace;
-    }
-
-    // If the namespace changed...
-    if (nameSpace != entryNameSpace_) {
-        // Then check that all entries in the previous namespace have been added..
-        if (remainingEntryCounts_[0] != 0) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                     "New namespace but %d entries remain to be added",
-                                     int(remainingEntryCounts_[0])));
-            return Void();
-        }
-        remainingEntryCounts_.erase(remainingEntryCounts_.begin());
-
-        if (signedDataCurrentNamespace_.size() > 0) {
-            signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_));
-            signedDataCurrentNamespace_ = cppbor::Array();
-        }
-    } else {
-        // Same namespace...
-        if (remainingEntryCounts_[0] == 0) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                     "Same namespace but no entries remain to be added"));
-            return Void();
-        }
-        remainingEntryCounts_[0] -= 1;
-    }
-
-    entryAdditionalData_ =
-            support::entryCreateAdditionalData(nameSpace, name, accessControlProfileIds);
-
-    entryRemainingBytes_ = entrySize;
-    entryNameSpace_ = nameSpace;
-    entryName_ = name;
-    entryAccessControlProfileIds_ = accessControlProfileIds;
-    entryBytes_.resize(0);
-    // LOG(INFO) << "name=" << name << " entrySize=" << entrySize;
-
-    _hidl_cb(support::resultOK());
-    return Void();
-}
-
-Return<void> WritableIdentityCredential::addEntryValue(const hidl_vec<uint8_t>& content,
-                                                       addEntryValue_cb _hidl_cb) {
-    size_t contentSize = content.size();
-
-    if (contentSize > IdentityCredentialStore::kGcmChunkSize) {
-        _hidl_cb(support::result(
-                         ResultCode::INVALID_DATA,
-                         "Passed in chunk of size %zd is bigger than kGcmChunkSize which is %zd",
-                         contentSize, IdentityCredentialStore::kGcmChunkSize),
-                 {});
-        return Void();
-    }
-    if (contentSize > entryRemainingBytes_) {
-        _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                 "Passed in chunk of size %zd is bigger than remaining space "
-                                 "of size %zd",
-                                 contentSize, entryRemainingBytes_),
-                 {});
-        return Void();
-    }
-
-    entryBytes_.insert(entryBytes_.end(), content.begin(), content.end());
-    entryRemainingBytes_ -= contentSize;
-    if (entryRemainingBytes_ > 0) {
-        if (contentSize != IdentityCredentialStore::kGcmChunkSize) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA,
-                                     "Retrieved non-final chunk of size %zd but expected "
-                                     "kGcmChunkSize which is %zd",
-                                     contentSize, IdentityCredentialStore::kGcmChunkSize),
-                     {});
-            return Void();
-        }
-    }
-
-    optional<vector<uint8_t>> nonce = support::getRandom(12);
-    if (!nonce) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error getting nonce"), {});
-        return Void();
-    }
-    optional<vector<uint8_t>> encryptedContent =
-            support::encryptAes128Gcm(storageKey_, nonce.value(), content, entryAdditionalData_);
-    if (!encryptedContent) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error encrypting content"), {});
-        return Void();
-    }
-
-    if (entryRemainingBytes_ == 0) {
-        // TODO: ideally do do this without parsing the data (but still validate data is valid
-        // CBOR).
-        auto [item, _, message] = cppbor::parse(entryBytes_);
-        if (item == nullptr) {
-            _hidl_cb(support::result(ResultCode::INVALID_DATA, "Data is not valid CBOR"), {});
-            return Void();
-        }
-        cppbor::Map entryMap;
-        entryMap.add("name", entryName_);
-        entryMap.add("value", std::move(item));
-        cppbor::Array profileIdArray;
-        for (auto id : entryAccessControlProfileIds_) {
-            profileIdArray.add(id);
-        }
-        entryMap.add("accessControlProfiles", std::move(profileIdArray));
-        signedDataCurrentNamespace_.add(std::move(entryMap));
-    }
-
-    _hidl_cb(support::resultOK(), encryptedContent.value());
-    return Void();
-}
-
-Return<void> WritableIdentityCredential::finishAddingEntries(finishAddingEntries_cb _hidl_cb) {
-    if (signedDataCurrentNamespace_.size() > 0) {
-        signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_));
-    }
-    cppbor::Array popArray;
-    popArray.add("ProofOfProvisioning")
-            .add(docType_)
-            .add(std::move(signedDataAccessControlProfiles_))
-            .add(std::move(signedDataNamespaces_))
-            .add(testCredential_);
-    vector<uint8_t> encodedCbor = popArray.encode();
-
-    optional<vector<uint8_t>> signature = support::coseSignEcDsa(credentialPrivKey_,
-                                                                 encodedCbor,  // payload
-                                                                 {},           // additionalData
-                                                                 {});          // certificateChain
-    if (!signature) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error signing data"), {}, {});
-        return Void();
-    }
-
-    vector<uint8_t> credentialKeys;
-    if (!generateCredentialKeys(storageKey_, credentialPrivKey_, credentialKeys)) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error generating CredentialKeys"), {}, {});
-        return Void();
-    }
-
-    vector<uint8_t> credentialData;
-    if (!generateCredentialData(testCredential_ ? support::getTestHardwareBoundKey()
-                                                : support::getHardwareBoundKey(),
-                                docType_, testCredential_, credentialKeys, credentialData)) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error generating CredentialData"), {}, {});
-        return Void();
-    }
-
-    _hidl_cb(support::resultOK(), credentialData, signature.value());
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace identity
-}  // namespace hardware
-}  // namespace android
diff --git a/identity/1.0/default/WritableIdentityCredential.h b/identity/1.0/default/WritableIdentityCredential.h
deleted file mode 100644
index 9f4e303..0000000
--- a/identity/1.0/default/WritableIdentityCredential.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_HARDWARE_IDENTITY_WRITABLEIDENTITYCREDENTIAL_H
-#define ANDROID_HARDWARE_IDENTITY_WRITABLEIDENTITYCREDENTIAL_H
-
-#include <android/hardware/identity/1.0/IWritableIdentityCredential.h>
-
-#include <android/hardware/identity/support/IdentityCredentialSupport.h>
-
-#include <cppbor.h>
-
-namespace android {
-namespace hardware {
-namespace identity {
-namespace implementation {
-
-using ::std::string;
-using ::std::vector;
-
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::identity::V1_0::IWritableIdentityCredential;
-using ::android::hardware::identity::V1_0::Result;
-using ::android::hardware::identity::V1_0::ResultCode;
-using ::android::hardware::identity::V1_0::SecureAccessControlProfile;
-
-class WritableIdentityCredential : public IWritableIdentityCredential {
-  public:
-    WritableIdentityCredential(const hidl_string& docType, bool testCredential)
-        : docType_(docType), testCredential_(testCredential) {}
-
-    // Creates the Credential Key. Returns false on failure. Must be called
-    // right after construction.
-    bool initialize();
-
-    // Methods from ::android::hardware::identity::IWritableIdentityCredential
-    // follow.
-    Return<void> getAttestationCertificate(const hidl_vec<uint8_t>& attestationChallenge,
-                                           getAttestationCertificate_cb _hidl_cb) override;
-
-    Return<void> startPersonalization(uint16_t accessControlProfileCount,
-                                      const hidl_vec<uint16_t>& entryCounts,
-                                      startPersonalization_cb _hidl_cb) override;
-
-    Return<void> addAccessControlProfile(uint16_t id, const hidl_vec<uint8_t>& readerCertificate,
-                                         bool userAuthenticationRequired, uint64_t timeoutMillis,
-                                         uint64_t secureUserId,
-                                         addAccessControlProfile_cb _hidl_cb) override;
-
-    Return<void> beginAddEntry(const hidl_vec<uint16_t>& accessControlProfileIds,
-                               const hidl_string& nameSpace, const hidl_string& name,
-                               uint32_t entrySize, beginAddEntry_cb _hidl_cb) override;
-
-    Return<void> addEntryValue(const hidl_vec<uint8_t>& content,
-                               addEntryValue_cb _hidl_cb) override;
-
-    Return<void> finishAddingEntries(finishAddingEntries_cb _hidl_cb) override;
-
-  private:
-    string docType_;
-    bool testCredential_;
-
-    // These are set in initialize().
-    vector<uint8_t> storageKey_;
-    vector<uint8_t> credentialPrivKey_;
-    vector<uint8_t> credentialPubKey_;
-
-    // These fields are initialized during startPersonalization()
-    size_t numAccessControlProfileRemaining_;
-    vector<uint16_t> remainingEntryCounts_;
-    cppbor::Array signedDataAccessControlProfiles_;
-    cppbor::Map signedDataNamespaces_;
-    cppbor::Array signedDataCurrentNamespace_;
-
-    // These fields are initialized during beginAddEntry()
-    size_t entryRemainingBytes_;
-    vector<uint8_t> entryAdditionalData_;
-    string entryNameSpace_;
-    string entryName_;
-    vector<uint16_t> entryAccessControlProfileIds_;
-    vector<uint8_t> entryBytes_;
-};
-
-}  // namespace implementation
-}  // namespace identity
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_IDENTITY_WRITABLEIDENTITYCREDENTIAL_H
diff --git a/identity/1.0/default/android.hardware.identity@1.0-service.example.rc b/identity/1.0/default/android.hardware.identity@1.0-service.example.rc
deleted file mode 100644
index 1eb7319..0000000
--- a/identity/1.0/default/android.hardware.identity@1.0-service.example.rc
+++ /dev/null
@@ -1,3 +0,0 @@
-service vendor.identity-1-0 /vendor/bin/hw/android.hardware.identity@1.0-service.example
-    class hal
-    user nobody
diff --git a/identity/1.0/default/service.cpp b/identity/1.0/default/service.cpp
deleted file mode 100644
index 839e803..0000000
--- a/identity/1.0/default/service.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "android.hardware.identity@1.0-service"
-
-#include <android-base/logging.h>
-#include <hidl/HidlTransportSupport.h>
-
-#include "IdentityCredentialStore.h"
-
-using android::hardware::joinRpcThreadpool;
-using android::hardware::identity::implementation::IdentityCredentialStore;
-
-int main(int /* argc */, char* argv[]) {
-    ::android::hardware::configureRpcThreadpool(1, true /*willJoinThreadpool*/);
-
-    ::android::base::InitLogging(argv, &android::base::StderrLogger);
-
-    auto identity_store = new IdentityCredentialStore();
-    auto status = identity_store->registerAsService();
-    if (status != android::OK) {
-        LOG(FATAL) << "Could not register service for IdentityCredentialStore 1.0 (" << status
-                   << ")";
-    }
-    joinRpcThreadpool();
-    return -1;  // Should never get here.
-}
diff --git a/identity/1.0/types.hal b/identity/1.0/types.hal
deleted file mode 100644
index 5aedfea..0000000
--- a/identity/1.0/types.hal
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2018 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.identity@1.0;
-
-/**
- * The ResultCode enumeration is used to convey the status of an operation.
- */
-enum ResultCode : int32_t {
-    /**
-     * Success.
-     */
-    OK = 0,
-
-    /**
-     * The operation failed. This is used as a generic catch-all for errors that don't belong
-     * in other categories, including memory/resource allocation failures and I/O errors.
-     */
-    FAILED = 1,
-
-    /**
-     * The passed data was invalid. This is a generic catch all for errors that don't belong
-     * in other categories related to parameter validation.
-     */
-    INVALID_DATA = 2,
-
-    /**
-     * The authToken parameter passed to IIdentityCredential.startRetrieval() is not valid.
-     */
-    INVALID_AUTH_TOKEN = 3,
-
-    /**
-     * The itemsRequest parameter passed to IIdentityCredential.startRetrieval() does not meet
-     * the requirements described in the documentation for that method.
-     */
-    INVALID_ITEMS_REQUEST_MESSAGE = 4,
-
-    /**
-     * The readerSignature parameter in IIdentityCredential.startRetrieval() is invalid,
-     * doesn't contain an embedded certificate chain, or the signature failed to
-     * validate.
-     */
-    READER_SIGNATURE_CHECK_FAILED = 5,
-
-    /**
-     * The sessionTranscript passed to startRetrieval() did not contain the ephmeral public
-     * key returned by createEphemeralPublicKey().
-     */
-    EPHEMERAL_PUBLIC_KEY_NOT_FOUND = 6,
-
-    /**
-     * An access condition related to user authentication was not satisfied.
-     */
-    USER_AUTHENTICATION_FAILED = 7,
-
-    /**
-     * An access condition related to reader authentication was not satisfied.
-     */
-    READER_AUTHENTICATION_FAILED = 8,
-
-    /**
-    * The request data element has no access control profiles associated so it cannot be accessed.
-    */
-    NO_ACCESS_CONTROL_PROFILES = 9,
-
-    /**
-     * The requested data element is not in the provided non-empty itemsRequest message.
-     */
-    NOT_IN_REQUEST_MESSAGE = 10,
-
-    /**
-     * The passed-in sessionTranscript doesn't match the previously passed-in sessionTranscript.
-     */
-    SESSION_TRANSCRIPT_MISMATCH = 11,
-};
-
-/**
- * A result has a ResultCode and corresponding textual message.
- */
-struct Result {
-    /**
-     * The result code.
-     *
-     * Implementations must not use values not defined in the ResultCode enumeration.
-     */
-    ResultCode code;
-
-    /**
-     * A human-readable message in English conveying more detail about a failure.
-     *
-     * If code is ResultCode::OK this field must be set to the empty string.
-     */
-    string message;
-};
-
-struct SecureAccessControlProfile {
-    /**
-     * id is a numeric identifier that must be unique within the context of a Credential and may be
-     * used to reference the profile.
-     */
-    uint16_t id;
-
-    /**
-     * readerCertificate, if non-empty, specifies a single X.509 certificate (not a chain
-     * of certificates) that must be used to authenticate requests. For details about how
-     * this is done, see the readerSignature paremter of IIdentityCredential.startRetrieval.
-     */
-    vec<uint8_t> readerCertificate;
-
-    /**
-     * if true, the user is required to authenticate to allow requests.  Required authentication
-     * fressness is specified by timeout below.
-     *
-     */
-    bool userAuthenticationRequired;
-
-    /**
-     * Timeout specifies the amount of time, in milliseconds, for which a user authentication (see
-     * above) is valid, if userAuthenticationRequired is set to true.  If userAuthenticationRequired
-     * is true and timout is zero then authentication is required for each reader session.
-     *
-     * If userAuthenticationRequired is false, timeout must be zero.
-     */
-    uint64_t timeoutMillis;
-
-    /**
-     * secureUserId must be non-zero if userAuthenticationRequired is true.
-     * It is not related to any Android user ID or UID, but is created in the
-     * Gatekeeper application in the secure environment.
-     */
-    uint64_t secureUserId;
-
-    /**
-     * The mac is used to authenticate the access control profile.  It contains:
-     *
-     *      AES-GCM-ENC(storageKey, R, {}, AccessControlProfile)
-     *
-     *  where AccessControlProfile is the CBOR map:
-     *
-     *      AccessControlProfile = {
-     *          "id": uint,
-     *          ? "readerCertificate" : bstr,
-     *          ? (
-     *              "userAuthenticationRequired" : bool,
-     *              "timeoutMillis" : uint,
-     *              "secureUserId" : uint
-     *          )
-     *      }
-     */
-    vec<uint8_t> mac;
-};
diff --git a/identity/1.0/vts/functional/VtsHalIdentityCredentialTargetTest.cpp b/identity/1.0/vts/functional/VtsHalIdentityCredentialTargetTest.cpp
deleted file mode 100644
index 903e912..0000000
--- a/identity/1.0/vts/functional/VtsHalIdentityCredentialTargetTest.cpp
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "IdentityCredentialHidlHalTest"
-
-#include <map>
-
-#include <android-base/logging.h>
-#include <android/hardware/identity/1.0/IIdentityCredentialStore.h>
-#include <android/hardware/identity/1.0/types.h>
-#include <android/hardware/identity/support/IdentityCredentialSupport.h>
-
-#include <cppbor.h>
-#include <cppbor_parse.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
-
-using std::map;
-using std::optional;
-using std::string;
-using std::vector;
-
-namespace android {
-namespace hardware {
-namespace identity {
-namespace test {
-
-using ::android::hardware::identity::V1_0::IIdentityCredential;
-using ::android::hardware::identity::V1_0::IIdentityCredentialStore;
-using ::android::hardware::identity::V1_0::IWritableIdentityCredential;
-using ::android::hardware::identity::V1_0::Result;
-using ::android::hardware::identity::V1_0::ResultCode;
-using ::android::hardware::identity::V1_0::SecureAccessControlProfile;
-using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
-
-// ---------------------------------------------------------------------------
-// Test Data.
-// ---------------------------------------------------------------------------
-
-struct TestEntryData {
-    TestEntryData(string nameSpace, string name, vector<uint16_t> profileIds)
-        : nameSpace(nameSpace), name(name), profileIds(profileIds) {}
-
-    TestEntryData(string nameSpace, string name, const string& value, vector<uint16_t> profileIds)
-        : TestEntryData(nameSpace, name, profileIds) {
-        valueCbor = cppbor::Tstr(((const char*)value.data())).encode();
-    }
-    TestEntryData(string nameSpace, string name, const vector<uint8_t>& value,
-                  vector<uint16_t> profileIds)
-        : TestEntryData(nameSpace, name, profileIds) {
-        valueCbor = cppbor::Bstr(value).encode();
-    }
-    TestEntryData(string nameSpace, string name, bool value, vector<uint16_t> profileIds)
-        : TestEntryData(nameSpace, name, profileIds) {
-        valueCbor = cppbor::Bool(value).encode();
-    }
-    TestEntryData(string nameSpace, string name, int64_t value, vector<uint16_t> profileIds)
-        : TestEntryData(nameSpace, name, profileIds) {
-        if (value >= 0) {
-            valueCbor = cppbor::Uint(value).encode();
-        } else {
-            valueCbor = cppbor::Nint(-value).encode();
-        }
-    }
-
-    string nameSpace;
-    string name;
-    vector<uint8_t> valueCbor;
-    vector<uint16_t> profileIds;
-};
-
-struct TestProfile {
-    uint16_t id;
-    hidl_vec<uint8_t> readerCertificate;
-    bool userAuthenticationRequired;
-    uint64_t timeoutMillis;
-};
-
-/************************************
- *   TEST DATA FOR AUTHENTICATION
- ************************************/
-// Test authentication token for user authentication
-
-class IdentityCredentialStoreHidlTest : public ::testing::TestWithParam<std::string> {
-  public:
-    virtual void SetUp() override {
-        string serviceName = GetParam();
-        ASSERT_FALSE(serviceName.empty());
-        credentialStore_ = IIdentityCredentialStore::getService(serviceName);
-        ASSERT_NE(credentialStore_, nullptr);
-
-        credentialStore_->getHardwareInformation(
-                [&](const Result& result, const hidl_string& credentialStoreName,
-                    const hidl_string& credentialStoreAuthorName, uint32_t chunkSize,
-                    bool /* isDirectAccess */,
-                    const hidl_vec<hidl_string> /* supportedDocTypes */) {
-                    EXPECT_EQ("", result.message);
-                    ASSERT_EQ(ResultCode::OK, result.code);
-                    ASSERT_GT(credentialStoreName.size(), 0u);
-                    ASSERT_GT(credentialStoreAuthorName.size(), 0u);
-                    ASSERT_GE(chunkSize, 256u);  // Chunk sizes < APDU buffer won't be supported
-                    dataChunkSize_ = chunkSize;
-                });
-    }
-    virtual void TearDown() override {}
-
-    uint32_t dataChunkSize_ = 0;
-
-    sp<IIdentityCredentialStore> credentialStore_;
-};
-
-TEST_P(IdentityCredentialStoreHidlTest, HardwareConfiguration) {
-    credentialStore_->getHardwareInformation(
-            [&](const Result& result, const hidl_string& credentialStoreName,
-                const hidl_string& credentialStoreAuthorName, uint32_t chunkSize,
-                bool /* isDirectAccess */, const hidl_vec<hidl_string> /* supportedDocTypes */) {
-                EXPECT_EQ("", result.message);
-                ASSERT_EQ(ResultCode::OK, result.code);
-                ASSERT_GT(credentialStoreName.size(), 0u);
-                ASSERT_GT(credentialStoreAuthorName.size(), 0u);
-                ASSERT_GE(chunkSize, 256u);  // Chunk sizes < APDU buffer won't be supported
-            });
-}
-
-TEST_P(IdentityCredentialStoreHidlTest, createAndRetrieveCredential) {
-    // First, generate a key-pair for the reader since its public key will be
-    // part of the request data.
-    optional<vector<uint8_t>> readerKeyPKCS8 = support::createEcKeyPair();
-    ASSERT_TRUE(readerKeyPKCS8);
-    optional<vector<uint8_t>> readerPublicKey =
-            support::ecKeyPairGetPublicKey(readerKeyPKCS8.value());
-    optional<vector<uint8_t>> readerKey = support::ecKeyPairGetPrivateKey(readerKeyPKCS8.value());
-    string serialDecimal = "1234";
-    string issuer = "Android Open Source Project";
-    string subject = "Android IdentityCredential VTS Test";
-    time_t validityNotBefore = time(nullptr);
-    time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
-    optional<vector<uint8_t>> readerCertificate = support::ecPublicKeyGenerateCertificate(
-            readerPublicKey.value(), readerKey.value(), serialDecimal, issuer, subject,
-            validityNotBefore, validityNotAfter);
-    ASSERT_TRUE(readerCertificate);
-
-    // Make the portrait image really big (just shy of 256 KiB) to ensure that
-    // the chunking code gets exercised.
-    vector<uint8_t> portraitImage;
-    portraitImage.resize(256 * 1024 - 10);
-    for (size_t n = 0; n < portraitImage.size(); n++) {
-        portraitImage[n] = (uint8_t)n;
-    }
-
-    // Access control profiles:
-    const vector<TestProfile> testProfiles = {// Profile 0 (reader authentication)
-                                              {0, readerCertificate.value(), false, 0},
-                                              // Profile 1 (no authentication)
-                                              {1, {}, false, 0}};
-
-    HardwareAuthToken authToken = {};
-
-    // Here's the actual test data:
-    const vector<TestEntryData> testEntries = {
-            {"PersonalData", "Last name", string("Turing"), vector<uint16_t>{0, 1}},
-            {"PersonalData", "Birth date", string("19120623"), vector<uint16_t>{0, 1}},
-            {"PersonalData", "First name", string("Alan"), vector<uint16_t>{0, 1}},
-            {"PersonalData", "Home address", string("Maida Vale, London, England"),
-             vector<uint16_t>{0}},
-            {"Image", "Portrait image", portraitImage, vector<uint16_t>{0, 1}},
-    };
-    const vector<uint16_t> testEntriesEntryCounts = {static_cast<uint16_t>(testEntries.size() - 1),
-                                                     1u};
-
-    string cborPretty;
-    sp<IWritableIdentityCredential> writableCredential;
-
-    hidl_vec<uint8_t> empty{0};
-
-    string docType = "org.iso.18013-5.2019.mdl";
-    bool testCredential = true;
-    Result result;
-    credentialStore_->createCredential(
-            docType, testCredential,
-            [&](const Result& _result, const sp<IWritableIdentityCredential>& _writableCredential) {
-                result = _result;
-                writableCredential = _writableCredential;
-            });
-    EXPECT_EQ("", result.message);
-    ASSERT_EQ(ResultCode::OK, result.code);
-    ASSERT_NE(writableCredential, nullptr);
-
-    string challenge = "attestationChallenge";
-    vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
-    vector<uint8_t> attestationCertificate;
-    writableCredential->getAttestationCertificate(
-            attestationChallenge,
-            [&](const Result& _result, const hidl_vec<uint8_t>& _attestationCertificate) {
-                result = _result;
-                attestationCertificate = _attestationCertificate;
-            });
-    EXPECT_EQ("", result.message);
-    ASSERT_EQ(ResultCode::OK, result.code);
-
-    writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts,
-                                             [&](const Result& _result) { result = _result; });
-    EXPECT_EQ("", result.message);
-    ASSERT_EQ(ResultCode::OK, result.code);
-
-    vector<SecureAccessControlProfile> returnedSecureProfiles;
-    for (const auto& testProfile : testProfiles) {
-        SecureAccessControlProfile profile;
-        writableCredential->addAccessControlProfile(
-                testProfile.id, testProfile.readerCertificate,
-                testProfile.userAuthenticationRequired, testProfile.timeoutMillis,
-                0,  // secureUserId
-                [&](const Result& _result, const SecureAccessControlProfile& _profile) {
-                    result = _result;
-                    profile = _profile;
-                });
-        EXPECT_EQ("", result.message);
-        ASSERT_EQ(ResultCode::OK, result.code);
-        ASSERT_EQ(testProfile.id, profile.id);
-        ASSERT_EQ(testProfile.readerCertificate, profile.readerCertificate);
-        ASSERT_EQ(testProfile.userAuthenticationRequired, profile.userAuthenticationRequired);
-        ASSERT_EQ(testProfile.timeoutMillis, profile.timeoutMillis);
-        ASSERT_EQ(support::kAesGcmTagSize + support::kAesGcmIvSize, profile.mac.size());
-        returnedSecureProfiles.push_back(profile);
-    }
-
-    // Uses TestEntryData* pointer as key and values are the encrypted blobs. This
-    // is a little hacky but it works well enough.
-    map<const TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
-
-    for (const auto& entry : testEntries) {
-        vector<vector<uint8_t>> chunks = support::chunkVector(entry.valueCbor, dataChunkSize_);
-
-        writableCredential->beginAddEntry(entry.profileIds, entry.nameSpace, entry.name,
-                                          entry.valueCbor.size(),
-                                          [&](const Result& _result) { result = _result; });
-        EXPECT_EQ("", result.message);
-        ASSERT_EQ(ResultCode::OK, result.code);
-
-        vector<vector<uint8_t>> encryptedChunks;
-        for (const auto& chunk : chunks) {
-            writableCredential->addEntryValue(
-                    chunk, [&](const Result& result, hidl_vec<uint8_t> encryptedContent) {
-                        EXPECT_EQ("", result.message);
-                        ASSERT_EQ(ResultCode::OK, result.code);
-                        ASSERT_GT(encryptedContent.size(), 0u);
-                        encryptedChunks.push_back(encryptedContent);
-                    });
-        }
-        encryptedBlobs[&entry] = encryptedChunks;
-    }
-
-    vector<uint8_t> credentialData;
-    vector<uint8_t> proofOfProvisioningSignature;
-    writableCredential->finishAddingEntries(
-            [&](const Result& _result, const hidl_vec<uint8_t>& _credentialData,
-                const hidl_vec<uint8_t>& _proofOfProvisioningSignature) {
-                result = _result;
-                credentialData = _credentialData;
-                proofOfProvisioningSignature = _proofOfProvisioningSignature;
-            });
-    EXPECT_EQ("", result.message);
-    ASSERT_EQ(ResultCode::OK, result.code);
-
-    optional<vector<uint8_t>> proofOfProvisioning =
-            support::coseSignGetPayload(proofOfProvisioningSignature);
-    ASSERT_TRUE(proofOfProvisioning);
-    cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
-    EXPECT_EQ(
-            "[\n"
-            "  'ProofOfProvisioning',\n"
-            "  'org.iso.18013-5.2019.mdl',\n"
-            "  [\n"
-            "    {\n"
-            "      'id' : 0,\n"
-            "      'readerCertificate' : <not printed>,\n"
-            "    },\n"
-            "    {\n"
-            "      'id' : 1,\n"
-            "    },\n"
-            "  ],\n"
-            "  {\n"
-            "    'PersonalData' : [\n"
-            "      {\n"
-            "        'name' : 'Last name',\n"
-            "        'value' : 'Turing',\n"
-            "        'accessControlProfiles' : [0, 1, ],\n"
-            "      },\n"
-            "      {\n"
-            "        'name' : 'Birth date',\n"
-            "        'value' : '19120623',\n"
-            "        'accessControlProfiles' : [0, 1, ],\n"
-            "      },\n"
-            "      {\n"
-            "        'name' : 'First name',\n"
-            "        'value' : 'Alan',\n"
-            "        'accessControlProfiles' : [0, 1, ],\n"
-            "      },\n"
-            "      {\n"
-            "        'name' : 'Home address',\n"
-            "        'value' : 'Maida Vale, London, England',\n"
-            "        'accessControlProfiles' : [0, ],\n"
-            "      },\n"
-            "    ],\n"
-            "    'Image' : [\n"
-            "      {\n"
-            "        'name' : 'Portrait image',\n"
-            "        'value' : <bstr size=262134 sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
-            "        'accessControlProfiles' : [0, 1, ],\n"
-            "      },\n"
-            "    ],\n"
-            "  },\n"
-            "  true,\n"
-            "]",
-            cborPretty);
-
-    optional<vector<uint8_t>> credentialPubKey =
-            support::certificateChainGetTopMostKey(attestationCertificate);
-    ASSERT_TRUE(credentialPubKey);
-    EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature,
-                                                 {},  // Additional data
-                                                 credentialPubKey.value()));
-    writableCredential = nullptr;
-
-    // Now that the credential has been provisioned, read it back and check the
-    // correct data is returned.
-    sp<IIdentityCredential> credential;
-    credentialStore_->getCredential(
-            credentialData, [&](const Result& _result, const sp<IIdentityCredential>& _credential) {
-                result = _result;
-                credential = _credential;
-            });
-    EXPECT_EQ("", result.message);
-    ASSERT_EQ(ResultCode::OK, result.code);
-    ASSERT_NE(credential, nullptr);
-
-    optional<vector<uint8_t>> readerEphemeralKeyPair = support::createEcKeyPair();
-    ASSERT_TRUE(readerEphemeralKeyPair);
-    optional<vector<uint8_t>> readerEphemeralPublicKey =
-            support::ecKeyPairGetPublicKey(readerEphemeralKeyPair.value());
-    credential->setReaderEphemeralPublicKey(readerEphemeralPublicKey.value(),
-                                            [&](const Result& _result) { result = _result; });
-    EXPECT_EQ("", result.message);
-    ASSERT_EQ(ResultCode::OK, result.code);
-
-    vector<uint8_t> ephemeralKeyPair;
-    credential->createEphemeralKeyPair(
-            [&](const Result& _result, const hidl_vec<uint8_t>& _ephemeralKeyPair) {
-                result = _result;
-                ephemeralKeyPair = _ephemeralKeyPair;
-            });
-    EXPECT_EQ("", result.message);
-    ASSERT_EQ(ResultCode::OK, result.code);
-    optional<vector<uint8_t>> ephemeralPublicKey = support::ecKeyPairGetPublicKey(ephemeralKeyPair);
-
-    // Calculate requestData field and sign it with the reader key.
-    auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ephemeralPublicKey.value());
-    ASSERT_TRUE(getXYSuccess);
-    cppbor::Map deviceEngagement = cppbor::Map().add("ephX", ephX).add("ephY", ephY);
-    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));
-    vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
-
-    vector<uint8_t> itemsRequestBytes =
-            cppbor::Map("nameSpaces",
-                        cppbor::Map()
-                                .add("PersonalData", cppbor::Map()
-                                                             .add("Last name", false)
-                                                             .add("Birth date", false)
-                                                             .add("First name", false)
-                                                             .add("Home address", true))
-                                .add("Image", cppbor::Map().add("Portrait image", false)))
-                    .encode();
-    cborPretty = support::cborPrettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
-    EXPECT_EQ(
-            "{\n"
-            "  'nameSpaces' : {\n"
-            "    'PersonalData' : {\n"
-            "      'Last name' : false,\n"
-            "      'Birth date' : false,\n"
-            "      'First name' : false,\n"
-            "      'Home address' : true,\n"
-            "    },\n"
-            "    'Image' : {\n"
-            "      'Portrait image' : false,\n"
-            "    },\n"
-            "  },\n"
-            "}",
-            cborPretty);
-    vector<uint8_t> dataToSign = cppbor::Array()
-                                         .add("ReaderAuthentication")
-                                         .add(sessionTranscript.clone())
-                                         .add(cppbor::Semantic(24, itemsRequestBytes))
-                                         .encode();
-    optional<vector<uint8_t>> readerSignature =
-            support::coseSignEcDsa(readerKey.value(), {},  // content
-                                   dataToSign,             // detached content
-                                   readerCertificate.value());
-    ASSERT_TRUE(readerSignature);
-
-    credential->startRetrieval(returnedSecureProfiles, authToken, itemsRequestBytes,
-                               sessionTranscriptBytes, readerSignature.value(),
-                               testEntriesEntryCounts,
-                               [&](const Result& _result) { result = _result; });
-    EXPECT_EQ("", result.message);
-    ASSERT_EQ(ResultCode::OK, result.code);
-
-    for (const auto& entry : testEntries) {
-        credential->startRetrieveEntryValue(entry.nameSpace, entry.name, entry.valueCbor.size(),
-                                            entry.profileIds,
-                                            [&](const Result& _result) { result = _result; });
-        EXPECT_EQ("", result.message);
-        ASSERT_EQ(ResultCode::OK, result.code);
-
-        auto it = encryptedBlobs.find(&entry);
-        ASSERT_NE(it, encryptedBlobs.end());
-        const vector<vector<uint8_t>>& encryptedChunks = it->second;
-
-        vector<uint8_t> content;
-        for (const auto& encryptedChunk : encryptedChunks) {
-            vector<uint8_t> chunk;
-            credential->retrieveEntryValue(
-                    encryptedChunk, [&](const Result& _result, const hidl_vec<uint8_t>& _chunk) {
-                        result = _result;
-                        chunk = _chunk;
-                    });
-            EXPECT_EQ("", result.message);
-            ASSERT_EQ(ResultCode::OK, result.code);
-            content.insert(content.end(), chunk.begin(), chunk.end());
-        }
-        EXPECT_EQ(content, entry.valueCbor);
-    }
-
-    // Generate the key that will be used to sign AuthenticatedData.
-    vector<uint8_t> signingKeyBlob;
-    vector<uint8_t> signingKeyCertificate;
-    credential->generateSigningKeyPair([&](const Result& _result,
-                                           const hidl_vec<uint8_t> _signingKeyBlob,
-                                           const hidl_vec<uint8_t> _signingKeyCertificate) {
-        result = _result;
-        signingKeyBlob = _signingKeyBlob;
-        signingKeyCertificate = _signingKeyCertificate;
-    });
-    EXPECT_EQ("", result.message);
-    ASSERT_EQ(ResultCode::OK, result.code);
-
-    vector<uint8_t> mac;
-    vector<uint8_t> deviceNameSpacesBytes;
-    credential->finishRetrieval(signingKeyBlob,
-                                [&](const Result& _result, const hidl_vec<uint8_t> _mac,
-                                    const hidl_vec<uint8_t> _deviceNameSpacesBytes) {
-                                    result = _result;
-                                    mac = _mac;
-                                    deviceNameSpacesBytes = _deviceNameSpacesBytes;
-                                });
-    EXPECT_EQ("", result.message);
-    ASSERT_EQ(ResultCode::OK, result.code);
-    cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
-    ASSERT_EQ(
-            "{\n"
-            "  'PersonalData' : {\n"
-            "    'Last name' : 'Turing',\n"
-            "    'Birth date' : '19120623',\n"
-            "    'First name' : 'Alan',\n"
-            "    'Home address' : 'Maida Vale, London, England',\n"
-            "  },\n"
-            "  'Image' : {\n"
-            "    'Portrait image' : <bstr size=262134 "
-            "sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
-            "  },\n"
-            "}",
-            cborPretty);
-    // The data that is MACed is ["DeviceAuthentication", sessionTranscriptBytes, docType,
-    // deviceNameSpacesBytes] so build up that structure
-    cppbor::Array deviceAuthentication;
-    deviceAuthentication.add("DeviceAuthentication");
-    deviceAuthentication.add(sessionTranscript.clone());
-    deviceAuthentication.add(docType);
-    deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
-    vector<uint8_t> encodedDeviceAuthentication = deviceAuthentication.encode();
-    optional<vector<uint8_t>> signingPublicKey =
-            support::certificateChainGetTopMostKey(signingKeyCertificate);
-    EXPECT_TRUE(signingPublicKey);
-
-    // Derive the key used for MACing.
-    optional<vector<uint8_t>> readerEphemeralPrivateKey =
-            support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
-    optional<vector<uint8_t>> sharedSecret =
-            support::ecdh(signingPublicKey.value(), readerEphemeralPrivateKey.value());
-    ASSERT_TRUE(sharedSecret);
-    vector<uint8_t> salt = {0x00};
-    vector<uint8_t> info = {};
-    optional<vector<uint8_t>> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32);
-    ASSERT_TRUE(derivedKey);
-    optional<vector<uint8_t>> calculatedMac =
-            support::coseMac0(derivedKey.value(), {},        // payload
-                              encodedDeviceAuthentication);  // detached content
-    ASSERT_TRUE(calculatedMac);
-    EXPECT_EQ(mac, calculatedMac);
-}
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, IdentityCredentialStoreHidlTest,
-                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
-                                 IIdentityCredentialStore::descriptor)),
-                         android::hardware::PrintInstanceNameToString);
-
-}  // namespace test
-}  // namespace identity
-}  // namespace hardware
-}  // namespace android
diff --git a/identity/1.0/vts/OWNERS b/identity/OWNERS
similarity index 100%
rename from identity/1.0/vts/OWNERS
rename to identity/OWNERS
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
new file mode 100644
index 0000000..72b19a1
--- /dev/null
+++ b/identity/aidl/Android.bp
@@ -0,0 +1,21 @@
+aidl_interface {
+    name: "android.hardware.identity",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/identity/*.aidl",
+    ],
+    imports: [
+        "android.hardware.keymaster",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+}
diff --git a/radio/config/1.3/IRadioConfigIndication.hal b/identity/aidl/android/hardware/identity/Certificate.aidl
similarity index 63%
copy from radio/config/1.3/IRadioConfigIndication.hal
copy to identity/aidl/android/hardware/identity/Certificate.aidl
index 9ef496c..5bbc17c 100644
--- a/radio/config/1.3/IRadioConfigIndication.hal
+++ b/identity/aidl/android/hardware/identity/Certificate.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.config@1.3;
+package android.hardware.identity;
 
-import @1.2::IRadioConfigIndication;
-
-/**
- * Interface declaring unsolicited radio config indications.
- */
-interface IRadioConfigIndication extends @1.2::IRadioConfigIndication {
-
-};
+@VintfStability
+parcelable Certificate {
+    /**
+     * encodedCertificate contains the bytes of a DER-encoded X.509 certificate.
+     *
+     * If there is no certificate, this array is empty.
+     */
+    byte[] encodedCertificate;
+}
diff --git a/identity/aidl/android/hardware/identity/CipherSuite.aidl b/identity/aidl/android/hardware/identity/CipherSuite.aidl
new file mode 100644
index 0000000..20b02a8
--- /dev/null
+++ b/identity/aidl/android/hardware/identity/CipherSuite.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.identity;
+
+/**
+ * Cipher suites that can be used for communication between holder and reader devices.
+ */
+@VintfStability
+@Backing(type="int")
+enum CipherSuite {
+    /**
+     * Specifies that the cipher suite that will be used to secure communications between the reader
+     * is:
+     *
+     * - ECDHE with HKDF-SHA-256 for key agreement.
+     * - AES-256 with GCM block mode for authenticated encryption (nonces are incremented by
+     *   one for every message).
+     * - ECDSA with SHA-256 for signing (used for signing session transcripts to defeat
+     *   man-in-the-middle attacks), signing keys are not ephemeral.
+     *
+     * At present this is the only supported cipher suite and it is mandatory for all
+     * implementations to support it.
+     */
+    CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1,
+}
diff --git a/identity/aidl/android/hardware/identity/HardwareInformation.aidl b/identity/aidl/android/hardware/identity/HardwareInformation.aidl
new file mode 100644
index 0000000..d67739d
--- /dev/null
+++ b/identity/aidl/android/hardware/identity/HardwareInformation.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.identity;
+
+@VintfStability
+parcelable HardwareInformation {
+    /**
+     * credentialStoreName is the name of the credential store implementation.
+     */
+    @utf8InCpp String credentialStoreName;
+
+    /**
+     * credentialStoreAuthorName is the name of the credential store author.
+     */
+    @utf8InCpp String credentialStoreAuthorName;
+
+    /**
+     * dataChunkSize is the size of data chunks to be used when sending and recieving data
+     * entries. All data chunks for a data item must be this size except for the last.
+     */
+    int dataChunkSize;
+
+    /**
+     * isDirectAccess specifies whether the provisioned credential is available through
+     * direct access. Credentials provisioned in credential stores with this set
+     * to true, should use reader authentication on all data elements.
+     */
+    boolean isDirectAccess;
+
+    /**
+     * supportedDocTypes if empty, then any document type is supported, otherwise
+     * only the document types returned are supported.
+     *
+     * Document types are defined in the relevant standard for the document, for example for the
+     * for Mobile Driving License as defined by ISO 18013-5 the document type is defined to
+     * be "org.iso.18013.5.1.mDL".
+     *
+     */
+    @utf8InCpp String[] supportedDocTypes;
+}
diff --git a/identity/1.0/IIdentityCredential.hal b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
similarity index 75%
rename from identity/1.0/IIdentityCredential.hal
rename to identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 75f6e18..10ce4c2 100644
--- a/identity/1.0/IIdentityCredential.hal
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.identity@1.0;
+package android.hardware.identity;
 
-import android.hardware.keymaster@4.0::HardwareAuthToken;
+import android.hardware.identity.Certificate;
+import android.hardware.identity.SecureAccessControlProfile;
+import android.hardware.keymaster.HardwareAuthToken;
 
+@VintfStability
 interface IIdentityCredential {
     /**
      * Delete a credential.
@@ -35,10 +38,9 @@
      * After this method has been called, the persistent storage used for credentialData should
      * be deleted.
      *
-     * @return proofOfDeletionSignature is a COSE_Sign1 signature described above.
+     * @return a COSE_Sign1 signature described above.
      */
-    deleteCredential()
-        generates(Result result, vec<uint8_t> proofOfDeletionSignature);
+    byte[] deleteCredential();
 
     /**
      * Creates an ephemeral EC key pair, for use in establishing a seceure session with a reader.
@@ -46,39 +48,33 @@
      * with the reader.  The reason for generating the key pair in the secure environment is so that
      * the secure environment knows what public key to expect to find in the session transcript.
      *
-     * This method may only be called once per instance. If called more than once, FAILED
+     * This method may only be called once per instance. If called more than once, STATUS_FAILED
      * will be returned.
      *
-     * @return result is OK on success or FAILED if an error occurred.
-     *
-     * @return keyPair contains the unencrypted key-pair in PKCS#8 format.
+     * @return the unencrypted key-pair in PKCS#8 format.
      */
-    createEphemeralKeyPair() generates (Result result, vec<uint8_t> keyPair);
+    byte[] createEphemeralKeyPair();
 
     /**
      * Sets the public part of the reader's ephemeral key pair.
      *
-     * This method may only be called once per instance. If called more than once, FAILED
+     * This method may only be called once per instance. If called more than once, STATUS_FAILED
      * will be returned.
      *
      * @param publicKey contains the reader's ephemeral public key, in uncompressed form.
-     *
-     * @return result is OK on success or FAILED if an error occurred.
      */
-    setReaderEphemeralPublicKey(vec<uint8_t> publicKey) generates (Result result);
+    void setReaderEphemeralPublicKey(in byte[] publicKey);
 
     /**
      * Creates a challenge value to be used for proving successful user authentication. This
      * is included in the authToken passed to the startRetrieval() method.
      *
-     * This method may only be called once per instance. If called more than once, FAILED
+     * This method may only be called once per instance. If called more than once, STATUS_FAILED
      * will be returned.
      *
-     * @return result is OK on success or FAILED if an error occurred.
-     *
-     * @return challenge on success, is a non-zero number.
+     * @return challenge, a non-zero number.
      */
-    createAuthChallenge() generates (Result result, uint64_t challenge);
+    long createAuthChallenge();
 
     /**
      * Start an entry retrieval process.
@@ -92,12 +88,12 @@
      * startRetrieval(), then multiple calls of startRetrieveEntryValue(), retrieveEntryValue(),
      * then finally finishRetrieval()) but if this is done, the sessionTranscript parameter
      * must be identical for each startRetrieval() invocation. If this is not the case, this call
-     * fails with the SESSION_TRANSCRIPT_MISMATCH error.
+     * fails with the STATUS_SESSION_TRANSCRIPT_MISMATCH error.
      *
-     * If the provided authToken is not valid this method fails with INVALID_AUTH_TOKEN.
+     * If the provided authToken is not valid this method fails with STATUS_INVALID_AUTH_TOKEN.
      *
      * Each of the provided accessControlProfiles is checked in this call. If they are not
-     * all valid, the call fails with INVALID_DATA.
+     * all valid, the call fails with STATUS_INVALID_DATA.
      *
      * For the itemsRequest parameter, the content can be defined in the way appropriate for
      * the credential, but there are three requirements that must be met to work with this HAL:
@@ -108,7 +104,7 @@
      *     the example below.
      *
      * If these requirements are not met the startRetrieval() call fails with
-     * INVALID_ITEMS_REQUEST_MESSAGE.
+     * STATUS_INVALID_ITEMS_REQUEST_MESSAGE.
      *
      * Here's an example of ItemsRequest CBOR which conforms to this requirement:
      *
@@ -156,17 +152,18 @@
      * 'x5chain' unprotected header element of the COSE_Sign1 structure (as as described
      * in 'draft-ietf-cose-x509-04'). There will be at least one certificate in said element
      * and there may be more (and if so, each certificate must be signed by its successor).
-     * This is checked and if the check fails the call fails with READER_SIGNATURE_CHECK_FAILED.
+     * This is checked and if the check fails the call fails with
+     * STATUS_READER_SIGNATURE_CHECK_FAILED.
      *
      * The SessionTranscript CBOR is conveyed in the sessionTranscript parameter. It
      * is permissible for this to be empty in which case the readerSignature parameter
-     * must also be empty. If this is not the case, the call fails with FAILED.
+     * must also be empty. If this is not the case, the call fails with STATUS_FAILED.
      *
      * If the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
      * part of the key-pair previously generated by createEphemeralKeyPair() must appear
      * somewhere in the bytes of DeviceEngagement structure. Both X and Y should be in
      * uncompressed form. If this is not satisfied, the call fails with
-     * EPHEMERAL_PUBLIC_KEY_NOT_FOUND.
+     * STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND.
      *
      * @param accessControlProfiles
      *   Access control profiles that are required to retrieve the entries that are going to be
@@ -196,16 +193,11 @@
      *   will succeed (i.e. that the access control profile checks will succeed).  This means that
      *   it's the responsibility of the caller to determine which access control checks will fail
      *   and remove the corresponding requests from the counts.
-     *
-     * @return result is OK on success. If an error occurs one of the values described above
-     *   will be returned.
      */
-    startRetrieval(vec<SecureAccessControlProfile> accessControlProfiles,
-                   HardwareAuthToken authToken,
-                   vec<uint8_t> itemsRequest,
-                   vec<uint8_t> sessionTranscript,
-                   vec<uint8_t> readerSignature,
-                   vec<uint16_t> requestCounts) generates(Result result);
+    void startRetrieval(in SecureAccessControlProfile[] accessControlProfiles,
+        in HardwareAuthToken authToken,
+        in byte[] itemsRequest,
+        in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
 
     /**
      * Starts retrieving an entry, subject to access control requirements.  Entries must be
@@ -213,15 +205,15 @@
      *
      * If the requestData parameter as passed to startRetrieval() was non-empty
      * this method must only be called with entries specified in that field. If this
-     * requirement is not met, the call fails with NOT_IN_REQUEST_MESSAGE.
+     * requirement is not met, the call fails with STATUS_NOT_IN_REQUEST_MESSAGE.
      *
-     * If nameSpace or name is empty this call fails with INVALID_DATA.
+     * If nameSpace or name is empty this call fails with STATUS_INVALID_DATA.
      *
      * Each access control profile for the entry is checked. If user authentication
      * is required and the supplied auth token doesn't provide it the call fails
-     * with USER_AUTHENTICATION_FAILED. If reader authentication is required and
+     * with STATUS_USER_AUTHENTICATION_FAILED. If reader authentication is required and
      * a suitable reader certificate chain isn't presented, the call fails with
-     * READER_AUTHENTICATION_FAILED.
+     * STATUS_READER_AUTHENTICATION_FAILED.
      *
      * It is permissible to keep retrieving values if an access control check fails.
      *
@@ -231,38 +223,29 @@
      *
      * @param entrySize is the size of the entry value, if it's a text string or a byte string.
      *     It must be zero if the entry value is an integer or boolean. If this requirement
-     *     is not met the call fails with INVALID_DATA.
+     *     is not met the call fails with STATUS_INVALID_DATA.
      *
      * @param accessControlProfileIds specifies the set of access control profiles that can
      *     authorize access to the provisioned element. If an identifier of a profile
      *     is given and this profile wasn't passed to startRetrieval() this call fails
-     *     with INVALID_DATA.
-     *
-     * @return result is OK on success. Otherwise one of INVALID_DATA, FAILED,
-     *     USER_AUTHENTICATION_FAILED, READER_AUTHENTICATION_FAILED.
+     *     with STATUS_INVALID_DATA.
      */
-    startRetrieveEntryValue(string nameSpace, string name, uint32_t entrySize,
-                            vec<uint16_t> accessControlProfileIds)
-        generates (Result result);
-
+    void startRetrieveEntryValue(in @utf8InCpp String nameSpace, in @utf8InCpp String name,
+                                 in int entrySize, in int[] accessControlProfileIds);
 
     /**
      * Retrieves an entry value, or part of one, if the entry value is larger than gcmChunkSize.
      * May only be called after startRetrieveEntry().
      *
      * If the passed in data is not authentic, can't be decrypted, is of the wrong size, or can't
-     * be decoded, this call fails with INVALID_DATA.
+     * be decoded, this call fails with STATUS_INVALID_DATA.
      *
      * @param encryptedContent contains the encrypted and MACed content.
      *
-     * @return result is OK on success, INVALID_DATA, or FAILED if an error occurred.
-     *
-     * @return content is the entry value as CBOR, or part of the entry value in the case the
+     * @return the entry value as CBOR, or part of the entry value in the case the
      *    content exceeds gcmChunkSize in length.
      */
-    retrieveEntryValue(vec<uint8_t> encryptedContent)
-        generates (Result result, vec<uint8_t> content);
-
+    byte[] retrieveEntryValue(in byte[] encryptedContent);
 
     /**
      * End retrieval of data, optionally returning a message authentication code over the
@@ -273,11 +256,9 @@
      *
      * @param signingKeyBlob is either empty or a signingKeyBlob (see generateSigningKeyPair(),
      *    below) containing the signing key to use to sign the data retrieved. If this
-     *    is not in the right format the call fails with INVALID_DATA.
+     *    is not in the right format the call fails with STATUS_INVALID_DATA.
      *
-     * @return result is OK on success, INVALID_DATA or FAILED if an error occurred.
-     *
-     * @return mac is empty if signingKeyBlob or the sessionTranscript passed to
+     * @param out mac is empty if signingKeyBlob or the sessionTranscript passed to
      *    startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload
      *    and the detached content is set to DeviceAuthentication as defined below.
      *    The key used for the MAC operation is EMacKey and is derived as follows:
@@ -321,23 +302,17 @@
      *        DataItemValue = any
      *
      *
-     * @return deviceNameSpaces the bytes of DeviceNameSpaces.
+     * @param out deviceNameSpaces the bytes of DeviceNameSpaces.
      */
-    finishRetrieval(vec<uint8_t> signingKeyBlob)
-        generates(Result result, vec<uint8_t> mac, vec<uint8_t> deviceNameSpaces);
-
+    void finishRetrieval(in byte[] signingKeyBlob, out byte[] mac, out byte[] deviceNameSpaces);
 
     /**
      * Generate a key pair to be used for signing session data and retrieved data items.
      *
-     * @return result is OK on success or FAILED if an error occurred.
+     * @param out signingKeyBlob contains an encrypted copy of the newly-generated private
+     *     signing key.
      *
-     * @return signingKeyBlob contains an encrypted copy of the newly-generated private signing key.
-     *
-     * @return signingKeyCertificate contains an X.509 certificate for the new signing key, signed
-     *     by the credential key.
+     * @return an X.509 certificate for the new signing key, signed by the credential key.
      */
-    generateSigningKeyPair()
-        generates(Result result, vec<uint8_t> signingKeyBlob,
-                  vec<uint8_t> signingKeyCertificate);
-};
+    Certificate generateSigningKeyPair(out byte[] signingKeyBlob);
+}
diff --git a/identity/1.0/IIdentityCredentialStore.hal b/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl
similarity index 67%
rename from identity/1.0/IIdentityCredentialStore.hal
rename to identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl
index 118ca6f..23cb1b7 100644
--- a/identity/1.0/IIdentityCredentialStore.hal
+++ b/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package android.hardware.identity@1.0;
+package android.hardware.identity;
 
-import IWritableIdentityCredential;
-import IIdentityCredential;
+import android.hardware.identity.IIdentityCredential;
+import android.hardware.identity.IWritableIdentityCredential;
+import android.hardware.identity.HardwareInformation;
+import android.hardware.identity.CipherSuite;
 
 /**
  * IIdentityCredentialStore provides an interface to a secure store for user identity documents.
@@ -98,37 +100,90 @@
  * define appropriate encodings, those are used.  For example, X.509 certificates.  Where new
  * encodings are needed, CBOR is used.  CBOR maps are described in CDDL notation
  * (https://tools.ietf.org/html/draft-ietf-cbor-cddl-06).
+ *
+ * All binder calls in the HAL may return a ServiceSpecificException with statuses from the
+ * STATUS_* integers defined in this interface. Each method states which status can be returned
+ * and under which circumstances.
  */
+@VintfStability
 interface IIdentityCredentialStore {
+    /**
+     * Success.
+     */
+    const int STATUS_OK = 0;
+
+    /**
+     * The operation failed. This is used as a generic catch-all for errors that don't belong
+     * in other categories, including memory/resource allocation failures and I/O errors.
+     */
+    const int STATUS_FAILED = 1;
+
+    /**
+     * Unsupported cipher suite.
+     */
+    const int STATUS_CIPHER_SUITE_NOT_SUPPORTED = 2;
+
+    /**
+     * The passed data was invalid. This is a generic catch all for errors that don't belong
+     * in other categories related to parameter validation.
+     */
+    const int STATUS_INVALID_DATA = 3;
+
+    /**
+     * The authToken parameter passed to IIdentityCredential.startRetrieval() is not valid.
+     */
+    const int STATUS_INVALID_AUTH_TOKEN = 4;
+
+    /**
+     * The itemsRequest parameter passed to IIdentityCredential.startRetrieval() does not meet
+     * the requirements described in the documentation for that method.
+     */
+    const int STATUS_INVALID_ITEMS_REQUEST_MESSAGE = 5;
+
+    /**
+     * The readerSignature parameter in IIdentityCredential.startRetrieval() is invalid,
+     * doesn't contain an embedded certificate chain, or the signature failed to
+     * validate.
+     */
+    const int STATUS_READER_SIGNATURE_CHECK_FAILED = 6;
+
+    /**
+     * The sessionTranscript passed to startRetrieval() did not contain the ephmeral public
+     * key returned by createEphemeralPublicKey().
+     */
+    const int STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND = 7;
+
+    /**
+     * An access condition related to user authentication was not satisfied.
+     */
+    const int STATUS_USER_AUTHENTICATION_FAILED = 8;
+
+    /**
+     * An access condition related to reader authentication was not satisfied.
+     */
+    const int STATUS_READER_AUTHENTICATION_FAILED = 9;
+
+    /**
+     * The request data element has no access control profiles associated so it cannot be accessed.
+     */
+    const int STATUS_NO_ACCESS_CONTROL_PROFILES = 10;
+
+    /**
+     * The requested data element is not in the provided non-empty itemsRequest message.
+     */
+    const int STATUS_NOT_IN_REQUEST_MESSAGE = 11;
+
+    /**
+     * The passed-in sessionTranscript doesn't match the previously passed-in sessionTranscript.
+     */
+    const int STATUS_SESSION_TRANSCRIPT_MISMATCH = 12;
 
     /**
      * Returns information about hardware.
      *
-     * The isDirectAccess output parameter indicates whether this credential store
-     * implementation is for direct access. Credentials provisioned in credential
-     * stores with this set to true, should use reader authentication on all data elements.
-     *
-     * @return result is OK on success, FAILED if an error occurred.
-     *
-     * @return credentialStoreName the name of the credential store implementation.
-     *
-     * @return credentialStoreAuthorName the name of the credential store author.
-     *
-     * @return dataChunkSize the maximum size of data chunks.
-     *
-     * @return isDirectAccess whether the provisioned credential is available through
-     *     direct access.
-     *
-     * @return supportedDocTypes if empty, then any document type is supported, otherwise
-     *     only the document types returned are supported.
+     * @return a HardwareInformation with information about the hardware.
      */
-    getHardwareInformation()
-        generates(Result result,
-                  string credentialStoreName,
-                  string credentialStoreAuthorName,
-                  uint32_t dataChunkSize,
-                  bool isDirectAccess,
-                  vec<string> supportedDocTypes);
+    HardwareInformation getHardwareInformation();
 
     /**
      * createCredential creates a new Credential.  When a Credential is created, two cryptographic
@@ -147,16 +202,14 @@
      *     all-zeros hardware-bound key (HBK) and must set the test bit in the
      *     personalizationReceipt (see finishAddingEntries(), in IWritableIdentityCredential).
      *
-     * @return result is OK on success, FAILED if an error occurred.
-     *
-     * @return writableCredential is an IWritableIdentityCredential HIDL interface that provides
-     *     operations to provision a credential.
+     * @return an IWritableIdentityCredential interface that provides operations to
+     *     provision a credential.
      */
-    createCredential(string docType, bool testCredential)
-        generates(Result result, IWritableIdentityCredential writableCredential);
+    IWritableIdentityCredential createCredential(in @utf8InCpp String docType,
+                                                 in boolean testCredential);
 
     /**
-     * getCredential retrieves an IIdentityCredential HIDL interface which allows use of a stored
+     * getCredential retrieves an IIdentityCredential interface which allows use of a stored
      * Credential.
      *
      * The cipher suite used to communicate with the remote verifier must also be specified. Currently
@@ -170,16 +223,17 @@
      *
      * Support for other cipher suites may be added in a future version of this HAL.
      *
+     * This method fails with STATUS_INVALID_DATA if the passed in credentialData cannot be
+     * decoded or decrypted.
+     *
+     * @param cipherSuite is the cipher suite to use.
+     *
      * @param credentialData is a CBOR-encoded structure containing metadata about the credential
      *     and an encrypted byte array that contains data used to secure the credential.  See the
-     *     return argument of the same name in finishAddingEntries(), in IWritableIdentityCredential.
+     *     return argument of the same name in finishAddingEntries(), in
+     *     IWritableIdentityCredential.
      *
-     * @return result is OK on success or INVALID_DATA if the passed in credentialData
-     *     cannot be decoded or decrypted.
-     *
-     * @return credential is an IIdentityCredential HIDL interface that provides operations on the
-     *     Credential.
+     * @return an IIdentityCredential HIDL interface that provides operations on the Credential.
      */
-    getCredential(vec<uint8_t> credentialData)
-        generates (Result result, IIdentityCredential credential);
-};
+    IIdentityCredential getCredential(in CipherSuite cipherSuite, in byte[] credentialData);
+}
diff --git a/identity/1.0/IWritableIdentityCredential.hal b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
similarity index 62%
rename from identity/1.0/IWritableIdentityCredential.hal
rename to identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
index b1ce00d..483b0c7 100644
--- a/identity/1.0/IWritableIdentityCredential.hal
+++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -14,50 +14,82 @@
  * limitations under the License.
  */
 
-package android.hardware.identity@1.0;
+package android.hardware.identity;
+
+import android.hardware.identity.Certificate;
+import android.hardware.identity.SecureAccessControlProfile;
 
 /**
  * IWritableIdentityCredential is used to personalize a new identity credential.  Credentials cannot
  * be updated or modified after creation; any changes require deletion and re-creation.
  */
+@VintfStability
 interface IWritableIdentityCredential {
     /**
      * Gets the certificate chain for credentialKey which can be used to prove the hardware
      * characteristics to an issuing authority.  Must not be called more than once.
      *
      * The certificate chain must be generated using Keymaster Attestation
-     * (see https://source.android.com/security/keystore/attestation) and must also
-     * have the Tag::IDENTITY_CREDENTIAL_KEY tag from KeyMaster 4.1 set. This tag indicates
-     * that this key is an Identity Credential key (which can only sign/MAC very
-     * specific messages) and not an Android Keystore key (which can be used to sign/MAC
-     * anything).
+     * (see https://source.android.com/security/keystore/attestation) with the
+     * following additional requirements:
+     *
+     *  - The attestationVersion field in the attestation extension must be at least 3.
+     *
+     *  - The attestationSecurityLevel field must be set to either Software (0),
+     *    TrustedEnvironment (1), or StrongBox (2) depending on how attestation is
+     *    implemented. Only the default AOSP implementation of this HAL may use
+     *    value 0 (additionally, this implementation must not be used on production
+     *    devices).
+     *
+     *  - The keymasterVersion field in the attestation extension must be set to (10*major + minor)
+     *    where major and minor are the Identity Credential interface major and minor versions.
+     *    Specifically for this version of the interface (1.0) this value is 10.
+     *
+     *  - The keymasterSecurityLevel field in the attestation extension must be set to
+     *    either Software (0), TrustedEnvironment (1), or StrongBox (2) depending on how
+     *    the Trusted Application backing the HAL implementation is implemented. Only
+     *    the default AOSP implementation of this HAL may use value 0 (additionally, this
+     *    implementation must not be used on production devices)
+     *
+     *  - The attestationChallenge field must be set to the passed-in challenge.
+     *
+     *  - The uniqueId field must be empty.
+     *
+     *  - The softwareEnforced field in the attestation extension must include
+     *    Tag::ATTESTATION_APPLICATION_ID which must be set to the bytes of the passed-in
+     *    attestationApplicationId.
+     *
+     *  - The teeEnforced field in the attestation extension must include
+     *    Tag::IDENTITY_CREDENTIAL_KEY. This tag indicates that the key is an Identity
+     *    Credential key (which can only sign/MAC very specific messages) and not an Android
+     *    Keystore key (which can be used to sign/MAC anything).
+     *
+     * Additional authorizations may be needed in the softwareEnforced and teeEnforced
+     * fields - the above is not an exhaustive list.
+     *
+     * @param attestationApplicationId is the DER encoded value to be stored
+     *     in Tag::ATTESTATION_APPLICATION_ID. This schema is described in
+     *     https://developer.android.com/training/articles/security-key-attestation#certificate_schema_attestationid
      *
      * @param attestationChallenge a challenge set by the issuer to ensure freshness.
      *
-     * @return result is OK on success, FAILED if an error occurred.
-     *
-     * @return certificate is the X.509 certificate chain for the credentialKey
+     * @return the X.509 certificate chain for the credentialKey
      */
-    getAttestationCertificate(vec<uint8_t> attestationChallenge)
-        generates(Result result, vec<uint8_t> certificate);
+    Certificate[] getAttestationCertificate(in byte[] attestationApplicationId, in byte[] attestationChallenge);
 
     /**
      * Start the personalization process.
      *
      * startPersonalization must not be called more than once.
      *
-     * @param accessControlProfileCount specifies the number of access control profiles that will be
-     *     provisioned with addAccessControlProfile().
+     * @param accessControlProfileCount specifies the number of access control profiles that will
+     *     be provisioned with addAccessControlProfile().
      *
      * @param entryCounts specifies the number of data entries that will be provisioned with
      *     beginAddEntry() and addEntry(). Each item in the array specifies how many entries
      *     will be added for each name space.
-     *
-     * @return result is OK on success, FAILED if an error occurred.
-     *
      */
-    startPersonalization(uint16_t accessControlProfileCount, vec<uint16_t> entryCounts)
-        generates(Result result);
+    void startPersonalization(in int accessControlProfileCount, in int[] entryCounts);
 
     /**
      * Add an access control profile, which defines the requirements or retrieval of one or more
@@ -67,15 +99,15 @@
      *
      * This method must be called exactly as many times as specified in the startPersonalization()
      * accessControlProfileCount parameter. If this is requirement is not met, the method fails
-     * with INVALID_DATA.
+     * with STATUS_INVALID_DATA.
      *
      * @param id a numeric identifier that must be unique within the context of a Credential and may
      *     be used to reference the profile. If this is not satisfied the call fails with
-     *     INVALID_DATA.
+     *     STATUS_INVALID_DATA.
      *
-     * @param readerCertificate if non-empty, specifies a X.509 certificate (or chain of certificates)
-     *     that must be used to authenticate requests (see the readerSignature parameter in
-     *     IIdentityCredential.startRetrieval).
+     * @param readerCertificate if non-empty, specifies a X.509 certificate (or chain of
+     *     certificates) that must be used to authenticate requests (see the readerSignature
+     *     parameter in IIdentityCredential.startRetrieval).
      *
      * @param userAuthenticationRequired if true, specifies that the user is required to
      *     authenticate to allow requests.  Required authentication freshness is specified by
@@ -85,22 +117,18 @@
      *     authentication (see userAuthenticationRequired above) is valid, if
      *     userAuthenticationRequired is true. If the timout is zero then authentication is
      *     required for each reader session. If userAuthenticationRequired is false, the timeout
-     *     must be zero. If this requirement is not met the call fails with INVALID_DATA.
+     *     must be zero. If this requirement is not met the call fails with STATUS_INVALID_DATA.
      *
      * @param secureUserId must be non-zero if userAuthenticationRequired is true. It is not
      *     related to any Android user ID or UID, but is created in the Gatekeeper application
      *     in the secure environment. If this requirement is not met the call fails with
-     *     INVALID_DATA.
+     *     STATUS_INVALID_DATA.
      *
-     * @return result is OK on success, INVALID_DATA or FAILED if an error occurred.
-     *
-     * @return secureAccessControlProfile is a structure with the passed-in data and MAC created
-     *     with storageKey for authenticating the data at a later point in time.
+     * @return a structure with the passed-in data and MAC created with storageKey for authenticating
+     *     the data at a later point in time.
      */
-    addAccessControlProfile(uint16_t id, vec<uint8_t> readerCertificate,
-                            bool userAuthenticationRequired, uint64_t timeoutMillis,
-                            uint64_t secureUserId)
-        generates(Result result, SecureAccessControlProfile secureAccessControlProfile);
+    SecureAccessControlProfile addAccessControlProfile(in int id, in Certificate readerCertificate,
+        in boolean userAuthenticationRequired, in long timeoutMillis, in long secureUserId);
 
     /**
      * Begins the process of adding an entry to the credential.  All access control profiles must be
@@ -109,7 +137,7 @@
      *
      * This method must be called exactly as many times as the sum of the items in the entryCounts
      * parameter specified in the startPersonalization(), and must be followed by one or more calls
-     * to addEntryValue(). If this requirement is not met the method fails with INVALID_DATA.
+     * to addEntryValue(). If this requirement is not met the method fails with STATUS_INVALID_DATA.
      *
      * @param accessControlProfileIds specifies the set of access control profiles that can
      *     authorize access to the provisioned element.
@@ -119,13 +147,10 @@
      * @param name is the name of the element.
      *
      * @param entrySize is the size of the entry value. If this requirement
-     *     is not met this method fails with INVALID_DATA.
-     *
-     * @return result is OK on success, INVALID_DATA or FAILED if an error occurred.
+     *     is not met this method fails with STATUS_INVALID_DATA.
      */
-    beginAddEntry(vec<uint16_t> accessControlProfileIds, string nameSpace,
-                  string name, uint32_t entrySize)
-        generates(Result result);
+    void beginAddEntry(in int[] accessControlProfileIds, in @utf8InCpp String nameSpace,
+        in @utf8InCpp String name, in int entrySize);
 
     /**
      * Continues the process of adding an entry, providing a value or part of a value.
@@ -135,18 +160,13 @@
      * (see IIdentityCredentialStore.getHardwareInformation()), the caller must provide the
      * value in chunks.  All chunks must be exactly gcmChunkSize except the last and the sum of all
      * chunk sizes must equal the value of the beginAddEntry() entrySize argument. If this
-     * requirement is not met the call fails with INVALID_DATA.
+     * requirement is not met the call fails with STATUS_INVALID_DATA.
      *
      * @param content is the entry value, encoded as CBOR. In the case the content exceeds gcmChunkSize,
      *     this may be partial content up to gcmChunkSize bytes long.
      *
-     * @return result is OK on success, INVALID_DATA or FAILED if an error occurred.
-     *
-     * @return encryptedContent contains the encrypted and MACed content.  For directly-available
-     *     credentials the contents are implementation-defined but must not exceed 32 bytes in
-     *     length.
-     *
-     *     For other credentials, encryptedContent contains:
+     * @return the encrypted and MACed content.  For directly-available credentials the contents are
+     *     implementation-defined. For other credentials, the result contains
      *
      *         AES-GCM-ENC(storageKey, R, Data, AdditionalData)
      *
@@ -160,18 +180,15 @@
      *             "AccessControlProfileIds" : [ + uint ],
      *         }
      */
-    addEntryValue(vec<uint8_t> content)
-        generates(Result result, vec<uint8_t> encryptedContent);
+    byte[] addEntryValue(in byte[] content);
 
     /**
-     * Finishes adding entries and returns a signature that an issuing authority may use to validate
-     * that all data was provisioned correctly.
+     * Finishes adding entries and returns a signature that an issuing authority may use to
+     * validate that all data was provisioned correctly.
      *
      * After this method is called, the IWritableIdentityCredential is no longer usable.
      *
-     * @return result is OK on success or FAILED if an error occurred.
-     *
-     * @return credentialData is a CBOR-encoded structure (in CDDL notation):
+     * @param out credentialData is a CBOR-encoded structure (in CDDL notation):
      *
      *         CredentialData = [
      *              tstr,   ; docType, an optional name that identifies the type of credential
@@ -194,10 +211,10 @@
      *              bstr    ; credentialPrivKey, the private key for credentialKey
      *         ]
      *
-     * @return proofOfProvisioningSignature proves to the IA that the credential was imported into the
-     *     secure hardware without alteration or error.  When the final addEntry() call is made
-     *     (when the number of provisioned entries equals the sum of the items in
-     *     startPersonalization() entryCounts parameter), it a COSE_Sign1 structure
+     * @param out proofOfProvisioningSignature proves to the IA that the credential was imported
+     *     into the secure hardware without alteration or error.  When the final addEntry() call is
+     *     made (when the number of provisioned entries equals the sum of the items in
+     *     startPersonalization() entryCounts parameter), a COSE_Sign1 structure
      *     signed by CredentialKey with payload set to the ProofOfProvisioning CBOR below:
      *
      *          ProofOfProvisioning = [
@@ -230,7 +247,6 @@
      *              "accessControlProfiles" : [ * uint ],
      *          }
      */
-    finishAddingEntries()
-        generates(Result result, vec<uint8_t> credentialData,
-                  vec<uint8_t> proofOfProvisioningSignature);
-};
+    void finishAddingEntries(out byte[] credentialData,
+        out byte[] proofOfProvisioningSignature);
+}
diff --git a/identity/aidl/android/hardware/identity/SecureAccessControlProfile.aidl b/identity/aidl/android/hardware/identity/SecureAccessControlProfile.aidl
new file mode 100644
index 0000000..01d312d
--- /dev/null
+++ b/identity/aidl/android/hardware/identity/SecureAccessControlProfile.aidl
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.identity;
+
+import android.hardware.identity.Certificate;
+
+@VintfStability
+parcelable SecureAccessControlProfile {
+    /**
+     * id is a numeric identifier that must be unique within the context of a Credential and may be
+     * used to reference the profile.
+     */
+    int id;
+
+    /**
+     * readerCertificate, if non-empty, specifies a single X.509 certificate (not a chain
+     * of certificates) that must be used to authenticate requests. For details about how
+     * this is done, see the readerSignature paremter of IIdentityCredential.startRetrieval.
+     */
+    Certificate readerCertificate;
+
+    /**
+     * if true, the user is required to authenticate to allow requests.  Required authentication
+     * fressness is specified by timeout below.
+     *
+     */
+    boolean userAuthenticationRequired;
+
+    /**
+     * Timeout specifies the amount of time, in milliseconds, for which a user authentication (see
+     * above) is valid, if userAuthenticationRequired is set to true.  If userAuthenticationRequired
+     * is true and timout is zero then authentication is required for each reader session.
+     *
+     * If userAuthenticationRequired is false, timeout must be zero.
+     */
+    long timeoutMillis;
+
+    /**
+     * secureUserId must be non-zero if userAuthenticationRequired is true.
+     * It is not related to any Android user ID or UID, but is created in the
+     * Gatekeeper application in the secure environment.
+     */
+    long secureUserId;
+
+    /**
+     * The mac is used to authenticate the access control profile.  It contains:
+     *
+     *      AES-GCM-ENC(storageKey, R, {}, AccessControlProfile)
+     *
+     *  where AccessControlProfile is the CBOR map:
+     *
+     *      AccessControlProfile = {
+     *          "id": uint,
+     *          ? "readerCertificate" : bstr,
+     *          ? (
+     *              "userAuthenticationRequired" : bool,
+     *              "timeoutMillis" : uint,
+     *              "secureUserId" : uint
+     *          )
+     *      }
+     */
+    byte[] mac;
+}
+
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
new file mode 100644
index 0000000..2eb0faa
--- /dev/null
+++ b/identity/aidl/default/Android.bp
@@ -0,0 +1,29 @@
+cc_binary {
+    name: "android.hardware.identity-service.example",
+    relative_install_path: "hw",
+    init_rc: ["identity-default.rc"],
+    vintf_fragments: ["identity-default.xml"],
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcppbor",
+        "libcrypto",
+        "liblog",
+        "libutils",
+        "android.hardware.identity-support-lib",
+        "android.hardware.identity-ndk_platform",
+        "android.hardware.keymaster-ndk_platform",
+    ],
+    srcs: [
+        "IdentityCredential.cpp",
+        "IdentityCredentialStore.cpp",
+        "WritableIdentityCredential.cpp",
+        "Util.cpp",
+        "service.cpp",
+    ],
+}
diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp
new file mode 100644
index 0000000..d5b3a0f
--- /dev/null
+++ b/identity/aidl/default/IdentityCredential.cpp
@@ -0,0 +1,768 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IdentityCredential"
+
+#include "IdentityCredential.h"
+#include "IdentityCredentialStore.h"
+#include "Util.h"
+
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+
+#include <string.h>
+
+#include <android-base/logging.h>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+namespace aidl::android::hardware::identity {
+
+using ::aidl::android::hardware::keymaster::Timestamp;
+using ::std::optional;
+
+using namespace ::android::hardware::identity;
+
+int IdentityCredential::initialize() {
+    auto [item, _, message] = cppbor::parse(credentialData_);
+    if (item == nullptr) {
+        LOG(ERROR) << "CredentialData is not valid CBOR: " << message;
+        return IIdentityCredentialStore::STATUS_INVALID_DATA;
+    }
+
+    const cppbor::Array* arrayItem = item->asArray();
+    if (arrayItem == nullptr || arrayItem->size() != 3) {
+        LOG(ERROR) << "CredentialData is not an array with three elements";
+        return IIdentityCredentialStore::STATUS_INVALID_DATA;
+    }
+
+    const cppbor::Tstr* docTypeItem = (*arrayItem)[0]->asTstr();
+    const cppbor::Bool* testCredentialItem =
+            ((*arrayItem)[1]->asSimple() != nullptr ? ((*arrayItem)[1]->asSimple()->asBool())
+                                                    : nullptr);
+    const cppbor::Bstr* encryptedCredentialKeysItem = (*arrayItem)[2]->asBstr();
+    if (docTypeItem == nullptr || testCredentialItem == nullptr ||
+        encryptedCredentialKeysItem == nullptr) {
+        LOG(ERROR) << "CredentialData unexpected item types";
+        return IIdentityCredentialStore::STATUS_INVALID_DATA;
+    }
+
+    docType_ = docTypeItem->value();
+    testCredential_ = testCredentialItem->value();
+
+    vector<uint8_t> hardwareBoundKey;
+    if (testCredential_) {
+        hardwareBoundKey = support::getTestHardwareBoundKey();
+    } else {
+        hardwareBoundKey = getHardwareBoundKey();
+    }
+
+    const vector<uint8_t>& encryptedCredentialKeys = encryptedCredentialKeysItem->value();
+    const vector<uint8_t> docTypeVec(docType_.begin(), docType_.end());
+    optional<vector<uint8_t>> decryptedCredentialKeys =
+            support::decryptAes128Gcm(hardwareBoundKey, encryptedCredentialKeys, docTypeVec);
+    if (!decryptedCredentialKeys) {
+        LOG(ERROR) << "Error decrypting CredentialKeys";
+        return IIdentityCredentialStore::STATUS_INVALID_DATA;
+    }
+
+    auto [dckItem, dckPos, dckMessage] = cppbor::parse(decryptedCredentialKeys.value());
+    if (dckItem == nullptr) {
+        LOG(ERROR) << "Decrypted CredentialKeys is not valid CBOR: " << dckMessage;
+        return IIdentityCredentialStore::STATUS_INVALID_DATA;
+    }
+    const cppbor::Array* dckArrayItem = dckItem->asArray();
+    if (dckArrayItem == nullptr || dckArrayItem->size() != 2) {
+        LOG(ERROR) << "Decrypted CredentialKeys is not an array with two elements";
+        return IIdentityCredentialStore::STATUS_INVALID_DATA;
+    }
+    const cppbor::Bstr* storageKeyItem = (*dckArrayItem)[0]->asBstr();
+    const cppbor::Bstr* credentialPrivKeyItem = (*dckArrayItem)[1]->asBstr();
+    if (storageKeyItem == nullptr || credentialPrivKeyItem == nullptr) {
+        LOG(ERROR) << "CredentialKeys unexpected item types";
+        return IIdentityCredentialStore::STATUS_INVALID_DATA;
+    }
+    storageKey_ = storageKeyItem->value();
+    credentialPrivKey_ = credentialPrivKeyItem->value();
+
+    return IIdentityCredentialStore::STATUS_OK;
+}
+
+ndk::ScopedAStatus IdentityCredential::deleteCredential(
+        vector<int8_t>* outProofOfDeletionSignature) {
+    cppbor::Array array = {"ProofOfDeletion", docType_, testCredential_};
+    vector<uint8_t> proofOfDeletion = array.encode();
+
+    optional<vector<uint8_t>> signature = support::coseSignEcDsa(credentialPrivKey_,
+                                                                 proofOfDeletion,  // payload
+                                                                 {},               // additionalData
+                                                                 {});  // certificateChain
+    if (!signature) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error signing data"));
+    }
+
+    *outProofOfDeletionSignature = byteStringToSigned(signature.value());
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus IdentityCredential::createEphemeralKeyPair(vector<int8_t>* outKeyPair) {
+    optional<vector<uint8_t>> kp = support::createEcKeyPair();
+    if (!kp) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error creating ephemeral key pair"));
+    }
+
+    // Stash public key of this key-pair for later check in startRetrieval().
+    optional<vector<uint8_t>> publicKey = support::ecKeyPairGetPublicKey(kp.value());
+    if (!publicKey) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error getting public part of ephemeral key pair"));
+    }
+    ephemeralPublicKey_ = publicKey.value();
+
+    *outKeyPair = byteStringToSigned(kp.value());
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus IdentityCredential::setReaderEphemeralPublicKey(
+        const vector<int8_t>& publicKey) {
+    readerPublicKey_ = byteStringToUnsigned(publicKey);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus IdentityCredential::createAuthChallenge(int64_t* outChallenge) {
+    uint64_t challenge = 0;
+    while (challenge == 0) {
+        optional<vector<uint8_t>> bytes = support::getRandom(8);
+        if (!bytes) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_FAILED,
+                    "Error getting random data for challenge"));
+        }
+
+        challenge = 0;
+        for (size_t n = 0; n < bytes.value().size(); n++) {
+            challenge |= ((bytes.value())[n] << (n * 8));
+        }
+    }
+
+    *outChallenge = challenge;
+    return ndk::ScopedAStatus::ok();
+}
+
+// TODO: this could be a lot faster if we did all the splitting and pubkey extraction
+// ahead of time.
+bool checkReaderAuthentication(const SecureAccessControlProfile& profile,
+                               const vector<uint8_t>& readerCertificateChain) {
+    optional<vector<uint8_t>> acpPubKey = support::certificateChainGetTopMostKey(
+            byteStringToUnsigned(profile.readerCertificate.encodedCertificate));
+    if (!acpPubKey) {
+        LOG(ERROR) << "Error extracting public key from readerCertificate in profile";
+        return false;
+    }
+
+    optional<vector<vector<uint8_t>>> certificatesInChain =
+            support::certificateChainSplit(readerCertificateChain);
+    if (!certificatesInChain) {
+        LOG(ERROR) << "Error splitting readerCertificateChain";
+        return false;
+    }
+    for (const vector<uint8_t>& certInChain : certificatesInChain.value()) {
+        optional<vector<uint8_t>> certPubKey = support::certificateChainGetTopMostKey(certInChain);
+        if (!certPubKey) {
+            LOG(ERROR)
+                    << "Error extracting public key from certificate in chain presented by reader";
+            return false;
+        }
+        if (acpPubKey.value() == certPubKey.value()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+Timestamp clockGetTime() {
+    struct timespec time;
+    clock_gettime(CLOCK_MONOTONIC, &time);
+    Timestamp ts;
+    ts.milliSeconds = time.tv_sec * 1000 + time.tv_nsec / 1000000;
+    return ts;
+}
+
+bool checkUserAuthentication(const SecureAccessControlProfile& profile,
+                             const HardwareAuthToken& authToken, uint64_t authChallenge) {
+    if (profile.secureUserId != authToken.userId) {
+        LOG(ERROR) << "secureUserId in profile (" << profile.secureUserId
+                   << ") differs from userId in authToken (" << authToken.userId << ")";
+        return false;
+    }
+
+    if (profile.timeoutMillis == 0) {
+        if (authToken.challenge == 0) {
+            LOG(ERROR) << "No challenge in authToken";
+            return false;
+        }
+
+        if (authToken.challenge != int64_t(authChallenge)) {
+            LOG(ERROR) << "Challenge in authToken doesn't match the challenge we created";
+            return false;
+        }
+        return true;
+    }
+
+    // Note that the Epoch for timestamps in HardwareAuthToken is at the
+    // discretion of the vendor:
+    //
+    //   "[...] since some starting point (generally the most recent device
+    //    boot) which all of the applications within one secure environment
+    //    must agree upon."
+    //
+    // Therefore, if this software implementation is used on a device which isn't
+    // the emulator then the assumption that the epoch is the same as used in
+    // clockGetTime above will not hold. This is OK as this software
+    // implementation should never be used on a real device.
+    //
+    Timestamp now = clockGetTime();
+    if (authToken.timestamp.milliSeconds > now.milliSeconds) {
+        LOG(ERROR) << "Timestamp in authToken (" << authToken.timestamp.milliSeconds
+                   << ") is in the future (now: " << now.milliSeconds << ")";
+        return false;
+    }
+    if (now.milliSeconds > authToken.timestamp.milliSeconds + profile.timeoutMillis) {
+        LOG(ERROR) << "Deadline for authToken (" << authToken.timestamp.milliSeconds << " + "
+                   << profile.timeoutMillis << " = "
+                   << (authToken.timestamp.milliSeconds + profile.timeoutMillis)
+                   << ") is in the past (now: " << now.milliSeconds << ")";
+        return false;
+    }
+    return true;
+}
+
+ndk::ScopedAStatus IdentityCredential::startRetrieval(
+        const vector<SecureAccessControlProfile>& accessControlProfiles,
+        const HardwareAuthToken& authToken, const vector<int8_t>& itemsRequestS,
+        const vector<int8_t>& sessionTranscriptS, const vector<int8_t>& readerSignatureS,
+        const vector<int32_t>& requestCounts) {
+    auto sessionTranscript = byteStringToUnsigned(sessionTranscriptS);
+    auto itemsRequest = byteStringToUnsigned(itemsRequestS);
+    auto readerSignature = byteStringToUnsigned(readerSignatureS);
+
+    if (sessionTranscript.size() > 0) {
+        auto [item, _, message] = cppbor::parse(sessionTranscript);
+        if (item == nullptr) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "SessionTranscript contains invalid CBOR"));
+        }
+        sessionTranscriptItem_ = std::move(item);
+    }
+    if (numStartRetrievalCalls_ > 0) {
+        if (sessionTranscript_ != sessionTranscript) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH,
+                    "Passed-in SessionTranscript doesn't match previously used SessionTranscript"));
+        }
+    }
+    sessionTranscript_ = sessionTranscript;
+
+    // If there is a signature, validate that it was made with the top-most key in the
+    // certificate chain embedded in the COSE_Sign1 structure.
+    optional<vector<uint8_t>> readerCertificateChain;
+    if (readerSignature.size() > 0) {
+        readerCertificateChain = support::coseSignGetX5Chain(readerSignature);
+        if (!readerCertificateChain) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED,
+                    "Unable to get reader certificate chain from COSE_Sign1"));
+        }
+
+        if (!support::certificateChainValidate(readerCertificateChain.value())) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED,
+                    "Error validating reader certificate chain"));
+        }
+
+        optional<vector<uint8_t>> readerPublicKey =
+                support::certificateChainGetTopMostKey(readerCertificateChain.value());
+        if (!readerPublicKey) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED,
+                    "Unable to get public key from reader certificate chain"));
+        }
+
+        const vector<uint8_t>& itemsRequestBytes = itemsRequest;
+        vector<uint8_t> dataThatWasSigned = cppbor::Array()
+                                                    .add("ReaderAuthentication")
+                                                    .add(sessionTranscriptItem_->clone())
+                                                    .add(cppbor::Semantic(24, itemsRequestBytes))
+                                                    .encode();
+        if (!support::coseCheckEcDsaSignature(readerSignature,
+                                              dataThatWasSigned,  // detached content
+                                              readerPublicKey.value())) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED,
+                    "readerSignature check failed"));
+        }
+    }
+
+    // Here's where we would validate the passed-in |authToken| to assure ourselves
+    // that it comes from the e.g. biometric hardware and wasn't made up by an attacker.
+    //
+    // However this involves calculating the MAC. However this requires access
+    // to the key needed to a pre-shared key which we don't have...
+    //
+
+    // To prevent replay-attacks, we check that the public part of the ephemeral
+    // key we previously created, is present in the DeviceEngagement part of
+    // SessionTranscript as a COSE_Key, in uncompressed form.
+    //
+    // We do this by just searching for the X and Y coordinates.
+    if (sessionTranscript.size() > 0) {
+        const cppbor::Array* array = sessionTranscriptItem_->asArray();
+        if (array == nullptr || array->size() != 2) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
+                    "SessionTranscript is not an array with two items"));
+        }
+        const cppbor::Semantic* taggedEncodedDE = (*array)[0]->asSemantic();
+        if (taggedEncodedDE == nullptr || taggedEncodedDE->value() != 24) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
+                    "First item in SessionTranscript array is not a "
+                    "semantic with value 24"));
+        }
+        const cppbor::Bstr* encodedDE = (taggedEncodedDE->child())->asBstr();
+        if (encodedDE == nullptr) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
+                    "Child of semantic in first item in SessionTranscript "
+                    "array is not a bstr"));
+        }
+        const vector<uint8_t>& bytesDE = encodedDE->value();
+
+        auto [getXYSuccess, ePubX, ePubY] = support::ecPublicKeyGetXandY(ephemeralPublicKey_);
+        if (!getXYSuccess) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
+                    "Error extracting X and Y from ePub"));
+        }
+        if (sessionTranscript.size() > 0 &&
+            !(memmem(bytesDE.data(), bytesDE.size(), ePubX.data(), ePubX.size()) != nullptr &&
+              memmem(bytesDE.data(), bytesDE.size(), ePubY.data(), ePubY.size()) != nullptr)) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND,
+                    "Did not find ephemeral public key's X and Y coordinates in "
+                    "SessionTranscript (make sure leading zeroes are not used)"));
+        }
+    }
+
+    // itemsRequest: If non-empty, contains request data that may be signed by the
+    // reader.  The content can be defined in the way appropriate for the
+    // credential, but there are three requirements that must be met to work with
+    // this HAL:
+    if (itemsRequest.size() > 0) {
+        // 1. The content must be a CBOR-encoded structure.
+        auto [item, _, message] = cppbor::parse(itemsRequest);
+        if (item == nullptr) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE,
+                    "Error decoding CBOR in itemsRequest"));
+        }
+
+        // 2. The CBOR structure must be a map.
+        const cppbor::Map* map = item->asMap();
+        if (map == nullptr) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE,
+                    "itemsRequest is not a CBOR map"));
+        }
+
+        // 3. The map must contain a key "nameSpaces" whose value contains a map, as described in
+        //    the example below.
+        //
+        //   NameSpaces = {
+        //     + NameSpace => DataElements ; Requested data elements for each NameSpace
+        //   }
+        //
+        //   NameSpace = tstr
+        //
+        //   DataElements = {
+        //     + DataElement => IntentToRetain
+        //   }
+        //
+        //   DataElement = tstr
+        //   IntentToRetain = bool
+        //
+        // Here's an example of an |itemsRequest| CBOR value satisfying above requirements 1.
+        // through 3.:
+        //
+        //    {
+        //        'docType' : 'org.iso.18013-5.2019',
+        //        'nameSpaces' : {
+        //            'org.iso.18013-5.2019' : {
+        //                'Last name' : false,
+        //                'Birth date' : false,
+        //                'First name' : false,
+        //                'Home address' : true
+        //            },
+        //            'org.aamva.iso.18013-5.2019' : {
+        //                'Real Id' : false
+        //            }
+        //        }
+        //    }
+        //
+        const cppbor::Map* nsMap = nullptr;
+        for (size_t n = 0; n < map->size(); n++) {
+            const auto& [keyItem, valueItem] = (*map)[n];
+            if (keyItem->type() == cppbor::TSTR && keyItem->asTstr()->value() == "nameSpaces" &&
+                valueItem->type() == cppbor::MAP) {
+                nsMap = valueItem->asMap();
+                break;
+            }
+        }
+        if (nsMap == nullptr) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE,
+                    "No nameSpaces map in top-most map"));
+        }
+
+        for (size_t n = 0; n < nsMap->size(); n++) {
+            auto [nsKeyItem, nsValueItem] = (*nsMap)[n];
+            const cppbor::Tstr* nsKey = nsKeyItem->asTstr();
+            const cppbor::Map* nsInnerMap = nsValueItem->asMap();
+            if (nsKey == nullptr || nsInnerMap == nullptr) {
+                return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                        IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE,
+                        "Type mismatch in nameSpaces map"));
+            }
+            string requestedNamespace = nsKey->value();
+            vector<string> requestedKeys;
+            for (size_t m = 0; m < nsInnerMap->size(); m++) {
+                const auto& [innerMapKeyItem, innerMapValueItem] = (*nsInnerMap)[m];
+                const cppbor::Tstr* nameItem = innerMapKeyItem->asTstr();
+                const cppbor::Simple* simple = innerMapValueItem->asSimple();
+                const cppbor::Bool* intentToRetainItem =
+                        (simple != nullptr) ? simple->asBool() : nullptr;
+                if (nameItem == nullptr || intentToRetainItem == nullptr) {
+                    return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                            IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE,
+                            "Type mismatch in value in nameSpaces map"));
+                }
+                requestedKeys.push_back(nameItem->value());
+            }
+            requestedNameSpacesAndNames_[requestedNamespace] = requestedKeys;
+        }
+    }
+
+    // Finally, validate all the access control profiles in the requestData.
+    bool haveAuthToken = (authToken.mac.size() > 0);
+    for (const auto& profile : accessControlProfiles) {
+        if (!secureAccessControlProfileCheckMac(profile, storageKey_)) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "Error checking MAC for profile"));
+        }
+        int accessControlCheck = IIdentityCredentialStore::STATUS_OK;
+        if (profile.userAuthenticationRequired) {
+            if (!haveAuthToken || !checkUserAuthentication(profile, authToken, authChallenge_)) {
+                accessControlCheck = IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED;
+            }
+        } else if (profile.readerCertificate.encodedCertificate.size() > 0) {
+            if (!readerCertificateChain ||
+                !checkReaderAuthentication(profile, readerCertificateChain.value())) {
+                accessControlCheck = IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED;
+            }
+        }
+        profileIdToAccessCheckResult_[profile.id] = accessControlCheck;
+    }
+
+    deviceNameSpacesMap_ = cppbor::Map();
+    currentNameSpaceDeviceNameSpacesMap_ = cppbor::Map();
+
+    requestCountsRemaining_ = requestCounts;
+    currentNameSpace_ = "";
+
+    itemsRequest_ = itemsRequest;
+
+    numStartRetrievalCalls_ += 1;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus IdentityCredential::startRetrieveEntryValue(
+        const string& nameSpace, const string& name, int32_t entrySize,
+        const vector<int32_t>& accessControlProfileIds) {
+    if (name.empty()) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA, "Name cannot be empty"));
+    }
+    if (nameSpace.empty()) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA, "Name space cannot be empty"));
+    }
+
+    if (requestCountsRemaining_.size() == 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA,
+                "No more name spaces left to go through"));
+    }
+
+    if (currentNameSpace_ == "") {
+        // First call.
+        currentNameSpace_ = nameSpace;
+    }
+
+    if (nameSpace == currentNameSpace_) {
+        // Same namespace.
+        if (requestCountsRemaining_[0] == 0) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "No more entries to be retrieved in current name space"));
+        }
+        requestCountsRemaining_[0] -= 1;
+    } else {
+        // New namespace.
+        if (requestCountsRemaining_[0] != 0) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "Moved to new name space but one or more entries need to be retrieved "
+                    "in current name space"));
+        }
+        if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) {
+            deviceNameSpacesMap_.add(currentNameSpace_,
+                                     std::move(currentNameSpaceDeviceNameSpacesMap_));
+        }
+        currentNameSpaceDeviceNameSpacesMap_ = cppbor::Map();
+
+        requestCountsRemaining_.erase(requestCountsRemaining_.begin());
+        currentNameSpace_ = nameSpace;
+    }
+
+    // It's permissible to have an empty itemsRequest... but if non-empty you can
+    // only request what was specified in said itemsRequest. Enforce that.
+    if (itemsRequest_.size() > 0) {
+        const auto& it = requestedNameSpacesAndNames_.find(nameSpace);
+        if (it == requestedNameSpacesAndNames_.end()) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE,
+                    "Name space was not requested in startRetrieval"));
+        }
+        const auto& dataItemNames = it->second;
+        if (std::find(dataItemNames.begin(), dataItemNames.end(), name) == dataItemNames.end()) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE,
+                    "Data item name in name space was not requested in startRetrieval"));
+        }
+    }
+
+    // Enforce access control.
+    //
+    // Access is granted if at least one of the profiles grants access.
+    //
+    // If an item is configured without any profiles, access is denied.
+    //
+    int accessControl = IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES;
+    for (auto id : accessControlProfileIds) {
+        auto search = profileIdToAccessCheckResult_.find(id);
+        if (search == profileIdToAccessCheckResult_.end()) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "Requested entry with unvalidated profile id"));
+        }
+        int accessControlForProfile = search->second;
+        if (accessControlForProfile == IIdentityCredentialStore::STATUS_OK) {
+            accessControl = IIdentityCredentialStore::STATUS_OK;
+            break;
+        }
+        accessControl = accessControlForProfile;
+    }
+    if (accessControl != IIdentityCredentialStore::STATUS_OK) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                int(accessControl), "Access control check failed"));
+    }
+
+    entryAdditionalData_ = entryCreateAdditionalData(nameSpace, name, accessControlProfileIds);
+
+    currentName_ = name;
+    entryRemainingBytes_ = entrySize;
+    entryValue_.resize(0);
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus IdentityCredential::retrieveEntryValue(const vector<int8_t>& encryptedContentS,
+                                                          vector<int8_t>* outContent) {
+    auto encryptedContent = byteStringToUnsigned(encryptedContentS);
+
+    optional<vector<uint8_t>> content =
+            support::decryptAes128Gcm(storageKey_, encryptedContent, entryAdditionalData_);
+    if (!content) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA, "Error decrypting data"));
+    }
+
+    size_t chunkSize = content.value().size();
+
+    if (chunkSize > entryRemainingBytes_) {
+        LOG(ERROR) << "Retrieved chunk of size " << chunkSize
+                   << " is bigger than remaining space of size " << entryRemainingBytes_;
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA,
+                "Retrieved chunk is bigger than remaining space"));
+    }
+
+    entryRemainingBytes_ -= chunkSize;
+    if (entryRemainingBytes_ > 0) {
+        if (chunkSize != IdentityCredentialStore::kGcmChunkSize) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "Retrieved non-final chunk of size which isn't kGcmChunkSize"));
+        }
+    }
+
+    entryValue_.insert(entryValue_.end(), content.value().begin(), content.value().end());
+
+    if (entryRemainingBytes_ == 0) {
+        auto [entryValueItem, _, message] = cppbor::parse(entryValue_);
+        if (entryValueItem == nullptr) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "Retrieved data which is invalid CBOR"));
+        }
+        currentNameSpaceDeviceNameSpacesMap_.add(currentName_, std::move(entryValueItem));
+    }
+
+    *outContent = byteStringToSigned(content.value());
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus IdentityCredential::finishRetrieval(const vector<int8_t>& signingKeyBlobS,
+                                                       vector<int8_t>* outMac,
+                                                       vector<int8_t>* outDeviceNameSpaces) {
+    auto signingKeyBlob = byteStringToUnsigned(signingKeyBlobS);
+
+    if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) {
+        deviceNameSpacesMap_.add(currentNameSpace_,
+                                 std::move(currentNameSpaceDeviceNameSpacesMap_));
+    }
+    vector<uint8_t> encodedDeviceNameSpaces = deviceNameSpacesMap_.encode();
+
+    // If there's no signing key or no sessionTranscript or no reader ephemeral
+    // public key, we return the empty MAC.
+    optional<vector<uint8_t>> mac;
+    if (signingKeyBlob.size() > 0 && sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0) {
+        cppbor::Array array;
+        array.add("DeviceAuthentication");
+        array.add(sessionTranscriptItem_->clone());
+        array.add(docType_);
+        array.add(cppbor::Semantic(24, encodedDeviceNameSpaces));
+        vector<uint8_t> encodedDeviceAuthentication = array.encode();
+
+        vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
+        optional<vector<uint8_t>> signingKey =
+                support::decryptAes128Gcm(storageKey_, signingKeyBlob, docTypeAsBlob);
+        if (!signingKey) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "Error decrypting signingKeyBlob"));
+        }
+
+        optional<vector<uint8_t>> sharedSecret =
+                support::ecdh(readerPublicKey_, signingKey.value());
+        if (!sharedSecret) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_FAILED, "Error doing ECDH"));
+        }
+
+        vector<uint8_t> salt = {0x00};
+        vector<uint8_t> info = {};
+        optional<vector<uint8_t>> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32);
+        if (!derivedKey) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_FAILED,
+                    "Error deriving key from shared secret"));
+        }
+
+        mac = support::coseMac0(derivedKey.value(), {},        // payload
+                                encodedDeviceAuthentication);  // additionalData
+        if (!mac) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_FAILED, "Error MACing data"));
+        }
+    }
+
+    *outMac = byteStringToSigned(mac.value_or(vector<uint8_t>({})));
+    *outDeviceNameSpaces = byteStringToSigned(encodedDeviceNameSpaces);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair(
+        vector<int8_t>* outSigningKeyBlob, Certificate* outSigningKeyCertificate) {
+    string serialDecimal = "0";  // TODO: set serial to something unique
+    string issuer = "Android Open Source Project";
+    string subject = "Android IdentityCredential Reference Implementation";
+    time_t validityNotBefore = time(nullptr);
+    time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
+
+    optional<vector<uint8_t>> signingKeyPKCS8 = support::createEcKeyPair();
+    if (!signingKeyPKCS8) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error creating signingKey"));
+    }
+
+    optional<vector<uint8_t>> signingPublicKey =
+            support::ecKeyPairGetPublicKey(signingKeyPKCS8.value());
+    if (!signingPublicKey) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error getting public part of signingKey"));
+    }
+
+    optional<vector<uint8_t>> signingKey = support::ecKeyPairGetPrivateKey(signingKeyPKCS8.value());
+    if (!signingKey) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error getting private part of signingKey"));
+    }
+
+    optional<vector<uint8_t>> certificate = support::ecPublicKeyGenerateCertificate(
+            signingPublicKey.value(), credentialPrivKey_, serialDecimal, issuer, subject,
+            validityNotBefore, validityNotAfter);
+    if (!certificate) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error creating signingKey"));
+    }
+
+    optional<vector<uint8_t>> nonce = support::getRandom(12);
+    if (!nonce) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error getting random"));
+    }
+    vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
+    optional<vector<uint8_t>> encryptedSigningKey = support::encryptAes128Gcm(
+            storageKey_, nonce.value(), signingKey.value(), docTypeAsBlob);
+    if (!encryptedSigningKey) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error encrypting signingKey"));
+    }
+    *outSigningKeyBlob = byteStringToSigned(encryptedSigningKey.value());
+    *outSigningKeyCertificate = Certificate();
+    outSigningKeyCertificate->encodedCertificate = byteStringToSigned(certificate.value());
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h
new file mode 100644
index 0000000..49ed0d4
--- /dev/null
+++ b/identity/aidl/default/IdentityCredential.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIAL_H
+#define ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIAL_H
+
+#include <aidl/android/hardware/identity/BnIdentityCredential.h>
+#include <aidl/android/hardware/keymaster/HardwareAuthToken.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <cppbor/cppbor.h>
+
+namespace aidl::android::hardware::identity {
+
+using ::aidl::android::hardware::keymaster::HardwareAuthToken;
+using ::std::map;
+using ::std::string;
+using ::std::vector;
+
+using MapStringToVectorOfStrings = map<string, vector<string>>;
+
+class IdentityCredential : public BnIdentityCredential {
+  public:
+    IdentityCredential(const vector<uint8_t>& credentialData)
+        : credentialData_(credentialData), numStartRetrievalCalls_(0), authChallenge_(0) {}
+
+    // Parses and decrypts credentialData_, return a status code from
+    // IIdentityCredentialStore. Must be called right after construction.
+    int initialize();
+
+    // Methods from IIdentityCredential follow.
+    ndk::ScopedAStatus deleteCredential(vector<int8_t>* outProofOfDeletionSignature) override;
+    ndk::ScopedAStatus createEphemeralKeyPair(vector<int8_t>* outKeyPair) override;
+    ndk::ScopedAStatus setReaderEphemeralPublicKey(const vector<int8_t>& publicKey) override;
+    ndk::ScopedAStatus createAuthChallenge(int64_t* outChallenge) override;
+    ndk::ScopedAStatus startRetrieval(
+            const vector<SecureAccessControlProfile>& accessControlProfiles,
+            const HardwareAuthToken& authToken, const vector<int8_t>& itemsRequest,
+            const vector<int8_t>& sessionTranscript, const vector<int8_t>& readerSignature,
+            const vector<int32_t>& requestCounts) override;
+    ndk::ScopedAStatus startRetrieveEntryValue(
+            const string& nameSpace, const string& name, int32_t entrySize,
+            const vector<int32_t>& accessControlProfileIds) override;
+    ndk::ScopedAStatus retrieveEntryValue(const vector<int8_t>& encryptedContent,
+                                          vector<int8_t>* outContent) override;
+    ndk::ScopedAStatus finishRetrieval(const vector<int8_t>& signingKeyBlob, vector<int8_t>* outMac,
+                                       vector<int8_t>* outDeviceNameSpaces) override;
+    ndk::ScopedAStatus generateSigningKeyPair(vector<int8_t>* outSigningKeyBlob,
+                                              Certificate* outSigningKeyCertificate) override;
+
+  private:
+    // Set by constructor
+    vector<uint8_t> credentialData_;
+    int numStartRetrievalCalls_;
+
+    // Set by initialize()
+    string docType_;
+    bool testCredential_;
+    vector<uint8_t> storageKey_;
+    vector<uint8_t> credentialPrivKey_;
+
+    // Set by createEphemeralKeyPair()
+    vector<uint8_t> ephemeralPublicKey_;
+
+    // Set by setReaderEphemeralPublicKey()
+    vector<uint8_t> readerPublicKey_;
+
+    // Set by createAuthChallenge()
+    uint64_t authChallenge_;
+
+    // Set at startRetrieval() time.
+    map<int32_t, int> profileIdToAccessCheckResult_;
+    vector<uint8_t> sessionTranscript_;
+    std::unique_ptr<cppbor::Item> sessionTranscriptItem_;
+    vector<uint8_t> itemsRequest_;
+    vector<int32_t> requestCountsRemaining_;
+    MapStringToVectorOfStrings requestedNameSpacesAndNames_;
+    cppbor::Map deviceNameSpacesMap_;
+    cppbor::Map currentNameSpaceDeviceNameSpacesMap_;
+
+    // Set at startRetrieveEntryValue() time.
+    string currentNameSpace_;
+    string currentName_;
+    size_t entryRemainingBytes_;
+    vector<uint8_t> entryValue_;
+    vector<uint8_t> entryAdditionalData_;
+};
+
+}  // namespace aidl::android::hardware::identity
+
+#endif  // ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIAL_H
diff --git a/identity/aidl/default/IdentityCredentialStore.cpp b/identity/aidl/default/IdentityCredentialStore.cpp
new file mode 100644
index 0000000..1efb4b4
--- /dev/null
+++ b/identity/aidl/default/IdentityCredentialStore.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IdentityCredentialStore"
+
+#include <android-base/logging.h>
+
+#include "IdentityCredential.h"
+#include "IdentityCredentialStore.h"
+#include "WritableIdentityCredential.h"
+
+namespace aidl::android::hardware::identity {
+
+ndk::ScopedAStatus IdentityCredentialStore::getHardwareInformation(
+        HardwareInformation* hardwareInformation) {
+    HardwareInformation hw;
+    hw.credentialStoreName = "Identity Credential Reference Implementation";
+    hw.credentialStoreAuthorName = "Google";
+    hw.dataChunkSize = kGcmChunkSize;
+    hw.isDirectAccess = false;
+    hw.supportedDocTypes = {};
+    *hardwareInformation = hw;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus IdentityCredentialStore::createCredential(
+        const string& docType, bool testCredential,
+        shared_ptr<IWritableIdentityCredential>* outWritableCredential) {
+    shared_ptr<WritableIdentityCredential> wc =
+            ndk::SharedRefBase::make<WritableIdentityCredential>(docType, testCredential);
+    if (!wc->initialize()) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error initializing WritableIdentityCredential"));
+    }
+    *outWritableCredential = wc;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus IdentityCredentialStore::getCredential(
+        CipherSuite cipherSuite, const vector<int8_t>& credentialData,
+        shared_ptr<IIdentityCredential>* outCredential) {
+    // We only support CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 right now.
+    if (cipherSuite != CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED,
+                "Unsupported cipher suite"));
+    }
+
+    vector<uint8_t> data = vector<uint8_t>(credentialData.begin(), credentialData.end());
+    shared_ptr<IdentityCredential> credential = ndk::SharedRefBase::make<IdentityCredential>(data);
+    auto ret = credential->initialize();
+    if (ret != IIdentityCredentialStore::STATUS_OK) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                int(ret), "Error initializing IdentityCredential"));
+    }
+    *outCredential = credential;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/IdentityCredentialStore.h b/identity/aidl/default/IdentityCredentialStore.h
new file mode 100644
index 0000000..a205113
--- /dev/null
+++ b/identity/aidl/default/IdentityCredentialStore.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIALSTORE_H
+#define ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIALSTORE_H
+
+#include <aidl/android/hardware/identity/BnIdentityCredentialStore.h>
+
+namespace aidl::android::hardware::identity {
+
+using ::std::shared_ptr;
+using ::std::string;
+using ::std::vector;
+
+class IdentityCredentialStore : public BnIdentityCredentialStore {
+  public:
+    IdentityCredentialStore() {}
+
+    // The GCM chunk size used by this implementation is 64 KiB.
+    static constexpr size_t kGcmChunkSize = 64 * 1024;
+
+    // Methods from IIdentityCredentialStore follow.
+    ndk::ScopedAStatus getHardwareInformation(HardwareInformation* hardwareInformation) override;
+
+    ndk::ScopedAStatus createCredential(
+            const string& docType, bool testCredential,
+            shared_ptr<IWritableIdentityCredential>* outWritableCredential) override;
+
+    ndk::ScopedAStatus getCredential(CipherSuite cipherSuite, const vector<int8_t>& credentialData,
+                                     shared_ptr<IIdentityCredential>* outCredential) override;
+};
+
+}  // namespace aidl::android::hardware::identity
+
+#endif  // ANDROID_HARDWARE_IDENTITY_IDENTITYCREDENTIALSTORE_H
diff --git a/identity/aidl/default/Util.cpp b/identity/aidl/default/Util.cpp
new file mode 100644
index 0000000..a0f86be
--- /dev/null
+++ b/identity/aidl/default/Util.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Util"
+
+#include "Util.h"
+
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+
+#include <string.h>
+
+#include <android-base/logging.h>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+namespace aidl::android::hardware::identity {
+
+using namespace ::android::hardware::identity;
+
+// This is not a very random HBK but that's OK because this is the SW
+// implementation where it can't be kept secret.
+vector<uint8_t> hardwareBoundKey = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+
+const vector<uint8_t>& getHardwareBoundKey() {
+    return hardwareBoundKey;
+}
+
+vector<uint8_t> byteStringToUnsigned(const vector<int8_t>& value) {
+    return vector<uint8_t>(value.begin(), value.end());
+}
+
+vector<int8_t> byteStringToSigned(const vector<uint8_t>& value) {
+    return vector<int8_t>(value.begin(), value.end());
+}
+
+vector<uint8_t> secureAccessControlProfileEncodeCbor(const SecureAccessControlProfile& profile) {
+    cppbor::Map map;
+    map.add("id", profile.id);
+
+    if (profile.readerCertificate.encodedCertificate.size() > 0) {
+        map.add("readerCertificate",
+                cppbor::Bstr(byteStringToUnsigned(profile.readerCertificate.encodedCertificate)));
+    }
+
+    if (profile.userAuthenticationRequired) {
+        map.add("userAuthenticationRequired", profile.userAuthenticationRequired);
+        map.add("timeoutMillis", profile.timeoutMillis);
+        map.add("secureUserId", profile.secureUserId);
+    }
+
+    return map.encode();
+}
+
+optional<vector<uint8_t>> secureAccessControlProfileCalcMac(
+        const SecureAccessControlProfile& profile, const vector<uint8_t>& storageKey) {
+    vector<uint8_t> cborData = secureAccessControlProfileEncodeCbor(profile);
+
+    optional<vector<uint8_t>> nonce = support::getRandom(12);
+    if (!nonce) {
+        return {};
+    }
+    optional<vector<uint8_t>> macO =
+            support::encryptAes128Gcm(storageKey, nonce.value(), {}, cborData);
+    if (!macO) {
+        return {};
+    }
+    return macO.value();
+}
+
+bool secureAccessControlProfileCheckMac(const SecureAccessControlProfile& profile,
+                                        const vector<uint8_t>& storageKey) {
+    vector<uint8_t> cborData = secureAccessControlProfileEncodeCbor(profile);
+
+    if (profile.mac.size() < support::kAesGcmIvSize) {
+        return false;
+    }
+    vector<uint8_t> nonce =
+            vector<uint8_t>(profile.mac.begin(), profile.mac.begin() + support::kAesGcmIvSize);
+    optional<vector<uint8_t>> mac = support::encryptAes128Gcm(storageKey, nonce, {}, cborData);
+    if (!mac) {
+        return false;
+    }
+    if (mac.value() != byteStringToUnsigned(profile.mac)) {
+        return false;
+    }
+    return true;
+}
+
+vector<uint8_t> entryCreateAdditionalData(const string& nameSpace, const string& name,
+                                          const vector<int32_t> accessControlProfileIds) {
+    cppbor::Map map;
+    map.add("Namespace", nameSpace);
+    map.add("Name", name);
+
+    cppbor::Array acpIds;
+    for (auto id : accessControlProfileIds) {
+        acpIds.add(id);
+    }
+    map.add("AccessControlProfileIds", std::move(acpIds));
+    return map.encode();
+}
+
+}  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/Util.h b/identity/aidl/default/Util.h
new file mode 100644
index 0000000..ee41ad1
--- /dev/null
+++ b/identity/aidl/default/Util.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_IDENTITY_UTIL_H
+#define ANDROID_HARDWARE_IDENTITY_UTIL_H
+
+#include <aidl/android/hardware/identity/BnIdentityCredential.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+
+#include <map>
+#include <optional>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <cppbor/cppbor.h>
+
+namespace aidl::android::hardware::identity {
+
+using ::std::optional;
+using ::std::string;
+using ::std::vector;
+
+// Returns the hardware-bound AES-128 key.
+const vector<uint8_t>& getHardwareBoundKey();
+
+// Calculates the MAC for |profile| using |storageKey|.
+optional<vector<uint8_t>> secureAccessControlProfileCalcMac(
+        const SecureAccessControlProfile& profile, const vector<uint8_t>& storageKey);
+
+// Checks authenticity of the MAC in |profile| using |storageKey|.
+bool secureAccessControlProfileCheckMac(const SecureAccessControlProfile& profile,
+                                        const vector<uint8_t>& storageKey);
+
+// Creates the AdditionalData CBOR used in the addEntryValue() HIDL method.
+vector<uint8_t> entryCreateAdditionalData(const string& nameSpace, const string& name,
+                                          const vector<int32_t> accessControlProfileIds);
+
+vector<uint8_t> byteStringToUnsigned(const vector<int8_t>& value);
+
+vector<int8_t> byteStringToSigned(const vector<uint8_t>& value);
+
+}  // namespace aidl::android::hardware::identity
+
+#endif  // ANDROID_HARDWARE_IDENTITY_UTIL_H
diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp
new file mode 100644
index 0000000..ba2062d
--- /dev/null
+++ b/identity/aidl/default/WritableIdentityCredential.cpp
@@ -0,0 +1,421 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "WritableIdentityCredential"
+
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+
+#include <android-base/logging.h>
+
+#include <cppbor/cppbor.h>
+#include <cppbor/cppbor_parse.h>
+
+#include "IdentityCredentialStore.h"
+#include "Util.h"
+#include "WritableIdentityCredential.h"
+
+namespace aidl::android::hardware::identity {
+
+using ::std::optional;
+using namespace ::android::hardware::identity;
+
+bool WritableIdentityCredential::initialize() {
+    optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
+    if (!keyPair) {
+        LOG(ERROR) << "Error creating credentialKey";
+        return false;
+    }
+
+    optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
+    if (!pubKey) {
+        LOG(ERROR) << "Error getting public part of credentialKey";
+        return false;
+    }
+    credentialPubKey_ = pubKey.value();
+
+    optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
+    if (!privKey) {
+        LOG(ERROR) << "Error getting private part of credentialKey";
+        return false;
+    }
+    credentialPrivKey_ = privKey.value();
+
+    optional<vector<uint8_t>> random = support::getRandom(16);
+    if (!random) {
+        LOG(ERROR) << "Error creating storageKey";
+        return false;
+    }
+    storageKey_ = random.value();
+
+    return true;
+}
+
+// TODO: use |attestationApplicationId| and |attestationChallenge| and also
+//       ensure the returned certificate chain satisfy the requirements listed in
+//       the docs for IWritableIdentityCredential::getAttestationCertificate()
+//
+ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate(
+        const vector<int8_t>& /*attestationApplicationId*/,
+        const vector<int8_t>& /*attestationChallenge*/, vector<Certificate>* outCertificateChain) {
+    // For now, we dynamically generate an attestion key on each and every
+    // request and use that to sign CredentialKey. In a real implementation this
+    // would look very differently.
+    optional<vector<uint8_t>> attestationKeyPair = support::createEcKeyPair();
+    if (!attestationKeyPair) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error creating attestationKey"));
+    }
+
+    optional<vector<uint8_t>> attestationPubKey =
+            support::ecKeyPairGetPublicKey(attestationKeyPair.value());
+    if (!attestationPubKey) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error getting public part of attestationKey"));
+    }
+
+    optional<vector<uint8_t>> attestationPrivKey =
+            support::ecKeyPairGetPrivateKey(attestationKeyPair.value());
+    if (!attestationPrivKey) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error getting private part of attestationKey"));
+    }
+
+    string serialDecimal;
+    string issuer;
+    string subject;
+    time_t validityNotBefore = time(nullptr);
+    time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
+
+    // First create a certificate for |credentialPubKey| which is signed by
+    // |attestationPrivKey|.
+    //
+    serialDecimal = "0";  // TODO: set serial to |attestationChallenge|
+    issuer = "Android Open Source Project";
+    subject = "Android IdentityCredential CredentialKey";
+    optional<vector<uint8_t>> credentialPubKeyCertificate = support::ecPublicKeyGenerateCertificate(
+            credentialPubKey_, attestationPrivKey.value(), serialDecimal, issuer, subject,
+            validityNotBefore, validityNotAfter);
+    if (!credentialPubKeyCertificate) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error creating certificate for credentialPubKey"));
+    }
+
+    // This is followed by a certificate for |attestationPubKey| self-signed by
+    // |attestationPrivKey|.
+    serialDecimal = "0";  // TODO: set serial
+    issuer = "Android Open Source Project";
+    subject = "Android IdentityCredential AttestationKey";
+    optional<vector<uint8_t>> attestationKeyCertificate = support::ecPublicKeyGenerateCertificate(
+            attestationPubKey.value(), attestationPrivKey.value(), serialDecimal, issuer, subject,
+            validityNotBefore, validityNotAfter);
+    if (!attestationKeyCertificate) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED,
+                "Error creating certificate for attestationPubKey"));
+    }
+
+    // Concatenate the certificates to form the chain.
+    vector<uint8_t> certificateChain;
+    certificateChain.insert(certificateChain.end(), credentialPubKeyCertificate.value().begin(),
+                            credentialPubKeyCertificate.value().end());
+    certificateChain.insert(certificateChain.end(), attestationKeyCertificate.value().begin(),
+                            attestationKeyCertificate.value().end());
+
+    optional<vector<vector<uint8_t>>> splitCertChain =
+            support::certificateChainSplit(certificateChain);
+    if (!splitCertChain) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error splitting certificate chain"));
+    }
+    *outCertificateChain = vector<Certificate>();
+    for (const vector<uint8_t>& cert : splitCertChain.value()) {
+        Certificate c = Certificate();
+        c.encodedCertificate = byteStringToSigned(cert);
+        outCertificateChain->push_back(std::move(c));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WritableIdentityCredential::startPersonalization(
+        int32_t accessControlProfileCount, const vector<int32_t>& entryCounts) {
+    numAccessControlProfileRemaining_ = accessControlProfileCount;
+    remainingEntryCounts_ = entryCounts;
+    entryNameSpace_ = "";
+
+    signedDataAccessControlProfiles_ = cppbor::Array();
+    signedDataNamespaces_ = cppbor::Map();
+    signedDataCurrentNamespace_ = cppbor::Array();
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WritableIdentityCredential::addAccessControlProfile(
+        int32_t id, const Certificate& readerCertificate, bool userAuthenticationRequired,
+        int64_t timeoutMillis, int64_t secureUserId,
+        SecureAccessControlProfile* outSecureAccessControlProfile) {
+    SecureAccessControlProfile profile;
+
+    if (numAccessControlProfileRemaining_ == 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA,
+                "numAccessControlProfileRemaining_ is 0 and expected non-zero"));
+    }
+
+    // Spec requires if |userAuthenticationRequired| is false, then |timeoutMillis| must also
+    // be zero.
+    if (!userAuthenticationRequired && timeoutMillis != 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA,
+                "userAuthenticationRequired is false but timeout is non-zero"));
+    }
+
+    profile.id = id;
+    profile.readerCertificate = readerCertificate;
+    profile.userAuthenticationRequired = userAuthenticationRequired;
+    profile.timeoutMillis = timeoutMillis;
+    profile.secureUserId = secureUserId;
+    optional<vector<uint8_t>> mac = secureAccessControlProfileCalcMac(profile, storageKey_);
+    if (!mac) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error calculating MAC for profile"));
+    }
+    profile.mac = byteStringToSigned(mac.value());
+
+    cppbor::Map profileMap;
+    profileMap.add("id", profile.id);
+    if (profile.readerCertificate.encodedCertificate.size() > 0) {
+        profileMap.add(
+                "readerCertificate",
+                cppbor::Bstr(byteStringToUnsigned(profile.readerCertificate.encodedCertificate)));
+    }
+    if (profile.userAuthenticationRequired) {
+        profileMap.add("userAuthenticationRequired", profile.userAuthenticationRequired);
+        profileMap.add("timeoutMillis", profile.timeoutMillis);
+    }
+    signedDataAccessControlProfiles_.add(std::move(profileMap));
+
+    numAccessControlProfileRemaining_--;
+
+    *outSecureAccessControlProfile = profile;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WritableIdentityCredential::beginAddEntry(
+        const vector<int32_t>& accessControlProfileIds, const string& nameSpace, const string& name,
+        int32_t entrySize) {
+    if (numAccessControlProfileRemaining_ != 0) {
+        LOG(ERROR) << "numAccessControlProfileRemaining_ is " << numAccessControlProfileRemaining_
+                   << " and expected zero";
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA,
+                "numAccessControlProfileRemaining_ is not zero"));
+    }
+
+    if (remainingEntryCounts_.size() == 0) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA, "No more namespaces to add to"));
+    }
+
+    // Handle initial beginEntry() call.
+    if (entryNameSpace_ == "") {
+        entryNameSpace_ = nameSpace;
+    }
+
+    // If the namespace changed...
+    if (nameSpace != entryNameSpace_) {
+        // Then check that all entries in the previous namespace have been added..
+        if (remainingEntryCounts_[0] != 0) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "New namespace but a non-zero number of entries remain to be added"));
+        }
+        remainingEntryCounts_.erase(remainingEntryCounts_.begin());
+
+        if (signedDataCurrentNamespace_.size() > 0) {
+            signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_));
+            signedDataCurrentNamespace_ = cppbor::Array();
+        }
+    } else {
+        // Same namespace...
+        if (remainingEntryCounts_[0] == 0) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "Same namespace but no entries remain to be added"));
+        }
+        remainingEntryCounts_[0] -= 1;
+    }
+
+    entryAdditionalData_ = entryCreateAdditionalData(nameSpace, name, accessControlProfileIds);
+
+    entryRemainingBytes_ = entrySize;
+    entryNameSpace_ = nameSpace;
+    entryName_ = name;
+    entryAccessControlProfileIds_ = accessControlProfileIds;
+    entryBytes_.resize(0);
+    // LOG(INFO) << "name=" << name << " entrySize=" << entrySize;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WritableIdentityCredential::addEntryValue(const vector<int8_t>& contentS,
+                                                             vector<int8_t>* outEncryptedContent) {
+    auto content = byteStringToUnsigned(contentS);
+    size_t contentSize = content.size();
+
+    if (contentSize > IdentityCredentialStore::kGcmChunkSize) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA,
+                "Passed in chunk of is bigger than kGcmChunkSize"));
+    }
+    if (contentSize > entryRemainingBytes_) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_INVALID_DATA,
+                "Passed in chunk is bigger than remaining space"));
+    }
+
+    entryBytes_.insert(entryBytes_.end(), content.begin(), content.end());
+    entryRemainingBytes_ -= contentSize;
+    if (entryRemainingBytes_ > 0) {
+        if (contentSize != IdentityCredentialStore::kGcmChunkSize) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "Retrieved non-final chunk which isn't kGcmChunkSize"));
+        }
+    }
+
+    optional<vector<uint8_t>> nonce = support::getRandom(12);
+    if (!nonce) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error getting nonce"));
+    }
+    optional<vector<uint8_t>> encryptedContent =
+            support::encryptAes128Gcm(storageKey_, nonce.value(), content, entryAdditionalData_);
+    if (!encryptedContent) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error encrypting content"));
+    }
+
+    if (entryRemainingBytes_ == 0) {
+        // TODO: ideally do do this without parsing the data (but still validate data is valid
+        // CBOR).
+        auto [item, _, message] = cppbor::parse(entryBytes_);
+        if (item == nullptr) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA, "Data is not valid CBOR"));
+        }
+        cppbor::Map entryMap;
+        entryMap.add("name", entryName_);
+        entryMap.add("value", std::move(item));
+        cppbor::Array profileIdArray;
+        for (auto id : entryAccessControlProfileIds_) {
+            profileIdArray.add(id);
+        }
+        entryMap.add("accessControlProfiles", std::move(profileIdArray));
+        signedDataCurrentNamespace_.add(std::move(entryMap));
+    }
+
+    *outEncryptedContent = byteStringToSigned(encryptedContent.value());
+    return ndk::ScopedAStatus::ok();
+}
+
+// Writes CBOR-encoded structure to |credentialKeys| containing |storageKey| and
+// |credentialPrivKey|.
+static bool generateCredentialKeys(const vector<uint8_t>& storageKey,
+                                   const vector<uint8_t>& credentialPrivKey,
+                                   vector<uint8_t>& credentialKeys) {
+    if (storageKey.size() != 16) {
+        LOG(ERROR) << "Size of storageKey is not 16";
+        return false;
+    }
+
+    cppbor::Array array;
+    array.add(cppbor::Bstr(storageKey));
+    array.add(cppbor::Bstr(credentialPrivKey));
+    credentialKeys = array.encode();
+    return true;
+}
+
+// Writes CBOR-encoded structure to |credentialData| containing |docType|,
+// |testCredential| and |credentialKeys|. The latter element will be stored in
+// encrypted form, using |hardwareBoundKey| as the encryption key.
+bool generateCredentialData(const vector<uint8_t>& hardwareBoundKey, const string& docType,
+                            bool testCredential, const vector<uint8_t>& credentialKeys,
+                            vector<uint8_t>& credentialData) {
+    optional<vector<uint8_t>> nonce = support::getRandom(12);
+    if (!nonce) {
+        LOG(ERROR) << "Error getting random";
+        return false;
+    }
+    vector<uint8_t> docTypeAsVec(docType.begin(), docType.end());
+    optional<vector<uint8_t>> credentialBlob = support::encryptAes128Gcm(
+            hardwareBoundKey, nonce.value(), credentialKeys, docTypeAsVec);
+    if (!credentialBlob) {
+        LOG(ERROR) << "Error encrypting CredentialKeys blob";
+        return false;
+    }
+
+    cppbor::Array array;
+    array.add(docType);
+    array.add(testCredential);
+    array.add(cppbor::Bstr(credentialBlob.value()));
+    credentialData = array.encode();
+    return true;
+}
+
+ndk::ScopedAStatus WritableIdentityCredential::finishAddingEntries(
+        vector<int8_t>* outCredentialData, vector<int8_t>* outProofOfProvisioningSignature) {
+    if (signedDataCurrentNamespace_.size() > 0) {
+        signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_));
+    }
+    cppbor::Array popArray;
+    popArray.add("ProofOfProvisioning")
+            .add(docType_)
+            .add(std::move(signedDataAccessControlProfiles_))
+            .add(std::move(signedDataNamespaces_))
+            .add(testCredential_);
+    vector<uint8_t> encodedCbor = popArray.encode();
+
+    optional<vector<uint8_t>> signature = support::coseSignEcDsa(credentialPrivKey_,
+                                                                 encodedCbor,  // payload
+                                                                 {},           // additionalData
+                                                                 {});          // certificateChain
+    if (!signature) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error signing data"));
+    }
+
+    vector<uint8_t> credentialKeys;
+    if (!generateCredentialKeys(storageKey_, credentialPrivKey_, credentialKeys)) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error generating CredentialKeys"));
+    }
+
+    vector<uint8_t> credentialData;
+    if (!generateCredentialData(
+                testCredential_ ? support::getTestHardwareBoundKey() : getHardwareBoundKey(),
+                docType_, testCredential_, credentialKeys, credentialData)) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error generating CredentialData"));
+    }
+
+    *outCredentialData = byteStringToSigned(credentialData);
+    *outProofOfProvisioningSignature = byteStringToSigned(signature.value());
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::identity
diff --git a/identity/aidl/default/WritableIdentityCredential.h b/identity/aidl/default/WritableIdentityCredential.h
new file mode 100644
index 0000000..b380f89
--- /dev/null
+++ b/identity/aidl/default/WritableIdentityCredential.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_IDENTITY_WRITABLEIDENTITYCREDENTIAL_H
+#define ANDROID_HARDWARE_IDENTITY_WRITABLEIDENTITYCREDENTIAL_H
+
+#include <aidl/android/hardware/identity/BnWritableIdentityCredential.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+
+#include <cppbor.h>
+
+namespace aidl::android::hardware::identity {
+
+using ::std::string;
+using ::std::vector;
+
+class WritableIdentityCredential : public BnWritableIdentityCredential {
+  public:
+    WritableIdentityCredential(const string& docType, bool testCredential)
+        : docType_(docType), testCredential_(testCredential) {}
+
+    // Creates the Credential Key. Returns false on failure. Must be called
+    // right after construction.
+    bool initialize();
+
+    // Methods from IWritableIdentityCredential follow.
+    ndk::ScopedAStatus getAttestationCertificate(const vector<int8_t>& attestationApplicationId,
+                                                 const vector<int8_t>& attestationChallenge,
+                                                 vector<Certificate>* outCertificateChain) override;
+
+    ndk::ScopedAStatus startPersonalization(int32_t accessControlProfileCount,
+                                            const vector<int32_t>& entryCounts) override;
+
+    ndk::ScopedAStatus addAccessControlProfile(
+            int32_t id, const Certificate& readerCertificate, bool userAuthenticationRequired,
+            int64_t timeoutMillis, int64_t secureUserId,
+            SecureAccessControlProfile* outSecureAccessControlProfile) override;
+
+    ndk::ScopedAStatus beginAddEntry(const vector<int32_t>& accessControlProfileIds,
+                                     const string& nameSpace, const string& name,
+                                     int32_t entrySize) override;
+
+    ndk::ScopedAStatus addEntryValue(const vector<int8_t>& content,
+                                     vector<int8_t>* outEncryptedContent) override;
+
+    ndk::ScopedAStatus finishAddingEntries(
+            vector<int8_t>* outCredentialData,
+            vector<int8_t>* outProofOfProvisioningSignature) override;
+
+    // private:
+    string docType_;
+    bool testCredential_;
+
+    // These are set in initialize().
+    vector<uint8_t> storageKey_;
+    vector<uint8_t> credentialPrivKey_;
+    vector<uint8_t> credentialPubKey_;
+
+    // These fields are initialized during startPersonalization()
+    size_t numAccessControlProfileRemaining_;
+    vector<int32_t> remainingEntryCounts_;
+    cppbor::Array signedDataAccessControlProfiles_;
+    cppbor::Map signedDataNamespaces_;
+    cppbor::Array signedDataCurrentNamespace_;
+
+    // These fields are initialized during beginAddEntry()
+    size_t entryRemainingBytes_;
+    vector<uint8_t> entryAdditionalData_;
+    string entryNameSpace_;
+    string entryName_;
+    vector<int32_t> entryAccessControlProfileIds_;
+    vector<uint8_t> entryBytes_;
+};
+
+}  // namespace aidl::android::hardware::identity
+
+#endif  // ANDROID_HARDWARE_IDENTITY_WRITABLEIDENTITYCREDENTIAL_H
diff --git a/identity/aidl/default/identity-default.rc b/identity/aidl/default/identity-default.rc
new file mode 100644
index 0000000..d3b62c1
--- /dev/null
+++ b/identity/aidl/default/identity-default.rc
@@ -0,0 +1,3 @@
+service vendor.identity-default /vendor/bin/hw/android.hardware.identity-service.example
+    class hal
+    user nobody
diff --git a/identity/aidl/default/identity-default.xml b/identity/aidl/default/identity-default.xml
new file mode 100644
index 0000000..a47d354
--- /dev/null
+++ b/identity/aidl/default/identity-default.xml
@@ -0,0 +1,9 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.identity</name>
+        <interface>
+            <name>IIdentityCredentialStore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/identity/aidl/default/service.cpp b/identity/aidl/default/service.cpp
new file mode 100644
index 0000000..f05c615
--- /dev/null
+++ b/identity/aidl/default/service.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.identity-service"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "IdentityCredentialStore.h"
+
+using aidl::android::hardware::identity::IdentityCredentialStore;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<IdentityCredentialStore> store =
+            ndk::SharedRefBase::make<IdentityCredentialStore>();
+
+    const std::string instance = std::string() + IdentityCredentialStore::descriptor + "/default";
+    LOG(INFO) << "instance: " << instance;
+    binder_status_t status = AServiceManager_addService(store->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
new file mode 100644
index 0000000..21ff440
--- /dev/null
+++ b/identity/aidl/vts/Android.bp
@@ -0,0 +1,21 @@
+cc_test {
+    name: "VtsHalIdentityTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalIdentityTargetTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libcppbor",
+        "android.hardware.identity-support-lib",
+    ],
+    static_libs: [
+        "android.hardware.identity-cpp",
+        "android.hardware.keymaster-cpp",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp b/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
new file mode 100644
index 0000000..5abe5a2
--- /dev/null
+++ b/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "VtsHalIdentityTargetTest"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android/hardware/identity/IIdentityCredentialStore.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cppbor.h>
+#include <cppbor_parse.h>
+#include <gtest/gtest.h>
+#include <future>
+#include <map>
+
+namespace android::hardware::identity {
+
+using std::map;
+using std::optional;
+using std::string;
+using std::vector;
+
+using ::android::sp;
+using ::android::String16;
+using ::android::binder::Status;
+
+using ::android::hardware::keymaster::HardwareAuthToken;
+
+// ---------------------------------------------------------------------------
+// Test Data.
+// ---------------------------------------------------------------------------
+
+struct TestEntryData {
+    TestEntryData(string nameSpace, string name, vector<int32_t> profileIds)
+        : nameSpace(nameSpace), name(name), profileIds(profileIds) {}
+
+    TestEntryData(string nameSpace, string name, const string& value, vector<int32_t> profileIds)
+        : TestEntryData(nameSpace, name, profileIds) {
+        valueCbor = cppbor::Tstr(((const char*)value.data())).encode();
+    }
+    TestEntryData(string nameSpace, string name, const vector<uint8_t>& value,
+                  vector<int32_t> profileIds)
+        : TestEntryData(nameSpace, name, profileIds) {
+        valueCbor = cppbor::Bstr(value).encode();
+    }
+    TestEntryData(string nameSpace, string name, bool value, vector<int32_t> profileIds)
+        : TestEntryData(nameSpace, name, profileIds) {
+        valueCbor = cppbor::Bool(value).encode();
+    }
+    TestEntryData(string nameSpace, string name, int64_t value, vector<int32_t> profileIds)
+        : TestEntryData(nameSpace, name, profileIds) {
+        if (value >= 0) {
+            valueCbor = cppbor::Uint(value).encode();
+        } else {
+            valueCbor = cppbor::Nint(-value).encode();
+        }
+    }
+
+    string nameSpace;
+    string name;
+    vector<uint8_t> valueCbor;
+    vector<int32_t> profileIds;
+};
+
+struct TestProfile {
+    uint16_t id;
+    vector<uint8_t> readerCertificate;
+    bool userAuthenticationRequired;
+    uint64_t timeoutMillis;
+};
+
+// ----------------------------------------------------------------
+
+class IdentityAidl : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
+                String16(GetParam().c_str()));
+        ASSERT_NE(credentialStore_, nullptr);
+    }
+
+    sp<IIdentityCredentialStore> credentialStore_;
+};
+
+TEST_P(IdentityAidl, hardwareInformation) {
+    HardwareInformation info;
+    ASSERT_TRUE(credentialStore_->getHardwareInformation(&info).isOk());
+    ASSERT_GT(info.credentialStoreName.size(), 0);
+    ASSERT_GT(info.credentialStoreAuthorName.size(), 0);
+    ASSERT_GE(info.dataChunkSize, 256);
+}
+
+TEST_P(IdentityAidl, createAndRetrieveCredential) {
+    // First, generate a key-pair for the reader since its public key will be
+    // part of the request data.
+    optional<vector<uint8_t>> readerKeyPKCS8 = support::createEcKeyPair();
+    ASSERT_TRUE(readerKeyPKCS8);
+    optional<vector<uint8_t>> readerPublicKey =
+            support::ecKeyPairGetPublicKey(readerKeyPKCS8.value());
+    optional<vector<uint8_t>> readerKey = support::ecKeyPairGetPrivateKey(readerKeyPKCS8.value());
+    string serialDecimal = "1234";
+    string issuer = "Android Open Source Project";
+    string subject = "Android IdentityCredential VTS Test";
+    time_t validityNotBefore = time(nullptr);
+    time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
+    optional<vector<uint8_t>> readerCertificate = support::ecPublicKeyGenerateCertificate(
+            readerPublicKey.value(), readerKey.value(), serialDecimal, issuer, subject,
+            validityNotBefore, validityNotAfter);
+    ASSERT_TRUE(readerCertificate);
+
+    // Make the portrait image really big (just shy of 256 KiB) to ensure that
+    // the chunking code gets exercised.
+    vector<uint8_t> portraitImage;
+    portraitImage.resize(256 * 1024 - 10);
+    for (size_t n = 0; n < portraitImage.size(); n++) {
+        portraitImage[n] = (uint8_t)n;
+    }
+
+    // Access control profiles:
+    const vector<TestProfile> testProfiles = {// Profile 0 (reader authentication)
+                                              {0, readerCertificate.value(), false, 0},
+                                              // Profile 1 (no authentication)
+                                              {1, {}, false, 0}};
+
+    HardwareAuthToken authToken;
+
+    // Here's the actual test data:
+    const vector<TestEntryData> testEntries = {
+            {"PersonalData", "Last name", string("Turing"), vector<int32_t>{0, 1}},
+            {"PersonalData", "Birth date", string("19120623"), vector<int32_t>{0, 1}},
+            {"PersonalData", "First name", string("Alan"), vector<int32_t>{0, 1}},
+            {"PersonalData", "Home address", string("Maida Vale, London, England"),
+             vector<int32_t>{0}},
+            {"Image", "Portrait image", portraitImage, vector<int32_t>{0, 1}},
+    };
+    const vector<int32_t> testEntriesEntryCounts = {static_cast<int32_t>(testEntries.size() - 1),
+                                                    1u};
+    HardwareInformation hwInfo;
+    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+    string cborPretty;
+    sp<IWritableIdentityCredential> writableCredential;
+    string docType = "org.iso.18013-5.2019.mdl";
+    bool testCredential = true;
+    ASSERT_TRUE(credentialStore_->createCredential(docType, testCredential, &writableCredential)
+                        .isOk());
+    ASSERT_NE(writableCredential, nullptr);
+
+    string challenge = "attestationChallenge";
+    // TODO: set it to something random and check it's in the cert chain
+    vector<uint8_t> attestationApplicationId = {};
+    vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
+    vector<Certificate> attestationCertificates;
+    ASSERT_TRUE(writableCredential
+                        ->getAttestationCertificate(attestationApplicationId, attestationChallenge,
+                                                    &attestationCertificates)
+                        .isOk());
+    ASSERT_GE(attestationCertificates.size(), 2);
+
+    ASSERT_TRUE(
+            writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts)
+                    .isOk());
+
+    vector<SecureAccessControlProfile> returnedSecureProfiles;
+    for (const auto& testProfile : testProfiles) {
+        SecureAccessControlProfile profile;
+        Certificate cert;
+        cert.encodedCertificate = testProfile.readerCertificate;
+        ASSERT_TRUE(writableCredential
+                            ->addAccessControlProfile(testProfile.id, cert,
+                                                      testProfile.userAuthenticationRequired,
+                                                      testProfile.timeoutMillis,
+                                                      0,  // secureUserId
+                                                      &profile)
+                            .isOk());
+        ASSERT_EQ(testProfile.id, profile.id);
+        ASSERT_EQ(testProfile.readerCertificate, profile.readerCertificate.encodedCertificate);
+        ASSERT_EQ(testProfile.userAuthenticationRequired, profile.userAuthenticationRequired);
+        ASSERT_EQ(testProfile.timeoutMillis, profile.timeoutMillis);
+        ASSERT_EQ(support::kAesGcmTagSize + support::kAesGcmIvSize, profile.mac.size());
+        returnedSecureProfiles.push_back(profile);
+    }
+
+    // Uses TestEntryData* pointer as key and values are the encrypted blobs. This
+    // is a little hacky but it works well enough.
+    map<const TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
+
+    for (const auto& entry : testEntries) {
+        vector<vector<uint8_t>> chunks =
+                support::chunkVector(entry.valueCbor, hwInfo.dataChunkSize);
+
+        ASSERT_TRUE(writableCredential
+                            ->beginAddEntry(entry.profileIds, entry.nameSpace, entry.name,
+                                            entry.valueCbor.size())
+                            .isOk());
+
+        vector<vector<uint8_t>> encryptedChunks;
+        for (const auto& chunk : chunks) {
+            vector<uint8_t> encryptedChunk;
+            ASSERT_TRUE(writableCredential->addEntryValue(chunk, &encryptedChunk).isOk());
+            encryptedChunks.push_back(encryptedChunk);
+        }
+        encryptedBlobs[&entry] = encryptedChunks;
+    }
+
+    vector<uint8_t> credentialData;
+    vector<uint8_t> proofOfProvisioningSignature;
+    ASSERT_TRUE(
+            writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature)
+                    .isOk());
+
+    optional<vector<uint8_t>> proofOfProvisioning =
+            support::coseSignGetPayload(proofOfProvisioningSignature);
+    ASSERT_TRUE(proofOfProvisioning);
+    cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
+    EXPECT_EQ(
+            "[\n"
+            "  'ProofOfProvisioning',\n"
+            "  'org.iso.18013-5.2019.mdl',\n"
+            "  [\n"
+            "    {\n"
+            "      'id' : 0,\n"
+            "      'readerCertificate' : <not printed>,\n"
+            "    },\n"
+            "    {\n"
+            "      'id' : 1,\n"
+            "    },\n"
+            "  ],\n"
+            "  {\n"
+            "    'PersonalData' : [\n"
+            "      {\n"
+            "        'name' : 'Last name',\n"
+            "        'value' : 'Turing',\n"
+            "        'accessControlProfiles' : [0, 1, ],\n"
+            "      },\n"
+            "      {\n"
+            "        'name' : 'Birth date',\n"
+            "        'value' : '19120623',\n"
+            "        'accessControlProfiles' : [0, 1, ],\n"
+            "      },\n"
+            "      {\n"
+            "        'name' : 'First name',\n"
+            "        'value' : 'Alan',\n"
+            "        'accessControlProfiles' : [0, 1, ],\n"
+            "      },\n"
+            "      {\n"
+            "        'name' : 'Home address',\n"
+            "        'value' : 'Maida Vale, London, England',\n"
+            "        'accessControlProfiles' : [0, ],\n"
+            "      },\n"
+            "    ],\n"
+            "    'Image' : [\n"
+            "      {\n"
+            "        'name' : 'Portrait image',\n"
+            "        'value' : <bstr size=262134 sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
+            "        'accessControlProfiles' : [0, 1, ],\n"
+            "      },\n"
+            "    ],\n"
+            "  },\n"
+            "  true,\n"
+            "]",
+            cborPretty);
+
+    optional<vector<uint8_t>> credentialPubKey =
+            support::certificateChainGetTopMostKey(attestationCertificates[0].encodedCertificate);
+    ASSERT_TRUE(credentialPubKey);
+    EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature,
+                                                 {},  // Additional data
+                                                 credentialPubKey.value()));
+    writableCredential = nullptr;
+
+    // Now that the credential has been provisioned, read it back and check the
+    // correct data is returned.
+    sp<IIdentityCredential> credential;
+    ASSERT_TRUE(credentialStore_
+                        ->getCredential(
+                                CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
+                                credentialData, &credential)
+                        .isOk());
+    ASSERT_NE(credential, nullptr);
+
+    optional<vector<uint8_t>> readerEphemeralKeyPair = support::createEcKeyPair();
+    ASSERT_TRUE(readerEphemeralKeyPair);
+    optional<vector<uint8_t>> readerEphemeralPublicKey =
+            support::ecKeyPairGetPublicKey(readerEphemeralKeyPair.value());
+    ASSERT_TRUE(credential->setReaderEphemeralPublicKey(readerEphemeralPublicKey.value()).isOk());
+
+    vector<uint8_t> ephemeralKeyPair;
+    ASSERT_TRUE(credential->createEphemeralKeyPair(&ephemeralKeyPair).isOk());
+    optional<vector<uint8_t>> ephemeralPublicKey = support::ecKeyPairGetPublicKey(ephemeralKeyPair);
+
+    // Calculate requestData field and sign it with the reader key.
+    auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ephemeralPublicKey.value());
+    ASSERT_TRUE(getXYSuccess);
+    cppbor::Map deviceEngagement = cppbor::Map().add("ephX", ephX).add("ephY", ephY);
+    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));
+    vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
+
+    vector<uint8_t> itemsRequestBytes =
+            cppbor::Map("nameSpaces",
+                        cppbor::Map()
+                                .add("PersonalData", cppbor::Map()
+                                                             .add("Last name", false)
+                                                             .add("Birth date", false)
+                                                             .add("First name", false)
+                                                             .add("Home address", true))
+                                .add("Image", cppbor::Map().add("Portrait image", false)))
+                    .encode();
+    cborPretty = support::cborPrettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
+    EXPECT_EQ(
+            "{\n"
+            "  'nameSpaces' : {\n"
+            "    'PersonalData' : {\n"
+            "      'Last name' : false,\n"
+            "      'Birth date' : false,\n"
+            "      'First name' : false,\n"
+            "      'Home address' : true,\n"
+            "    },\n"
+            "    'Image' : {\n"
+            "      'Portrait image' : false,\n"
+            "    },\n"
+            "  },\n"
+            "}",
+            cborPretty);
+    vector<uint8_t> dataToSign = cppbor::Array()
+                                         .add("ReaderAuthentication")
+                                         .add(sessionTranscript.clone())
+                                         .add(cppbor::Semantic(24, itemsRequestBytes))
+                                         .encode();
+    optional<vector<uint8_t>> readerSignature =
+            support::coseSignEcDsa(readerKey.value(), {},  // content
+                                   dataToSign,             // detached content
+                                   readerCertificate.value());
+    ASSERT_TRUE(readerSignature);
+
+    ASSERT_TRUE(credential
+                        ->startRetrieval(returnedSecureProfiles, authToken, itemsRequestBytes,
+                                         sessionTranscriptBytes, readerSignature.value(),
+                                         testEntriesEntryCounts)
+                        .isOk());
+
+    for (const auto& entry : testEntries) {
+        ASSERT_TRUE(credential
+                            ->startRetrieveEntryValue(entry.nameSpace, entry.name,
+                                                      entry.valueCbor.size(), entry.profileIds)
+                            .isOk());
+
+        auto it = encryptedBlobs.find(&entry);
+        ASSERT_NE(it, encryptedBlobs.end());
+        const vector<vector<uint8_t>>& encryptedChunks = it->second;
+
+        vector<uint8_t> content;
+        for (const auto& encryptedChunk : encryptedChunks) {
+            vector<uint8_t> chunk;
+            ASSERT_TRUE(credential->retrieveEntryValue(encryptedChunk, &chunk).isOk());
+            content.insert(content.end(), chunk.begin(), chunk.end());
+        }
+        EXPECT_EQ(content, entry.valueCbor);
+    }
+
+    // Generate the key that will be used to sign AuthenticatedData.
+    vector<uint8_t> signingKeyBlob;
+    Certificate signingKeyCertificate;
+    ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
+
+    vector<uint8_t> mac;
+    vector<uint8_t> deviceNameSpacesBytes;
+    ASSERT_TRUE(credential->finishRetrieval(signingKeyBlob, &mac, &deviceNameSpacesBytes).isOk());
+    cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
+    ASSERT_EQ(
+            "{\n"
+            "  'PersonalData' : {\n"
+            "    'Last name' : 'Turing',\n"
+            "    'Birth date' : '19120623',\n"
+            "    'First name' : 'Alan',\n"
+            "    'Home address' : 'Maida Vale, London, England',\n"
+            "  },\n"
+            "  'Image' : {\n"
+            "    'Portrait image' : <bstr size=262134 "
+            "sha1=941e372f654d86c32d88fae9e41b706afbfd02bb>,\n"
+            "  },\n"
+            "}",
+            cborPretty);
+    // The data that is MACed is ["DeviceAuthentication", sessionTranscriptBytes, docType,
+    // deviceNameSpacesBytes] so build up that structure
+    cppbor::Array deviceAuthentication;
+    deviceAuthentication.add("DeviceAuthentication");
+    deviceAuthentication.add(sessionTranscript.clone());
+    deviceAuthentication.add(docType);
+    deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
+    vector<uint8_t> encodedDeviceAuthentication = deviceAuthentication.encode();
+    optional<vector<uint8_t>> signingPublicKey =
+            support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate);
+    EXPECT_TRUE(signingPublicKey);
+
+    // Derive the key used for MACing.
+    optional<vector<uint8_t>> readerEphemeralPrivateKey =
+            support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
+    optional<vector<uint8_t>> sharedSecret =
+            support::ecdh(signingPublicKey.value(), readerEphemeralPrivateKey.value());
+    ASSERT_TRUE(sharedSecret);
+    vector<uint8_t> salt = {0x00};
+    vector<uint8_t> info = {};
+    optional<vector<uint8_t>> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32);
+    ASSERT_TRUE(derivedKey);
+    optional<vector<uint8_t>> calculatedMac =
+            support::coseMac0(derivedKey.value(), {},        // payload
+                              encodedDeviceAuthentication);  // detached content
+    ASSERT_TRUE(calculatedMac);
+    EXPECT_EQ(mac, calculatedMac);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        Identity, IdentityAidl,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
+        android::PrintInstanceNameToString);
+// INSTANTIATE_TEST_SUITE_P(Identity, IdentityAidl,
+// testing::Values("android.hardware.identity.IIdentityCredentialStore/default"));
+
+}  // namespace android::hardware::identity
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ::android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ::android::ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index 38dc10b..7b4546b 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -23,7 +23,6 @@
         "include",
     ],
     shared_libs: [
-        "android.hardware.identity@1.0",
         "libcrypto",
         "libbase",
         "libhidlbase",
@@ -41,7 +40,6 @@
     ],
     shared_libs: [
         "android.hardware.identity-support-lib",
-        "android.hardware.identity@1.0",
         "libcrypto",
         "libbase",
         "libhidlbase",
diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
index 485571a..4533ad9 100644
--- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
+++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
@@ -18,12 +18,11 @@
 #define IDENTITY_SUPPORT_INCLUDE_IDENTITY_CREDENTIAL_UTILS_H_
 
 #include <cstdint>
+#include <optional>
 #include <string>
 #include <tuple>
 #include <vector>
 
-#include <android/hardware/identity/1.0/types.h>
-
 namespace android {
 namespace hardware {
 namespace identity {
@@ -34,10 +33,6 @@
 using ::std::tuple;
 using ::std::vector;
 
-using ::android::hardware::identity::V1_0::Result;
-using ::android::hardware::identity::V1_0::ResultCode;
-using ::android::hardware::identity::V1_0::SecureAccessControlProfile;
-
 // ---------------------------------------------------------------------------
 // Miscellaneous utilities.
 // ---------------------------------------------------------------------------
@@ -258,21 +253,11 @@
                                    const vector<uint8_t>& detachedContent);
 
 // ---------------------------------------------------------------------------
-// Platform abstraction.
-// ---------------------------------------------------------------------------
-
-// Returns the hardware-bound AES-128 key.
-const vector<uint8_t>& getHardwareBoundKey();
-
-// ---------------------------------------------------------------------------
 // Utility functions specific to IdentityCredential.
 // ---------------------------------------------------------------------------
 
-// Returns a reference to a Result with code OK and empty message.
-const Result& resultOK();
-
-// Returns a new Result with the given code and message.
-Result result(ResultCode code, const char* format, ...) __attribute__((format(printf, 2, 3)));
+// Returns the testing AES-128 key where all bits are set to 0.
+const vector<uint8_t>& getTestHardwareBoundKey();
 
 // Splits the given bytestring into chunks. If the given vector is smaller or equal to
 // |maxChunkSize| a vector with |content| as the only element is returned. Otherwise
@@ -280,21 +265,6 @@
 // may be smaller than |maxChunkSize|.
 vector<vector<uint8_t>> chunkVector(const vector<uint8_t>& content, size_t maxChunkSize);
 
-// Calculates the MAC for |profile| using |storageKey|.
-optional<vector<uint8_t>> secureAccessControlProfileCalcMac(
-        const SecureAccessControlProfile& profile, const vector<uint8_t>& storageKey);
-
-// Checks authenticity of the MAC in |profile| using |storageKey|.
-bool secureAccessControlProfileCheckMac(const SecureAccessControlProfile& profile,
-                                        const vector<uint8_t>& storageKey);
-
-// Returns the testing AES-128 key where all bits are set to 0.
-const vector<uint8_t>& getTestHardwareBoundKey();
-
-// Creates the AdditionalData CBOR used in the addEntryValue() HIDL method.
-vector<uint8_t> entryCreateAdditionalData(const string& nameSpace, const string& name,
-                                          const vector<uint16_t> accessControlProfileIds);
-
 }  // namespace support
 }  // namespace identity
 }  // namespace hardware
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index 7d93a4b..e2828bf 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -1682,36 +1682,9 @@
 }
 
 // ---------------------------------------------------------------------------
-// Platform abstraction.
-// ---------------------------------------------------------------------------
-
-// This is not a very random HBK but that's OK because this is the SW
-// implementation where it can't be kept secret.
-vector<uint8_t> hardwareBoundKey = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
-
-const vector<uint8_t>& getHardwareBoundKey() {
-    return hardwareBoundKey;
-}
-
-// ---------------------------------------------------------------------------
 // Utility functions specific to IdentityCredential.
 // ---------------------------------------------------------------------------
 
-Result okResult{ResultCode::OK, ""};
-
-const Result& resultOK() {
-    return okResult;
-}
-
-Result result(ResultCode code, const char* format, ...) {
-    va_list ap;
-    va_start(ap, format);
-    string str;
-    android::base::StringAppendV(&str, format, ap);
-    va_end(ap);
-    return Result{code, str};
-}
-
 vector<vector<uint8_t>> chunkVector(const vector<uint8_t>& content, size_t maxChunkSize) {
     vector<vector<uint8_t>> ret;
 
@@ -1738,56 +1711,6 @@
     return ret;
 }
 
-vector<uint8_t> secureAccessControlProfileEncodeCbor(const SecureAccessControlProfile& profile) {
-    cppbor::Map map;
-    map.add("id", profile.id);
-
-    if (profile.readerCertificate.size() > 0) {
-        map.add("readerCertificate", cppbor::Bstr(profile.readerCertificate));
-    }
-
-    if (profile.userAuthenticationRequired) {
-        map.add("userAuthenticationRequired", profile.userAuthenticationRequired);
-        map.add("timeoutMillis", profile.timeoutMillis);
-        map.add("secureUserId", profile.secureUserId);
-    }
-
-    return map.encode();
-}
-
-optional<vector<uint8_t>> secureAccessControlProfileCalcMac(
-        const SecureAccessControlProfile& profile, const vector<uint8_t>& storageKey) {
-    vector<uint8_t> cborData = secureAccessControlProfileEncodeCbor(profile);
-
-    optional<vector<uint8_t>> nonce = getRandom(12);
-    if (!nonce) {
-        return {};
-    }
-    optional<vector<uint8_t>> macO = encryptAes128Gcm(storageKey, nonce.value(), {}, cborData);
-    if (!macO) {
-        return {};
-    }
-    return macO.value();
-}
-
-bool secureAccessControlProfileCheckMac(const SecureAccessControlProfile& profile,
-                                        const vector<uint8_t>& storageKey) {
-    vector<uint8_t> cborData = secureAccessControlProfileEncodeCbor(profile);
-
-    if (profile.mac.size() < kAesGcmIvSize) {
-        return false;
-    }
-    vector<uint8_t> nonce =
-            vector<uint8_t>(profile.mac.begin(), profile.mac.begin() + kAesGcmIvSize);
-    optional<vector<uint8_t>> mac = encryptAes128Gcm(storageKey, nonce, {}, cborData);
-    if (!mac) {
-        return false;
-    }
-    if (mac.value() != vector<uint8_t>(profile.mac)) {
-        return false;
-    }
-    return true;
-}
 
 vector<uint8_t> testHardwareBoundKey = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
@@ -1795,20 +1718,6 @@
     return testHardwareBoundKey;
 }
 
-vector<uint8_t> entryCreateAdditionalData(const string& nameSpace, const string& name,
-                                          const vector<uint16_t> accessControlProfileIds) {
-    cppbor::Map map;
-    map.add("Namespace", nameSpace);
-    map.add("Name", name);
-
-    cppbor::Array acpIds;
-    for (auto id : accessControlProfileIds) {
-        acpIds.add(id);
-    }
-    map.add("AccessControlProfileIds", std::move(acpIds));
-    return map.encode();
-}
-
 }  // namespace support
 }  // namespace identity
 }  // namespace hardware
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
new file mode 100644
index 0000000..a2d73ead
--- /dev/null
+++ b/keymaster/aidl/Android.bp
@@ -0,0 +1,18 @@
+aidl_interface {
+    name: "android.hardware.keymaster",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/keymaster/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+}
diff --git a/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl b/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
new file mode 100644
index 0000000..58602aa
--- /dev/null
+++ b/keymaster/aidl/android/hardware/keymaster/HardwareAuthToken.aidl
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.keymaster;
+
+import android.hardware.keymaster.Timestamp;
+import android.hardware.keymaster.HardwareAuthenticatorType;
+
+/**
+ * HardwareAuthToken is used to prove successful user authentication, to unlock the use of a key.
+ *
+ * HardwareAuthTokens are produced by other secure environment applications, notably GateKeeper and
+ * Fingerprint, in response to successful user authentication events.  These tokens are passed to
+ * begin(), update(), and finish() to prove that authentication occurred.  See those methods for
+ * more details.  It is up to the caller to determine which of the generated auth tokens is
+ * appropriate for a given key operation.
+ */
+@VintfStability
+parcelable HardwareAuthToken {
+
+    /**
+     * challenge is a value that's used to enable authentication tokens to authorize specific
+     * events.  The primary use case for challenge is to authorize an IKeymasterDevice cryptographic
+     * operation, for keys that require authentication per operation. See begin() for details.
+     */
+    long challenge;
+
+    /**
+     *  userId is the a "secure" user ID.  It is not related to any Android user ID or UID, but is
+     *  created in the Gatekeeper application in the secure environment.
+     */
+    long userId;
+
+    /**
+     *  authenticatorId is the a "secure" user ID.  It is not related to any Android user ID or UID,
+     *  but is created in an authentication application in the secure environment, such as the
+     *  Fingerprint application.
+     */
+    long authenticatorId;  // Secure authenticator ID.
+
+    /**
+     * authenticatorType describes the type of authentication that took place, e.g. password or
+     * fingerprint.
+     */
+    HardwareAuthenticatorType authenticatorType;
+
+    /**
+     * timestamp indicates when the user authentication took place, in milliseconds since some
+     * starting point (generally the most recent device boot) which all of the applications within
+     * one secure environment must agree upon.  This timestamp is used to determine whether or not
+     * the authentication occurred recently enough to unlock a key (see Tag::AUTH_TIMEOUT).
+     */
+    Timestamp timestamp;
+
+    /**
+     * MACs are computed with a backward-compatible method, used by Keymaster 3.0, Gatekeeper 1.0
+     * and Fingerprint 1.0, as well as pre-treble HALs.
+     *
+     * The MAC is Constants::AUTH_TOKEN_MAC_LENGTH bytes in length and is computed as follows:
+     *
+     *     HMAC_SHA256(
+     *         H, 0 || challenge || user_id || authenticator_id || authenticator_type || timestamp)
+     *
+     * where ``||'' represents concatenation, the leading zero is a single byte, and all integers
+     * are represented as unsigned values, the full width of the type.  The challenge, userId and
+     * authenticatorId values are in machine order, but authenticatorType and timestamp are in
+     * network order (big-endian).  This odd construction is compatible with the hw_auth_token_t
+     * structure,
+     *
+     * Note that mac is a vec rather than an array, not because it's actually variable-length but
+     * because it could be empty.  As documented in the IKeymasterDevice::begin,
+     * IKeymasterDevice::update and IKeymasterDevice::finish doc comments, an empty mac indicates
+     * that this auth token is empty.
+     */
+    byte[] mac;
+}
diff --git a/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl b/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl
new file mode 100644
index 0000000..3141858
--- /dev/null
+++ b/keymaster/aidl/android/hardware/keymaster/HardwareAuthenticatorType.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.keymaster;
+
+/**
+ * Hardware authentication type, used by HardwareAuthTokens to specify the mechanism used to
+ * authentiate the user, and in KeyCharacteristics to specify the allowable mechanisms for
+ * authenticating to activate a key.
+ */
+@VintfStability
+@Backing(type="int")
+enum HardwareAuthenticatorType {
+    NONE = 0,
+    PASSWORD = 1 << 0,
+    FINGERPRINT = 1 << 1,
+    // Additional entries must be powers of 2.
+    ANY = 0xFFFFFFFF,
+}
diff --git a/radio/config/1.3/IRadioConfigIndication.hal b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
similarity index 66%
rename from radio/config/1.3/IRadioConfigIndication.hal
rename to keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
index 9ef496c..4b2f108 100644
--- a/radio/config/1.3/IRadioConfigIndication.hal
+++ b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,9 @@
  * limitations under the License.
  */
 
-package android.hardware.radio.config@1.3;
+package android.hardware.keymaster;
 
-import @1.2::IRadioConfigIndication;
-
-/**
- * Interface declaring unsolicited radio config indications.
- */
-interface IRadioConfigIndication extends @1.2::IRadioConfigIndication {
-
-};
+@VintfStability
+parcelable Timestamp {
+    long milliSeconds;
+}
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index ba9fb45..03af671 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -14,13 +14,30 @@
 // limitations under the License.
 //
 
+cc_defaults {
+    name: "neuralnetworks_vts_functional_defaults",
+    defaults: ["VtsHalTargetTestDefaults"],
+    arch: {
+        x86: {
+            cflags: [ "-D_Float16=__fp16",
+                      "-Xclang", "-fnative-half-type",
+                      "-Xclang", "-fallow-half-arguments-and-returns" ],
+        },
+        x86_64: {
+            cflags: [ "-D_Float16=__fp16",
+                      "-Xclang", "-fnative-half-type",
+                      "-Xclang", "-fallow-half-arguments-and-returns" ],
+        },
+    },
+}
+
 cc_library_static {
     name: "VtsHalNeuralNetworksV1_0_utils",
     srcs: [
         "Callbacks.cpp",
         "Utils.cpp",
     ],
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: ["neuralnetworks_vts_functional_defaults"],
     export_include_dirs: ["include"],
     shared_libs: [
         "libfmq",
@@ -42,7 +59,7 @@
 
 cc_test {
     name: "VtsHalNeuralnetworksV1_0TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: ["neuralnetworks_vts_functional_defaults"],
     srcs: [
         "BasicTests.cpp",
         "TestAssertions.cpp",
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 595ad85..e28605d 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -42,10 +42,11 @@
 
 Model createModel(const TestModel& testModel) {
     // Model operands.
-    hidl_vec<Operand> operands(testModel.operands.size());
+    CHECK_EQ(testModel.referenced.size(), 0u);  // Not supported in 1.0.
+    hidl_vec<Operand> operands(testModel.main.operands.size());
     size_t constCopySize = 0, constRefSize = 0;
-    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-        const auto& op = testModel.operands[i];
+    for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
+        const auto& op = testModel.main.operands[i];
 
         DataLocation loc = {};
         if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
@@ -70,9 +71,9 @@
     }
 
     // Model operations.
-    hidl_vec<Operation> operations(testModel.operations.size());
-    std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
-                   [](const TestOperation& op) -> Operation {
+    hidl_vec<Operation> operations(testModel.main.operations.size());
+    std::transform(testModel.main.operations.begin(), testModel.main.operations.end(),
+                   operations.begin(), [](const TestOperation& op) -> Operation {
                        return {.type = static_cast<OperationType>(op.type),
                                .inputs = op.inputs,
                                .outputs = op.outputs};
@@ -80,8 +81,8 @@
 
     // Constant copies.
     hidl_vec<uint8_t> operandValues(constCopySize);
-    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-        const auto& op = testModel.operands[i];
+    for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
+        const auto& op = testModel.main.operands[i];
         if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
             const uint8_t* begin = op.data.get<uint8_t>();
             const uint8_t* end = begin + op.data.size();
@@ -102,8 +103,8 @@
                 reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
         CHECK(mappedPtr != nullptr);
 
-        for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-            const auto& op = testModel.operands[i];
+        for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
+            const auto& op = testModel.main.operands[i];
             if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
                 const uint8_t* begin = op.data.get<uint8_t>();
                 const uint8_t* end = begin + op.data.size();
@@ -114,8 +115,8 @@
 
     return {.operands = std::move(operands),
             .operations = std::move(operations),
-            .inputIndexes = testModel.inputIndexes,
-            .outputIndexes = testModel.outputIndexes,
+            .inputIndexes = testModel.main.inputIndexes,
+            .outputIndexes = testModel.main.outputIndexes,
             .operandValues = std::move(operandValues),
             .pools = std::move(pools)};
 }
diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp
index 5b630fd..0dba85a 100644
--- a/neuralnetworks/1.0/vts/functional/Utils.cpp
+++ b/neuralnetworks/1.0/vts/functional/Utils.cpp
@@ -42,10 +42,10 @@
 
 Request createRequest(const TestModel& testModel) {
     // Model inputs.
-    hidl_vec<RequestArgument> inputs(testModel.inputIndexes.size());
+    hidl_vec<RequestArgument> inputs(testModel.main.inputIndexes.size());
     size_t inputSize = 0;
-    for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
-        const auto& op = testModel.operands[testModel.inputIndexes[i]];
+    for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
+        const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
         if (op.data.size() == 0) {
             // Omitted input.
             inputs[i] = {.hasNoValue = true};
@@ -59,10 +59,10 @@
     }
 
     // Model outputs.
-    hidl_vec<RequestArgument> outputs(testModel.outputIndexes.size());
+    hidl_vec<RequestArgument> outputs(testModel.main.outputIndexes.size());
     size_t outputSize = 0;
-    for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) {
-        const auto& op = testModel.operands[testModel.outputIndexes[i]];
+    for (uint32_t i = 0; i < testModel.main.outputIndexes.size(); i++) {
+        const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
 
         // In the case of zero-sized output, we should at least provide a one-byte buffer.
         // This is because zero-sized tensors are only supported internally to the driver, or
@@ -90,8 +90,8 @@
     CHECK(inputPtr != nullptr);
 
     // Copy input data to the memory pool.
-    for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
-        const auto& op = testModel.operands[testModel.inputIndexes[i]];
+    for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
+        const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
         if (op.data.size() > 0) {
             const uint8_t* begin = op.data.get<uint8_t>();
             const uint8_t* end = begin + op.data.size();
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 69e1761..9ba1925 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -16,7 +16,7 @@
 
 cc_test {
     name: "VtsHalNeuralnetworksV1_1TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: ["neuralnetworks_vts_functional_defaults"],
     srcs: [
         "BasicTests.cpp",
         "TestAssertions.cpp",
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
index 7a929d6..cee15a3 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
@@ -49,10 +49,11 @@
 
 Model createModel(const TestModel& testModel) {
     // Model operands.
-    hidl_vec<Operand> operands(testModel.operands.size());
+    CHECK_EQ(testModel.referenced.size(), 0u);  // Not supported in 1.1.
+    hidl_vec<Operand> operands(testModel.main.operands.size());
     size_t constCopySize = 0, constRefSize = 0;
-    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-        const auto& op = testModel.operands[i];
+    for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
+        const auto& op = testModel.main.operands[i];
 
         DataLocation loc = {};
         if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
@@ -77,9 +78,9 @@
     }
 
     // Model operations.
-    hidl_vec<Operation> operations(testModel.operations.size());
-    std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
-                   [](const TestOperation& op) -> Operation {
+    hidl_vec<Operation> operations(testModel.main.operations.size());
+    std::transform(testModel.main.operations.begin(), testModel.main.operations.end(),
+                   operations.begin(), [](const TestOperation& op) -> Operation {
                        return {.type = static_cast<OperationType>(op.type),
                                .inputs = op.inputs,
                                .outputs = op.outputs};
@@ -87,8 +88,8 @@
 
     // Constant copies.
     hidl_vec<uint8_t> operandValues(constCopySize);
-    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-        const auto& op = testModel.operands[i];
+    for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
+        const auto& op = testModel.main.operands[i];
         if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
             const uint8_t* begin = op.data.get<uint8_t>();
             const uint8_t* end = begin + op.data.size();
@@ -109,8 +110,8 @@
                 reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
         CHECK(mappedPtr != nullptr);
 
-        for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-            const auto& op = testModel.operands[i];
+        for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
+            const auto& op = testModel.main.operands[i];
             if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
                 const uint8_t* begin = op.data.get<uint8_t>();
                 const uint8_t* end = begin + op.data.size();
@@ -121,8 +122,8 @@
 
     return {.operands = std::move(operands),
             .operations = std::move(operations),
-            .inputIndexes = testModel.inputIndexes,
-            .outputIndexes = testModel.outputIndexes,
+            .inputIndexes = testModel.main.inputIndexes,
+            .outputIndexes = testModel.main.outputIndexes,
             .operandValues = std::move(operandValues),
             .pools = std::move(pools),
             .relaxComputationFloat32toFloat16 = testModel.isRelaxed};
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index e867120..f0fd769 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -2314,7 +2314,38 @@
     AXIS_ALIGNED_BBOX_TRANSFORM = 41,
 
     /**
-     * Performs a forward LSTM on the input followed by a backward LSTM.
+     * A recurrent neural network layer that applies an LSTM cell to a
+     * sequence of inputs in forward and backward directions.
+     *
+     * The op supports cross-linking via an auxiliary input. Regular cell feeds
+     * one input into the two RNN cells in the following way:
+     *
+     *       INPUT  (INPUT_REVERSED)
+     *         |         |
+     *    ---------------------
+     *    | FW_LSTM   BW_LSTM |
+     *    ---------------------
+     *         |         |
+     *      FW_OUT     BW_OUT
+     *
+     * An op with cross-linking takes two inputs and feeds them into the RNN
+     * cells in the following way:
+     *
+     *       AUX_INPUT   (AUX_INPUT_REVERSED)
+     *           |             |
+     *     INPUT | (INPUT_R'D.)|
+     *       |   |       |     |
+     *    -----------------------
+     *    |  \  /        \    / |
+     *    | FW_LSTM     BW_LSTM |
+     *    -----------------------
+     *         |           |
+     *      FW_OUT      BW_OUT
+     *
+     * The cross-linking mode is enabled iff auxiliary input and auxiliary
+     * weights are present. While stacking this op on top of itself, this
+     * allows to connect both forward and backward outputs from previous cell
+     * to the next cell's input.
      *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16}
@@ -2324,7 +2355,6 @@
      *
      * All input and output tensors must be of the same type.
      *
-     *
      * Inputs:
      * * 0: The input.
      *      A 3-D tensor of shape:
@@ -2533,8 +2563,8 @@
      * * “activation” is the function passed as the “fused_activation_function”
      *   argument (if not “NONE”).
      *
-     * The op also supports an auxiliary input. Regular cell feeds one input
-     * into the two RNN cells in the following way:
+     * The op supports cross-linking via an auxiliary input. Regular cell feeds
+     * one input into the two RNN cells in the following way:
      *
      *       INPUT  (INPUT_REVERSED)
      *         |         |
@@ -2544,8 +2574,8 @@
      *         |         |
      *      FW_OUT     BW_OUT
      *
-     * An op with an auxiliary input takes two inputs and feeds them into the
-     * RNN cells in the following way:
+     * An op with cross-linking takes two inputs and feeds them into the RNN
+     * cells in the following way:
      *
      *       AUX_INPUT   (AUX_INPUT_REVERSED)
      *           |             |
@@ -2558,9 +2588,10 @@
      *         |           |
      *      FW_OUT      BW_OUT
      *
-     * While stacking this op on top of itself, this allows to connect both
-     * forward and backward outputs from previous cell to the next cell's
-     * inputs.
+     * The cross-linking mode is enabled iff auxiliary input and auxiliary
+     * weights are present. While stacking this op on top of itself, this
+     * allows to connect both forward and backward outputs from previous cell
+     * to the next cell's input.
      *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16}
@@ -3165,7 +3196,7 @@
      * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
      *      walking through input in the ‘height’ dimension.
      * * 9: An {@link OperandType::INT32} scalar, specifying the number of
-            groups.
+     *      groups.
      * * 10: An {@link OperandType::INT32} scalar, and has to be one of the
      *       {@link FusedActivationFunc} values. Specifies the activation to
      *       invoke on the result.
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index fc727b7..31a1a81 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -16,7 +16,7 @@
 
 cc_library_static {
     name: "VtsHalNeuralNetworksV1_2Callbacks",
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: ["neuralnetworks_vts_functional_defaults"],
     export_include_dirs: ["include"],
     srcs: [
         "Callbacks.cpp",
@@ -33,7 +33,7 @@
 
 cc_test {
     name: "VtsHalNeuralnetworksV1_2TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: ["neuralnetworks_vts_functional_defaults"],
     srcs: [
         "BasicTests.cpp",
         "CompilationCachingTests.cpp",
@@ -71,5 +71,5 @@
     header_libs: [
         "libneuralnetworks_headers",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
index 8e82c53..58d3c4a 100644
--- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
@@ -79,6 +79,18 @@
     EXPECT_TRUE(ret.isOk());
 }
 
+// device name test
+TEST_P(NeuralnetworksHidlTest, GetDeviceNameTest) {
+    const std::string deviceName = getName(GetParam());
+    auto pos = deviceName.find('-');
+    EXPECT_NE(pos, std::string::npos);
+    // The separator should not be the first or last character.
+    EXPECT_NE(pos, 0);
+    EXPECT_NE(pos, deviceName.length() - 1);
+    // There should only be 1 separator.
+    EXPECT_EQ(std::string::npos, deviceName.find('-', pos + 1));
+}
+
 // device supported extensions test
 TEST_P(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) {
     Return<void> ret = kDevice->getSupportedExtensions(
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 2130a76..10dec79 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -207,10 +207,10 @@
     };
 
     return {
-            .operands = std::move(operands),
-            .operations = std::move(operations),
-            .inputIndexes = {1},
-            .outputIndexes = {len * 2 + 1},
+            .main = {.operands = std::move(operands),
+                     .operations = std::move(operations),
+                     .inputIndexes = {1},
+                     .outputIndexes = {len * 2 + 1}},
             .isRelaxed = false,
     };
 }
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index 599fd1d..4c8fede 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -75,10 +75,11 @@
 
 Model createModel(const TestModel& testModel) {
     // Model operands.
-    hidl_vec<Operand> operands(testModel.operands.size());
+    CHECK_EQ(testModel.referenced.size(), 0u);  // Not supported in 1.1.
+    hidl_vec<Operand> operands(testModel.main.operands.size());
     size_t constCopySize = 0, constRefSize = 0;
-    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-        const auto& op = testModel.operands[i];
+    for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
+        const auto& op = testModel.main.operands[i];
 
         DataLocation loc = {};
         if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
@@ -110,9 +111,9 @@
     }
 
     // Model operations.
-    hidl_vec<Operation> operations(testModel.operations.size());
-    std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
-                   [](const TestOperation& op) -> Operation {
+    hidl_vec<Operation> operations(testModel.main.operations.size());
+    std::transform(testModel.main.operations.begin(), testModel.main.operations.end(),
+                   operations.begin(), [](const TestOperation& op) -> Operation {
                        return {.type = static_cast<OperationType>(op.type),
                                .inputs = op.inputs,
                                .outputs = op.outputs};
@@ -120,8 +121,8 @@
 
     // Constant copies.
     hidl_vec<uint8_t> operandValues(constCopySize);
-    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-        const auto& op = testModel.operands[i];
+    for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
+        const auto& op = testModel.main.operands[i];
         if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
             const uint8_t* begin = op.data.get<uint8_t>();
             const uint8_t* end = begin + op.data.size();
@@ -142,8 +143,8 @@
                 reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
         CHECK(mappedPtr != nullptr);
 
-        for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-            const auto& op = testModel.operands[i];
+        for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
+            const auto& op = testModel.main.operands[i];
             if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
                 const uint8_t* begin = op.data.get<uint8_t>();
                 const uint8_t* end = begin + op.data.size();
@@ -154,15 +155,15 @@
 
     return {.operands = std::move(operands),
             .operations = std::move(operations),
-            .inputIndexes = testModel.inputIndexes,
-            .outputIndexes = testModel.outputIndexes,
+            .inputIndexes = testModel.main.inputIndexes,
+            .outputIndexes = testModel.main.outputIndexes,
             .operandValues = std::move(operandValues),
             .pools = std::move(pools),
             .relaxComputationFloat32toFloat16 = testModel.isRelaxed};
 }
 
 static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) {
-    const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size();
+    const auto byteSize = testModel.main.operands[testModel.main.outputIndexes[index]].data.size();
     return byteSize > 1u;
 }
 
@@ -302,17 +303,17 @@
             // either empty, or have the same number of elements as the number of outputs.
             ASSERT_EQ(ErrorStatus::NONE, executionStatus);
             ASSERT_TRUE(outputShapes.size() == 0 ||
-                        outputShapes.size() == testModel.outputIndexes.size());
+                        outputShapes.size() == testModel.main.outputIndexes.size());
             break;
         case OutputType::UNSPECIFIED:
             // If the model output operands are not fully specified, outputShapes must have
             // the same number of elements as the number of outputs.
             ASSERT_EQ(ErrorStatus::NONE, executionStatus);
-            ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
+            ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
             break;
         case OutputType::INSUFFICIENT:
             ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
-            ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
+            ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
             ASSERT_FALSE(outputShapes[0].isSufficient);
             return;
     }
@@ -320,7 +321,7 @@
     // Go through all outputs, check returned output shapes.
     for (uint32_t i = 0; i < outputShapes.size(); i++) {
         EXPECT_TRUE(outputShapes[i].isSufficient);
-        const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions;
+        const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
         const std::vector<uint32_t> actual = outputShapes[i].dimensions;
         EXPECT_EQ(expect, actual);
     }
diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal
index 610db79..e0b04a8 100644
--- a/neuralnetworks/1.3/IDevice.hal
+++ b/neuralnetworks/1.3/IDevice.hal
@@ -48,19 +48,6 @@
     getCapabilities_1_3() generates (ErrorStatus status, Capabilities capabilities);
 
     /**
-     * Returns whether the device is able to complete or abort a task within a
-     * specified duration.
-     *
-     * @return prepareModelDeadline 'true' if the device supports completing or
-     *     aborting model preparation by the deadline when the deadline is supplied,
-     *     'false' otherwise.
-     * @return executionDeadline 'true' if the device supports completing or
-     *     aborting an execution by the deadline when the deadline is supplied,
-     *     'false' otherwise.
-     */
-    supportsDeadlines() generates (bool prepareModelDeadline, bool executionDeadline);
-
-    /**
      * Gets the supported operations in a model.
      *
      * getSupportedOperations indicates which operations of the top-level
@@ -140,14 +127,10 @@
      *
      * prepareModel_1_3 can be called with an optional deadline. If the model
      * is not able to be prepared before the provided deadline, the model
-     * preparation must be aborted, and either {@link
+     * preparation may be aborted, and either {@link
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
-     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
-     * If the service reports that it does not support preparation deadlines via
-     * IDevice::supportsDeadlines, and prepareModel_1_3 is called with a
-     * deadline, then the argument is invalid, and {@link
-     * ErrorStatus::INVALID_ARGUMENT} must be returned.
      *
      * Optionally, the driver may save the prepared model to cache during the
      * asynchronous preparation. Any error that occurs when saving to cache must
@@ -172,9 +155,9 @@
      *     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 must be prepared. If the
-     *     model cannot be prepared by the deadline, the preparation must be
-     *     aborted.
+     * @param deadline The time by which the model is expected to be prepared.
+     *     If the model cannot be prepared by the deadline, the preparation may
+     *     be aborted.
      * @param modelCache A vector of handles with each entry holding exactly one
      *     cache file descriptor for the security-sensitive cache. The length of
      *     the vector must either be 0 indicating that caching information is
@@ -209,8 +192,8 @@
      *     - GENERAL_FAILURE if there is an unspecified error
      *     - INVALID_ARGUMENT if one of the input arguments related to preparing
      *       the model is invalid
-     *     - MISSED_DEADLINE_* if the deadline for preparing a model cannot be
-     *       met
+     *     - MISSED_DEADLINE_* if the preparation is aborted because the model
+     *       cannot be prepared by the deadline
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
     prepareModel_1_3(Model model, ExecutionPreference preference,
@@ -260,21 +243,13 @@
      * the model, the callback object must be invoked with the appropriate
      * ErrorStatus value and nullptr for the IPreparedModel.
      *
-     * The model is prepared with a priority. This priority is relative to other
-     * prepared models owned by the same client. Higher priority executions may
-     * use more compute resources than lower priority executions, and may
-     * preempt or starve lower priority executions.
-     *
      * prepareModelFromCache_1_3 can be called with an optional deadline. If the
      * model is not able to prepared before the provided deadline, the model
-     * preparation must be aborted, and either {@link
+     * preparation may be aborted, and either {@link
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT}
-     * or {@link ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The
+     * 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. If the service reports that it does not support
-     * preparation deadlines via IDevice::supportsDeadlines, and
-     * prepareModelFromCache_1_3 is called with a deadline, then the argument is
-     * invalid, and {@link ErrorStatus::INVALID_ARGUMENT} must be returned.
+     * described above.
      *
      * 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
@@ -284,11 +259,9 @@
      * used with different shapes of inputs on different (possibly concurrent)
      * executions.
      *
-     * @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 must be prepared. If the
-     *     model cannot be prepared by the deadline, the preparation must be
-     *     aborted.
+     * @param deadline The time by which the model is expected to be prepared.
+     *     If the model cannot be prepared by the deadline, the preparation may
+     *     be aborted.
      * @param modelCache A vector of handles with each entry holding exactly one
      *     cache file descriptor for the security-sensitive cache. The length of
      *     the vector must match the numModelCache returned from getNumberOfCacheFilesNeeded.
@@ -314,11 +287,11 @@
      *     - GENERAL_FAILURE if caching is not supported or if there is an
      *       unspecified error
      *     - INVALID_ARGUMENT if one of the input arguments is invalid
-     *     - MISSED_DEADLINE_* if the deadline for preparing a model cannot be
-     *       met
+     *     - MISSED_DEADLINE_* if the preparation is aborted because the model
+     *       cannot be prepared by the deadline
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
-    prepareModelFromCache_1_3(Priority priority, OptionalTimePoint deadline,
+    prepareModelFromCache_1_3(OptionalTimePoint deadline,
                               vec<handle> modelCache, vec<handle> dataCache,
                               uint8_t[Constant:BYTE_SIZE_OF_CACHE_TOKEN] token,
                               IPreparedModelCallback callback)
@@ -379,5 +352,5 @@
      */
     allocate(BufferDesc desc, vec<IPreparedModel> preparedModels, vec<BufferRole> inputRoles,
              vec<BufferRole> outputRoles)
-            generates (ErrorStatus status, IBuffer buffer, int32_t token);
+            generates (ErrorStatus status, IBuffer buffer, uint32_t token);
 };
diff --git a/neuralnetworks/1.3/IExecutionCallback.hal b/neuralnetworks/1.3/IExecutionCallback.hal
index 439428a..ea11b17 100644
--- a/neuralnetworks/1.3/IExecutionCallback.hal
+++ b/neuralnetworks/1.3/IExecutionCallback.hal
@@ -47,7 +47,8 @@
      *                 corresponding output
      *               - INVALID_ARGUMENT if one of the input arguments to
      *                 prepareModel is invalid
-     *               - MISSED_DEADLINE_* if the deadline could not be met
+     *               - MISSED_DEADLINE_* if the execution is aborted because it
+     *                 cannot be completed by the deadline
      *               - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      * @param outputShapes A list of shape information of model output operands.
      *                     The index into "outputShapes" corresponds with to index
diff --git a/neuralnetworks/1.3/IFencedExecutionCallback.hal b/neuralnetworks/1.3/IFencedExecutionCallback.hal
index 39076b9..949438e 100644
--- a/neuralnetworks/1.3/IFencedExecutionCallback.hal
+++ b/neuralnetworks/1.3/IFencedExecutionCallback.hal
@@ -38,11 +38,24 @@
      *                - DEVICE_UNAVAILABLE if driver is offline or busy
      *                - GENERAL_FAILURE if the asynchronous task resulted in an
      *                  unspecified error
-     * @return timing Duration of execution. Unless MeasureTiming::YES was passed when
-     *                launching the execution and status is NONE, all times must
-     *                be reported as UINT64_MAX. A driver may choose to report
-     *                any time as UINT64_MAX, indicating that particular measurement is
-     *                not available.
+     *                - MISSED_DEADLINE_* if the execution is aborted because it
+     *                  cannot be completed by the deadline
+     *                - RESOURCE_EXHAUSTED_* if the task was aborted by the
+     *                  driver
+     * @return timingLaunched The duration starts when executeFenced is called and ends when
+     *                        executeFenced signals the returned syncFence.
+     *                        Unless MeasureTiming::YES was passed when
+     *                        launching the execution and status is NONE, all times
+     *                        must be reported as UINT64_MAX. A driver may choose to
+     *                        report any time as UINT64_MAX, indicating that particular
+     *                        measurement is not available.
+     * @return timingFenced The duration starts when all waitFor sync fences have been signaled
+     *                      and ends when executeFenced signals the returned syncFence.
+     *                      Unless MeasureTiming::YES was passed when
+     *                      launching the execution and status is NONE, all times
+     *                      must be reported as UINT64_MAX. A driver may choose to
+     *                      report any time as UINT64_MAX, indicating that particular
+     *                      measurement is not available.
      */
-    getExecutionInfo() generates (ErrorStatus status, Timing timing);
+    getExecutionInfo() generates (ErrorStatus status, Timing timingLaunched, Timing timingFenced);
 };
diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
index f84bcf4..a1814b5 100644
--- a/neuralnetworks/1.3/IPreparedModel.hal
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -21,6 +21,7 @@
 import @1.2::OutputShape;
 import @1.2::Timing;
 import ErrorStatus;
+import OptionalTimeoutDuration;
 import OptionalTimePoint;
 import Request;
 import IExecutionCallback;
@@ -68,15 +69,11 @@
      *   There must be no failure unless the device itself is in a bad state.
      *
      * execute_1_3 can be called with an optional deadline. If the execution
-     * is not able to completed before the provided deadline, the execution
-     * must be aborted, and either {@link
+     * is not able to be completed before the provided deadline, the execution
+     * may be aborted, and either {@link
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
-     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
-     * If the service reports that it does not support execution deadlines via
-     * IDevice::supportsDeadlines, and execute_1_3 is called with a deadline,
-     * then the argument is invalid, and {@link ErrorStatus::INVALID_ARGUMENT}
-     * must be returned.
      *
      * Any number of calls to the execute* and executeSynchronously* functions,
      * in any combination, may be made concurrently, even on the same
@@ -88,9 +85,20 @@
      *                The duration runs from the time the driver sees the call
      *                to the execute_1_3 function to the time the driver invokes
      *                the callback.
-     * @param deadline The time by which execution must complete. If the
-     *                 execution cannot be finished by the deadline, the
-     *                 execution must be aborted.
+     * @param deadline The time by which the execution is expected to complete.
+     *                 If the execution cannot be completed by the deadline, the
+     *                 execution may be aborted.
+     * @param loopTimeoutDuration The maximum amount of time 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 the model
+     *                            contains a {@link OperationType::WHILE}
+     *                            operation and no loop timeout duration is
+     *                            provided, the maximum amount of time is {@link
+     *                            LoopTimeoutDurationNs::DEFAULT}. When
+     *                            provided, the duration must not exceed {@link
+     *                            LoopTimeoutDurationNs::MAXIMUM}.
      * @param callback A callback object used to return the error status of
      *                 the execution, shape information of model output operands, and
      *                 duration of execution. The callback object's notify function must
@@ -104,13 +112,13 @@
      *                  not large enough to store the resultant values
      *                - INVALID_ARGUMENT if one of the input arguments is
      *                  invalid
-     *                - MISSED_DEADLINE_* if the deadline for executing a model
-     *                  cannot be met
+     *                - MISSED_DEADLINE_* if the execution is aborted because it
+     *                  cannot be completed by the deadline
      *                - RESOURCE_EXHAUSTED_* if the task was aborted by the
      *                  driver
      */
     execute_1_3(Request request, MeasureTiming measure, OptionalTimePoint deadline,
-                IExecutionCallback callback)
+                OptionalTimeoutDuration loopTimeoutDuration, IExecutionCallback callback)
         generates (ErrorStatus status);
 
     /**
@@ -138,16 +146,12 @@
      * (ErrorStatus::NONE): There must be no failure unless the device itself is
      * in a bad state.
      *
-     * executeSynchronously_1_3 can be called with an optional deadline. If the
-     * execution is not able to completed before the provided deadline, the
-     * execution must be aborted, and either {@link
+     * executeSynchronously_1_3 may be called with an optional deadline. If the
+     * execution is not able to be completed before the provided deadline, the
+     * execution may be aborted, and either {@link
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
-     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
-     * If the service reports that it does not support execution deadlines via
-     * IDevice::supportsDeadlines, and executeSynchronously_1_3 is called with a
-     * deadline, then the argument is invalid, and
-     * {@link ErrorStatus::INVALID_ARGUMENT} must be returned.
      *
      * Any number of calls to the execute* and executeSynchronously* functions,
      * in any combination, may be made concurrently, even on the same
@@ -159,9 +163,20 @@
      *                The duration runs from the time the driver sees the call
      *                to the executeSynchronously_1_3 function to the time the driver
      *                returns from the function.
-     * @param deadline The time by which execution must complete. If the
-     *                 execution cannot be finished by the deadline, the
-     *                 execution must be aborted.
+     * @param deadline The time by which the execution is expected to complete.
+     *                 If the execution cannot be finished by the deadline, the
+     *                 execution may be aborted.
+     * @param loopTimeoutDuration The maximum amount of time 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 the model
+     *                            contains a {@link OperationType::WHILE}
+     *                            operation and no loop timeout duration is
+     *                            provided, the maximum amount of time is {@link
+     *                            LoopTimeoutDurationNs::DEFAULT}. When
+     *                            provided, the duration must not exceed {@link
+     *                            LoopTimeoutDurationNs::MAXIMUM}.
      * @return status Error status of the execution, must be:
      *                - NONE if execution is performed successfully
      *                - DEVICE_UNAVAILABLE if driver is offline or busy
@@ -171,8 +186,8 @@
      *                  corresponding output
      *                - INVALID_ARGUMENT if one of the input arguments is
      *                  invalid
-     *                - MISSED_DEADLINE_* if the deadline for executing a model
-     *                  cannot be met
+     *                - MISSED_DEADLINE_* if the execution is aborted because it
+     *                  cannot be completed by the deadline
      *                - RESOURCE_EXHAUSTED_* if the task was aborted by the
      *                  driver
      * @return outputShapes A list of shape information of model output operands.
@@ -186,7 +201,8 @@
      *                measurement is not available.
      */
     executeSynchronously_1_3(Request request, MeasureTiming measure,
-                             OptionalTimePoint deadline)
+                             OptionalTimePoint deadline,
+                             OptionalTimeoutDuration loopTimeoutDuration)
                   generates (ErrorStatus status, vec<OutputShape> outputShapes,
                              Timing timing);
 
@@ -194,52 +210,83 @@
      * Launch a fenced asynchronous execution on a prepared model.
      *
      * The execution is performed asynchronously with respect to the caller.
-     * executeFenced must fully validate the request, and only accept one that is
-     * guaranteed to be completed, unless a hardware failure or kernel panic happens on the device.
-     * If there is an error during validation, executeFenced must immediately return with
-     * the corresponding ErrorStatus. If the request is valid and there is no error launching,
-     * executeFenced must dispatch an asynchronous task to perform the execution in the
-     * background, and immediately return with ErrorStatus::NONE, a sync_fence that will be
-     * signaled once the execution is completed, and a callback that can be used by the client
-     * to query the duration and runtime error status. If the task has finished
-     * before the call returns, empty handle may be returned for the sync fence. If the
-     * asynchronous task fails to launch, executeFenced must immediately return with
-     * ErrorStatus::GENERAL_FAILURE, and empty handle for the sync fence and nullptr
-     * for callback. The execution must wait for all the sync fences (if any) in wait_for to be
-     * signaled before starting the actual execution.
-     *
-     * If any of sync fences in wait_for changes to error status after the executeFenced
-     * call succeeds, the driver must immediately set the returned sync fence to error status.
+     * executeFenced must verify the inputs to the function are correct, and the usages
+     * of memory pools allocated by IDevice::allocate are valid. If there is an error,
+     * executeFenced must immediately return with the corresponding ErrorStatus, an empty
+     * handle for syncFence, and nullptr for callback. If the inputs to the function
+     * are valid and there is no error, executeFenced must dispatch an asynchronous task
+     * to perform the execution in the background, and immediately return with
+     * ErrorStatus::NONE, a sync fence that will be signaled once the execution is completed,
+     * and a callback that can be used by the client to query the duration and runtime error
+     * status. If the task has finished before the call returns, an empty handle may be returned
+     * for syncFence. The execution must wait for all the sync fences (if any) in waitFor
+     * to be signaled before starting the actual execution.
      *
      * When the asynchronous task has finished its execution, it must
-     * immediately signal the sync_fence created when dispatching. After
-     * the sync_fence is signaled, the task must not modify the content of
+     * immediately signal the syncFence returned from the executeFenced call. After
+     * the syncFence is signaled, the task must not modify the content of
      * any data object referenced by 'request' (described by the
      * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}).
      *
+     * executeFenced may be called with an optional deadline and an optional duration.
+     * If the execution is not able to be completed before the provided deadline or
+     * within the timeout duration (measured from when all sync fences in waitFor are
+     * signaled), whichever comes earlier, the execution may be aborted, and either
+     * {@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.
+     *
+     * 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
+     * has been reached or the duration has elapsed, the driver must immediately set the returned
+     * syncFence to error status.
+     *
      * Any number of calls to the executeFenced, execute* and executeSynchronously*
      * functions, in any combination, may be made concurrently, even on the same
      * IPreparedModel object.
      *
      * @param request The input and output information on which the prepared
-     *                model is to be executed.
+     *                model is to be executed. The outputs in the request must have
+     *                fully specified dimensions.
      * @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.
-     *                The duration runs from the time the driver sees the call
-     *                to the executeFenced function to the time sync_fence is triggered.
+     * @param deadline The time by which the execution is expected to complete.
+     *                 If the execution cannot be finished by the deadline, the
+     *                 execution may be aborted.
+     * @param loopTimeoutDuration The maximum amount of time 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 the model
+     *                            contains a {@link OperationType::WHILE}
+     *                            operation and no loop timeout duration is
+     *                            provided, the maximum amount of time is {@link
+     *                            LoopTimeoutDurationNs::DEFAULT}. When
+     *                            provided, the duration must not exceed {@link
+     *                            LoopTimeoutDurationNs::MAXIMUM}.
+     * @param duration The length of time 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.
      * @return status Error status of the call, must be:
      *                - NONE if task is successfully launched
      *                - DEVICE_UNAVAILABLE if driver is offline or busy
      *                - GENERAL_FAILURE if there is an unspecified error
      *                - INVALID_ARGUMENT if one of the input arguments is invalid, including
      *                                   fences in error states.
-     * @return syncFence The sync fence that will be triggered when the task is completed.
+     *                - MISSED_DEADLINE_* if the execution is aborted because it
+     *                  cannot be completed by the deadline
+     *                - RESOURCE_EXHAUSTED_* if the task was aborted by the
+     *                  driver
+     * @return syncFence The sync fence that will be signaled when the task is completed.
      *                   The sync fence will be set to error if a critical error,
      *                   e.g. hardware failure or kernel panic, occurs when doing execution.
      * @return callback The IFencedExecutionCallback can be used to query information like duration
      *                  and error status when the execution is completed.
      */
-    executeFenced(Request request, vec<handle> waitFor, MeasureTiming measure)
+    executeFenced(Request request, vec<handle> waitFor, MeasureTiming measure,
+                  OptionalTimePoint deadline, OptionalTimeoutDuration loopTimeoutDuration,
+                  OptionalTimeoutDuration duration)
         generates (ErrorStatus status, handle syncFence, IFencedExecutionCallback callback);
 };
diff --git a/neuralnetworks/1.3/IPreparedModelCallback.hal b/neuralnetworks/1.3/IPreparedModelCallback.hal
index 11ebbf4..c0d3416 100644
--- a/neuralnetworks/1.3/IPreparedModelCallback.hal
+++ b/neuralnetworks/1.3/IPreparedModelCallback.hal
@@ -47,8 +47,8 @@
      *                 unspecified error
      *               - INVALID_ARGUMENT if one of the input arguments to
      *                 prepareModel is invalid
-     *               - MISSED_DEADLINE_* if the deadline for executing a model
-     *                 cannot be met
+     *               - MISSED_DEADLINE_* if the preparation is aborted because
+     *                 the model cannot be prepared by the deadline
      *               - RESOURCE_EXHAUSTED_* if the task was aborted by the
      *                 driver
      * @param preparedModel A model that has been asynchronously prepared for
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index abc33e7..08d8e6b 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -22,9 +22,9 @@
 import @1.0::RequestArgument;
 import @1.2::Model.ExtensionNameAndPrefix;
 import @1.2::Model.ExtensionTypeEncoding;
+import @1.2::Operand.ExtraParams;
 import @1.2::OperandType;
 import @1.2::OperationType;
-import @1.2::SymmPerChannelQuantParams;
 
 import android.hidl.safe_union@1.0::Monostate;
 
@@ -2364,7 +2364,54 @@
     AXIS_ALIGNED_BBOX_TRANSFORM = @1.2::OperationType:AXIS_ALIGNED_BBOX_TRANSFORM,
 
     /**
-     * Performs a forward LSTM on the input followed by a backward LSTM.
+     * A recurrent neural network layer that applies an LSTM cell to a
+     * sequence of inputs in forward and backward directions.
+     *
+     * The op supports cross-linking via an auxiliary input. Regular cell feeds
+     * one input into the two RNN cells in the following way:
+     *
+     *       INPUT  (INPUT_REVERSED)
+     *         |         |
+     *    ---------------------
+     *    | FW_LSTM   BW_LSTM |
+     *    ---------------------
+     *         |         |
+     *      FW_OUT     BW_OUT
+     *
+     * An op with cross-linking takes two inputs and feeds them into the RNN
+     * cells in the following way:
+     *
+     *       AUX_INPUT   (AUX_INPUT_REVERSED)
+     *           |             |
+     *     INPUT | (INPUT_R'D.)|
+     *       |   |       |     |
+     *    -----------------------
+     *    |  \  /        \    / |
+     *    | FW_LSTM     BW_LSTM |
+     *    -----------------------
+     *         |           |
+     *      FW_OUT      BW_OUT
+     *
+     * The cross-linking mode is enabled iff auxiliary input and auxiliary
+     * weights are present. While stacking this op on top of itself, this
+     * allows to connect both forward and backward outputs from previous cell
+     * to the next cell's input.
+     *
+     * Since HAL version 1.3 parallel linking mode is supported. The mode is
+     * enabled if auxiliary input is present but auxiliary weights are omitted.
+     * In this case, the cell feeds inputs into the RNN in the following way:
+     *
+     *       INPUT (AUX_INPUT_REVERSED)
+     *         |         |
+     *    ---------------------
+     *    | FW_LSTM   BW_LSTM |
+     *    ---------------------
+     *         |         |
+     *      FW_OUT     BW_OUT
+     *
+     * While stacking this op on top of itself, this allows to connect both
+     * forward and backward outputs from previous cell to the next cell's
+     * corresponding inputs.
      *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16}
@@ -2374,7 +2421,6 @@
      *
      * All input and output tensors must be of the same type.
      *
-     *
      * Inputs:
      * * 0: The input.
      *      A 3-D tensor of shape:
@@ -2466,25 +2512,34 @@
      * * 38: The backward input cell state.
      *       A 2-D tensor of shape [batch_size, bw_num_units].
      * * 39: The auxiliary input. Optional.
-     *       A 3-D tensor of shape [max_time, batch_size, input_size], where “batch_size”
-     *       corresponds to the batching dimension, and “input_size” is the size
-     *       of the input.
-     * * 40: The forward auxiliary input-to-input weights. Optional.
-     *       A 2-D tensor of shape [fw_num_units, input_size].
-     * * 41: The forward auxiliary input-to-forget weights. Optional.
-     *       A 2-D tensor of shape [fw_num_units, input_size].
-     * * 42: The forward auxiliary input-to-cell weights. Optional.
-     *       A 2-D tensor of shape [fw_num_units, input_size].
-     * * 43: The forward auxiliary input-to-output weights. Optional.
-     *       A 2-D tensor of shape [fw_num_units, input_size].
-     * * 44: The backward auxiliary input-to-input weights. Optional.
-     *       A 2-D tensor of shape [bw_num_units, input_size].
-     * * 45: The backward auxiliary input-to-forget weights. Optional.
-     *       A 2-D tensor of shape [bw_num_units, input_size].
-     * * 46: The backward auxiliary input-to-cell weights. Optional.
-     *       A 2-D tensor of shape [bw_num_units, input_size].
-     * * 47: The backward auxiliary input-to-output weights. Optional.
-     *       A 2-D tensor of shape [bw_num_units, input_size].
+     *       A 3-D tensor of shape [max_time, batch_size, aux_input_size],
+     *       where “batch_size” corresponds to the batching dimension, and
+     *       “aux_input_size” is the size of the auxiliary input. Optional. See
+     *       the docs above for the usage modes explanation.
+     * * 40: The forward auxiliary input-to-input weights.
+     *       Optional. See the docs above for the usage modes explanation.
+     *       A 2-D tensor of shape [fw_num_units, aux_input_size].
+     * * 41: The forward auxiliary input-to-forget weights.
+     *       Optional. See the docs above for the usage modes explanation.
+     *       A 2-D tensor of shape [fw_num_units, aux_input_size].
+     * * 42: The forward auxiliary input-to-cell weights.
+     *       Optional. See the docs above for the usage modes explanation.
+     *       A 2-D tensor of shape [fw_num_units, aux_input_size].
+     * * 43: The forward auxiliary input-to-output weights.
+     *       Optional. See the docs above for the usage modes explanation.
+     *       A 2-D tensor of shape [fw_num_units, aux_input_size].
+     * * 44: The backward auxiliary input-to-input weights.
+     *       Optional. See the docs above for the usage modes explanation.
+     *       A 2-D tensor of shape [bw_num_units, aux_input_size].
+     * * 45: The backward auxiliary input-to-forget weights.
+     *       Optional. See the docs above for the usage modes explanation.
+     *       A 2-D tensor of shape [bw_num_units, aux_input_size].
+     * * 46: The backward auxiliary input-to-cell weights.
+     *       Optional. See the docs above for the usage modes explanation.
+     *       A 2-D tensor of shape [bw_num_units, aux_input_size].
+     * * 47: The backward auxiliary input-to-output weights.
+     *       Optional. See the docs above for the usage modes explanation.
+     *       A 2-D tensor of shape [bw_num_units, aux_input_size].
      * * 48: The activation function.
      *       A value indicating the activation function:
      *       <ul>
@@ -2556,6 +2611,30 @@
      *      A 3-D tensor of shape:
      *        If time-major: [max_time, batch_size, bw_output_size]
      *        If batch-major: [batch_size, max_time, bw_output_size]
+     * * 2: The forward activation state output.
+     *      A 2-D tensor of shape [batch_size, fw_output_size] containing an
+     *      activation state from the last time step in the sequence. This
+     *      output is optional and can be omitted. If this output is present
+     *      then outputs 3-5 must be present as well.
+     *      Available since HAL version 1.3.
+     * * 3: The forward cell state output.
+     *      A tensor of shape [batch_size, fw_cell_size] containing a cell state
+     *      from the last time step in the sequence. This output is optional
+     *      and can be omitted. If this output is present
+     *      then outputs 2, 4, 5 must be present as well.
+     *      Available since HAL version 1.3.
+     * * 4: The backward activation state output.
+     *      A 2-D tensor of shape [batch_size, bw_output_size] containing an
+     *      activation state from the last time step in the sequence. This
+     *      output is optional and can be omitted. If this output is present
+     *      then outputs 2, 3, 5 must be present as well.
+     *      Available since HAL version 1.3.
+     * * 5: The backward cell state output.
+     *      A tensor of shape [batch_size, bw_cell_size] containing a cell state
+     *      from the last time step in the sequence. This output is optional
+     *      and can be omitted. If this output is present
+     *      then outputs 2-4 must be present as well.
+     *      Available since HAL version 1.3.
      */
     BIDIRECTIONAL_SEQUENCE_LSTM = @1.2::OperationType:BIDIRECTIONAL_SEQUENCE_LSTM,
 
@@ -2583,8 +2662,8 @@
      * * “activation” is the function passed as the “fused_activation_function”
      *   argument (if not “NONE”).
      *
-     * The op also supports an auxiliary input. Regular cell feeds one input
-     * into the two RNN cells in the following way:
+     * The op supports cross-linking via an auxiliary input. Regular cell feeds
+     * one input into the two RNN cells in the following way:
      *
      *       INPUT  (INPUT_REVERSED)
      *         |         |
@@ -2594,8 +2673,8 @@
      *         |         |
      *      FW_OUT     BW_OUT
      *
-     * An op with an auxiliary input takes two inputs and feeds them into the
-     * RNN cells in the following way:
+     * An op with cross-linking takes two inputs and feeds them into the RNN
+     * cells in the following way:
      *
      *       AUX_INPUT   (AUX_INPUT_REVERSED)
      *           |             |
@@ -2608,9 +2687,26 @@
      *         |           |
      *      FW_OUT      BW_OUT
      *
+     * The cross-linking mode is enabled iff auxiliary input and auxiliary
+     * weights are present. While stacking this op on top of itself, this
+     * allows to connect both forward and backward outputs from previous cell
+     * to the next cell's input.
+     *
+     * Since HAL version 1.3 parallel linking mode is supported. The mode is
+     * enabled if auxiliary input is present but auxiliary weights are omitted.
+     * In this case, the cell feeds inputs into the RNN in the following way:
+     *
+     *       INPUT (AUX_INPUT_REVERSED)
+     *         |         |
+     *    ---------------------
+     *    | FW_RNN     BW_RNN |
+     *    ---------------------
+     *         |         |
+     *      FW_OUT     BW_OUT
+     *
      * While stacking this op on top of itself, this allows to connect both
      * forward and backward outputs from previous cell to the next cell's
-     * inputs.
+     * corresponding inputs.
      *
      * Supported tensor {@link OperandType}:
      * * {@link OperandType::TENSOR_FLOAT16}
@@ -2643,11 +2739,17 @@
      *      A 2-D tensor of shape [batchSize, bwNumUnits]. Specifies a hidden
      *      state input for the first time step of the computation.
      * * 9: auxInput.
-     *      A 3-D tensor. The shape is the same as of the input 0.
+     *      A 3-D tensor. The shape is defined by the input 6 (timeMajor). If
+     *      it is set to true, then the input has a shape [maxTime, batchSize,
+     *      auxInputSize], otherwise the input has a shape [batchSize, maxTime,
+     *      auxInputSize]. Can be omitted. See the docs above for the usage
+     *      modes explanation.
      * * 10:fwAuxWeights.
-     *      A 2-D tensor of shape [fwNumUnits, inputSize].
+     *      A 2-D tensor of shape [fwNumUnits, auxInputSize]. Can be omitted.
+     *      See the docs above for the usage modes explanation.
      * * 11:bwAuxWeights.
-     *      A 2-D tensor of shape [bwNumUnits, inputSize].
+     *      A 2-D tensor of shape [bwNumUnits, auxInputSize]. Can be omitted.
+     *      See the docs above for the usage modes explanation.
      * * 12:fusedActivationFunction.
      *      A {@link FusedActivationFunc} value indicating the activation function. If
      *      “NONE” is specified then it results in a linear activation.
@@ -2673,6 +2775,18 @@
      *      (timeMajor). If it is set to true, then the shape is set to
      *      [maxTime, batchSize, bwNumUnits], otherwise the shape is set to
      *      [batchSize, maxTime, bwNumUnits].
+     * * 2: The forward hidden state output.
+     *      A 2-D tensor of shape [batchSize, fwNumUnits] containing a hidden
+     *      state from the last time step in the sequence. This output is
+     *      optional and can be omitted. If this output is present then output
+     *      3 must be present as well.
+     *      Available since HAL version 1.3.
+     * * 3: The backward hidden state output.
+     *      A 2-D tensor of shape [batchSize, bwNumUnits] containing a hidden
+     *      state from the last time step in the sequence. This output is
+     *      optional and can be omitted. If this output is present then output
+     *      2 must be present as well.
+     *      Available since HAL version 1.3.
      */
     BIDIRECTIONAL_SEQUENCE_RNN = @1.2::OperationType:BIDIRECTIONAL_SEQUENCE_RNN,
 
@@ -3253,7 +3367,7 @@
      * * 8: An {@link OperandType::INT32} scalar, specifying the stride when
      *      walking through input in the ‘height’ dimension.
      * * 9: An {@link OperandType::INT32} scalar, specifying the number of
-            groups.
+     *      groups.
      * * 10: An {@link OperandType::INT32} scalar, and has to be one of the
      *       {@link FusedActivationFunc} values. Specifies the activation to
      *       invoke on the result.
@@ -4656,6 +4770,15 @@
      *      A 3-D tensor of shape:
      *        If time-major: [max_time, batch_size, output_size]
      *        If batch-major: [batch_size, max_time, output_size]
+     * * 1: A tensor of shape [batch_size, output_size] containing a hidden
+     *      state from the last time step in the sequence. This output is
+     *      optional and can be omitted. If this output is present then
+     *      output #2 must be present as well.
+     *      Available since HAL version 1.3.
+     * * 2: A tensor of shape [batch_size, cell_size] containing a cell state
+     *      from the last time step in the sequence. This output is optional
+     *      and can be omitted.
+     *      Available since HAL version 1.3.
      */
     UNIDIRECTIONAL_SEQUENCE_LSTM = @1.2::OperationType:UNIDIRECTIONAL_SEQUENCE_LSTM,
 
@@ -4711,6 +4834,10 @@
      *      it is set to 1, then the output has a shape [maxTime, batchSize,
      *      numUnits], otherwise the output has a shape [batchSize, maxTime,
      *      numUnits].
+     * * 1: A tensor of shape [batchSize, numUnits] containing hidden state
+     *      from the last time step in the sequence. This output is optional
+     *      and can be omitted.
+     *      Available since HAL version 1.3.
      */
     UNIDIRECTIONAL_SEQUENCE_RNN = @1.2::OperationType:UNIDIRECTIONAL_SEQUENCE_RNN,
 
@@ -5127,8 +5254,10 @@
 /**
  * The capabilities of a driver.
  *
- * Performance of an operation comes from the type of its first operand.
- * This represents performance for non extension operand types.
+ * This represents performance of non-extension operations.
+ *
+ * Performance of an operation other than {@link OperationType::IF} and
+ * {@link OperationType::WHILE} comes from the type of its first operand.
  */
 struct Capabilities {
     /**
@@ -5151,11 +5280,32 @@
 
     /**
      * Performance by operand type. Must be sorted by OperandType.
-     * If a particular OperandType is not present in operandPerformance,
+     *
+     * If a particular {@link OperandType} is not present in operandPerformance,
      * its performance is treated as
      * { .execTime = FLT_MAX, .powerUsage = FLT_MAX }.
+     *
+     * Performance does not apply to {@link OperandType::SUBGRAPH}, and a driver
+     * must not report operand performance for {@link OperandType::SUBGRAPH}.
      */
     vec<OperandPerformance> operandPerformance;
+
+    /**
+     * Performance of an {@link OperationType::IF} operation is the sum of
+     * {@link Capabilities::ifPerformance} and the mean of performance for the
+     * two branch subgraphs, where performance for a subgraph is the sum of the
+     * performance of all operations within the subgraph.
+     */
+    PerformanceInfo ifPerformance;
+
+    /**
+     * Performance of a {@link OperationType::WHILE} operation is the sum of
+     * {@link Capabilities::whilePerformance}, performance for the condition
+     * subgraph and performance for the body subgraph, where performance for a
+     * subgraph is the sum of the performance of all operations within the
+     * subgraph.
+     */
+    PerformanceInfo whilePerformance;
 };
 
 /**
@@ -5343,27 +5493,7 @@
     /**
      * Additional parameters specific to a particular operand type.
      */
-    safe_union ExtraParams {
-       /**
-        * No additional parameters.
-        */
-       Monostate none;
-
-       /**
-        * Symmetric per-channel quantization parameters.
-        *
-        * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL.
-        */
-       SymmPerChannelQuantParams channelQuant;
-
-       /**
-        * Extension operand parameters.
-        *
-        * The framework treats this as an opaque data blob.
-        * The format is up to individual extensions.
-        */
-       vec<uint8_t> extension;
-    } extraParams;
+    @1.2::Operand.ExtraParams extraParams;
 };
 
 /**
@@ -5551,7 +5681,7 @@
          * Specifies a driver-managed buffer. It is the token returned from IDevice::allocate,
          * and is specific to the IDevice object.
          */
-        int32_t token;
+        uint32_t token;
     };
 
     /**
@@ -5573,6 +5703,19 @@
      * Time point of the steady clock (as from std::chrono::steady_clock)
      * measured in nanoseconds.
      */
+    uint64_t nanosecondsSinceEpoch;
+};
+
+/**
+ * Optional timeout duration measured in nanoseconds.
+ */
+safe_union OptionalTimeoutDuration {
+    /** No time point provided. */
+    Monostate none;
+
+    /**
+     * Timeout duration measured in nanoseconds.
+     */
     uint64_t nanoseconds;
 };
 
@@ -5606,3 +5749,14 @@
      */
     RESOURCE_EXHAUSTED_PERSISTENT,
 };
+
+/**
+ * Each {@link OperationType::WHILE} operation in the model has an implicit
+ * execution timeout duration associated with it ("loop timeout duration").
+ * This duration is configurable on a per-execution basis and must not exceed
+ * 15 seconds. The default value is 2 seconds.
+ */
+enum LoopTimeoutDurationNs : uint64_t {
+    DEFAULT = 2000000000,
+    MAXIMUM = 15000000000,
+};
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
index a973923..0a6e45e 100644
--- a/neuralnetworks/1.3/types.t
+++ b/neuralnetworks/1.3/types.t
@@ -24,9 +24,9 @@
 import @1.0::RequestArgument;
 import @1.2::Model.ExtensionNameAndPrefix;
 import @1.2::Model.ExtensionTypeEncoding;
+import @1.2::Operand.ExtraParams;
 import @1.2::OperandType;
 import @1.2::OperationType;
-import @1.2::SymmPerChannelQuantParams;
 
 import android.hidl.safe_union@1.0::Monostate;
 
@@ -103,8 +103,10 @@
 /**
  * The capabilities of a driver.
  *
- * Performance of an operation comes from the type of its first operand.
- * This represents performance for non extension operand types.
+ * This represents performance of non-extension operations.
+ *
+ * Performance of an operation other than {@link OperationType::IF} and
+ * {@link OperationType::WHILE} comes from the type of its first operand.
  */
 struct Capabilities {
     /**
@@ -127,11 +129,32 @@
 
     /**
      * Performance by operand type. Must be sorted by OperandType.
-     * If a particular OperandType is not present in operandPerformance,
+     *
+     * If a particular {@link OperandType} is not present in operandPerformance,
      * its performance is treated as
      * { .execTime = FLT_MAX, .powerUsage = FLT_MAX }.
+     *
+     * Performance does not apply to {@link OperandType::SUBGRAPH}, and a driver
+     * must not report operand performance for {@link OperandType::SUBGRAPH}.
      */
     vec<OperandPerformance> operandPerformance;
+
+    /**
+     * Performance of an {@link OperationType::IF} operation is the sum of
+     * {@link Capabilities::ifPerformance} and the mean of performance for the
+     * two branch subgraphs, where performance for a subgraph is the sum of the
+     * performance of all operations within the subgraph.
+     */
+    PerformanceInfo ifPerformance;
+
+    /**
+     * Performance of a {@link OperationType::WHILE} operation is the sum of
+     * {@link Capabilities::whilePerformance}, performance for the condition
+     * subgraph and performance for the body subgraph, where performance for a
+     * subgraph is the sum of the performance of all operations within the
+     * subgraph.
+     */
+    PerformanceInfo whilePerformance;
 };
 
 /**
@@ -319,27 +342,7 @@
     /**
      * Additional parameters specific to a particular operand type.
      */
-    safe_union ExtraParams {
-       /**
-        * No additional parameters.
-        */
-       Monostate none;
-
-       /**
-        * Symmetric per-channel quantization parameters.
-        *
-        * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL.
-        */
-       SymmPerChannelQuantParams channelQuant;
-
-       /**
-        * Extension operand parameters.
-        *
-        * The framework treats this as an opaque data blob.
-        * The format is up to individual extensions.
-        */
-       vec<uint8_t> extension;
-    } extraParams;
+    @1.2::Operand.ExtraParams extraParams;
 };
 
 /**
@@ -527,7 +530,7 @@
          * Specifies a driver-managed buffer. It is the token returned from IDevice::allocate,
          * and is specific to the IDevice object.
          */
-        int32_t token;
+        uint32_t token;
     };
 
     /**
@@ -549,6 +552,19 @@
      * Time point of the steady clock (as from std::chrono::steady_clock)
      * measured in nanoseconds.
      */
+    uint64_t nanosecondsSinceEpoch;
+};
+
+/**
+ * Optional timeout duration measured in nanoseconds.
+ */
+safe_union OptionalTimeoutDuration {
+    /** No time point provided. */
+    Monostate none;
+
+    /**
+     * Timeout duration measured in nanoseconds.
+     */
     uint64_t nanoseconds;
 };
 
@@ -582,3 +598,14 @@
      */
     RESOURCE_EXHAUSTED_PERSISTENT,
 };
+
+/**
+ * Each {@link OperationType::WHILE} operation in the model has an implicit
+ * execution timeout duration associated with it ("loop timeout duration").
+ * This duration is configurable on a per-execution basis and must not exceed
+ * 15 seconds. The default value is 2 seconds.
+ */
+enum LoopTimeoutDurationNs : uint64_t {
+    DEFAULT = 2000000000,
+    MAXIMUM = 15000000000,
+};
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index 8e7e9b9..f936267 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -16,7 +16,7 @@
 
 cc_library_static {
     name: "VtsHalNeuralNetworksV1_3_utils",
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: ["neuralnetworks_vts_functional_defaults"],
     export_include_dirs: ["include"],
     srcs: [
         "Callbacks.cpp",
@@ -35,7 +35,7 @@
 
 cc_test {
     name: "VtsHalNeuralnetworksV1_3TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: ["neuralnetworks_vts_functional_defaults"],
     srcs: [
         "BasicTests.cpp",
         "CompilationCachingTests.cpp",
diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp
index 891850c..1c25369 100644
--- a/neuralnetworks/1.3/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp
@@ -57,6 +57,11 @@
                                    [](const OperandPerformance& a, const OperandPerformance& b) {
                                        return a.type < b.type;
                                    }));
+        EXPECT_TRUE(std::all_of(opPerf.begin(), opPerf.end(), [](const OperandPerformance& a) {
+            return a.type != OperandType::SUBGRAPH;
+        }));
+        EXPECT_TRUE(isPositive(capabilities.ifPerformance));
+        EXPECT_TRUE(isPositive(capabilities.whilePerformance));
     });
     EXPECT_TRUE(ret.isOk());
 }
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index 576e524..ac18c8f 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -209,10 +209,10 @@
     };
 
     return {
-            .operands = std::move(operands),
-            .operations = std::move(operations),
-            .inputIndexes = {1},
-            .outputIndexes = {len * 2 + 1},
+            .main = {.operands = std::move(operands),
+                     .operations = std::move(operations),
+                     .inputIndexes = {1},
+                     .outputIndexes = {len * 2 + 1}},
             .isRelaxed = false,
     };
 }
@@ -370,7 +370,7 @@
         sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
         hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken);
         Return<ErrorStatus> prepareLaunchStatus = kDevice->prepareModelFromCache_1_3(
-                kDefaultPriority, {}, modelCache, dataCache, cacheToken, preparedModelCallback);
+                {}, modelCache, dataCache, cacheToken, preparedModelCallback);
         ASSERT_TRUE(prepareLaunchStatus.isOk());
         if (static_cast<ErrorStatus>(prepareLaunchStatus) != ErrorStatus::NONE) {
             *preparedModel = nullptr;
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 88837db..8c9393b 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -74,12 +74,19 @@
 
 enum class Executor { ASYNC, SYNC, BURST, FENCED };
 
-enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
+enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT, MISSED_DEADLINE };
 
 enum class MemoryType { SHARED, DEVICE };
 
 enum class IOType { INPUT, OUTPUT };
 
+static void waitForSyncFence(int syncFd) {
+    constexpr int kInfiniteTimeout = -1;
+    ASSERT_GT(syncFd, 0);
+    int r = sync_wait(syncFd, kInfiniteTimeout);
+    ASSERT_GE(r, 0);
+}
+
 struct TestConfig {
     Executor executor;
     MeasureTiming measureTiming;
@@ -115,15 +122,15 @@
     // Return {IBuffer object, token} if successful.
     // Return {nullptr, 0} if device memory is not supported.
     template <IOType ioType>
-    std::pair<sp<IBuffer>, int32_t> allocate(uint32_t index) {
-        std::pair<sp<IBuffer>, int32_t> buffer;
+    std::pair<sp<IBuffer>, uint32_t> allocate(uint32_t index) {
+        std::pair<sp<IBuffer>, uint32_t> buffer;
         allocateInternal<ioType>(index, &buffer);
         return buffer;
     }
 
   private:
     template <IOType ioType>
-    void allocateInternal(uint32_t index, std::pair<sp<IBuffer>, int32_t>* result) {
+    void allocateInternal(uint32_t index, std::pair<sp<IBuffer>, uint32_t>* result) {
         ASSERT_NE(result, nullptr);
 
         // Prepare arguments.
@@ -138,14 +145,14 @@
         // Allocate device memory.
         ErrorStatus status;
         sp<IBuffer> buffer;
-        int32_t token;
-        const auto ret = kDevice->allocate(
-                {}, {kPreparedModel}, inputRoles, outputRoles,
-                [&status, &buffer, &token](ErrorStatus error, const sp<IBuffer>& buf, int32_t tok) {
-                    status = error;
-                    buffer = buf;
-                    token = tok;
-                });
+        uint32_t token;
+        auto cb = [&status, &buffer, &token](ErrorStatus error, const sp<IBuffer>& buf,
+                                             uint32_t tok) {
+            status = error;
+            buffer = buf;
+            token = tok;
+        };
+        const auto ret = kDevice->allocate({}, {kPreparedModel}, inputRoles, outputRoles, cb);
 
         // Check allocation results.
         ASSERT_TRUE(ret.isOk());
@@ -162,7 +169,8 @@
         if constexpr (ioType == IOType::INPUT) {
             if (buffer != nullptr) {
                 // TestBuffer -> Shared memory.
-                const auto& testBuffer = kTestModel.operands[kTestModel.inputIndexes[index]].data;
+                const auto& testBuffer =
+                        kTestModel.main.operands[kTestModel.main.inputIndexes[index]].data;
                 ASSERT_GT(testBuffer.size(), 0);
                 hidl_memory tmp = nn::allocateSharedMemory(testBuffer.size());
                 sp<IMemory> inputMemory = mapMemory(tmp);
@@ -188,29 +196,45 @@
     const TestModel& kTestModel;
 };
 
-}  // namespace
+Subgraph createSubgraph(const TestSubgraph& testSubgraph, uint32_t* constCopySize,
+                        std::vector<const TestBuffer*>* constCopies, uint32_t* constRefSize,
+                        std::vector<const TestBuffer*>* constReferences) {
+    CHECK(constCopySize != nullptr);
+    CHECK(constCopies != nullptr);
+    CHECK(constRefSize != nullptr);
+    CHECK(constReferences != nullptr);
 
-Model createModel(const TestModel& testModel) {
-    // Model operands.
-    hidl_vec<Operand> operands(testModel.operands.size());
-    size_t constCopySize = 0, constRefSize = 0;
-    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-        const auto& op = testModel.operands[i];
+    // Operands.
+    hidl_vec<Operand> operands(testSubgraph.operands.size());
+    for (uint32_t i = 0; i < testSubgraph.operands.size(); i++) {
+        const auto& op = testSubgraph.operands[i];
 
         DataLocation loc = {};
         if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
-            loc = {.poolIndex = 0,
-                   .offset = static_cast<uint32_t>(constCopySize),
-                   .length = static_cast<uint32_t>(op.data.size())};
-            constCopySize += op.data.alignedSize();
+            loc = {
+                    .poolIndex = 0,
+                    .offset = *constCopySize,
+                    .length = static_cast<uint32_t>(op.data.size()),
+            };
+            constCopies->push_back(&op.data);
+            *constCopySize += op.data.alignedSize();
         } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
-            loc = {.poolIndex = 0,
-                   .offset = static_cast<uint32_t>(constRefSize),
-                   .length = static_cast<uint32_t>(op.data.size())};
-            constRefSize += op.data.alignedSize();
+            loc = {
+                    .poolIndex = 0,
+                    .offset = *constRefSize,
+                    .length = static_cast<uint32_t>(op.data.size()),
+            };
+            constReferences->push_back(&op.data);
+            *constRefSize += op.data.alignedSize();
+        } else if (op.lifetime == TestOperandLifeTime::SUBGRAPH) {
+            loc = {
+                    .poolIndex = 0,
+                    .offset = *op.data.get<uint32_t>(),
+                    .length = 0,
+            };
         }
 
-        Operand::ExtraParams extraParams;
+        V1_2::Operand::ExtraParams extraParams;
         if (op.type == TestOperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) {
             extraParams.channelQuant(SymmPerChannelQuantParams{
                     .scales = op.channelQuant.scales, .channelDim = op.channelQuant.channelDim});
@@ -226,25 +250,52 @@
                        .extraParams = std::move(extraParams)};
     }
 
-    // Model operations.
-    hidl_vec<Operation> operations(testModel.operations.size());
-    std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
-                   [](const TestOperation& op) -> Operation {
+    // Operations.
+    hidl_vec<Operation> operations(testSubgraph.operations.size());
+    std::transform(testSubgraph.operations.begin(), testSubgraph.operations.end(),
+                   operations.begin(), [](const TestOperation& op) -> Operation {
                        return {.type = static_cast<OperationType>(op.type),
                                .inputs = op.inputs,
                                .outputs = op.outputs};
                    });
 
+    return {.operands = std::move(operands),
+            .operations = std::move(operations),
+            .inputIndexes = testSubgraph.inputIndexes,
+            .outputIndexes = testSubgraph.outputIndexes};
+}
+
+void copyTestBuffers(const std::vector<const TestBuffer*>& buffers, uint8_t* output) {
+    uint32_t offset = 0;
+    for (const TestBuffer* buffer : buffers) {
+        const uint8_t* begin = buffer->get<uint8_t>();
+        const uint8_t* end = begin + buffer->size();
+        std::copy(begin, end, output + offset);
+        offset += buffer->alignedSize();
+    }
+}
+
+}  // namespace
+
+Model createModel(const TestModel& testModel) {
+    uint32_t constCopySize = 0;
+    uint32_t constRefSize = 0;
+    std::vector<const TestBuffer*> constCopies;
+    std::vector<const TestBuffer*> constReferences;
+
+    Subgraph mainSubgraph = createSubgraph(testModel.main, &constCopySize, &constCopies,
+                                           &constRefSize, &constReferences);
+    hidl_vec<Subgraph> refSubgraphs(testModel.referenced.size());
+    std::transform(testModel.referenced.begin(), testModel.referenced.end(), refSubgraphs.begin(),
+                   [&constCopySize, &constCopies, &constRefSize,
+                    &constReferences](const TestSubgraph& testSubgraph) {
+                       return createSubgraph(testSubgraph, &constCopySize, &constCopies,
+                                             &constRefSize, &constReferences);
+                   });
+
     // Constant copies.
     hidl_vec<uint8_t> operandValues(constCopySize);
-    for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-        const auto& op = testModel.operands[i];
-        if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
-            const uint8_t* begin = op.data.get<uint8_t>();
-            const uint8_t* end = begin + op.data.size();
-            std::copy(begin, end, operandValues.data() + operands[i].location.offset);
-        }
-    }
+    copyTestBuffers(constCopies, operandValues.data());
 
     // Shared memory.
     hidl_vec<hidl_memory> pools = {};
@@ -259,27 +310,18 @@
                 reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
         CHECK(mappedPtr != nullptr);
 
-        for (uint32_t i = 0; i < testModel.operands.size(); i++) {
-            const auto& op = testModel.operands[i];
-            if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
-                const uint8_t* begin = op.data.get<uint8_t>();
-                const uint8_t* end = begin + op.data.size();
-                std::copy(begin, end, mappedPtr + operands[i].location.offset);
-            }
-        }
+        copyTestBuffers(constReferences, mappedPtr);
     }
 
-    return {.main = {.operands = std::move(operands),
-                     .operations = std::move(operations),
-                     .inputIndexes = testModel.inputIndexes,
-                     .outputIndexes = testModel.outputIndexes},
+    return {.main = std::move(mainSubgraph),
+            .referenced = std::move(refSubgraphs),
             .operandValues = std::move(operandValues),
             .pools = std::move(pools),
             .relaxComputationFloat32toFloat16 = testModel.isRelaxed};
 }
 
 static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) {
-    const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size();
+    const auto byteSize = testModel.main.operands[testModel.main.outputIndexes[index]].data.size();
     return byteSize > 1u;
 }
 
@@ -310,13 +352,13 @@
     // - [2+i, 2+i+o): Output device memories
     DeviceMemoryAllocator allocator(device, preparedModel, testModel);
     std::vector<sp<IBuffer>> buffers;
-    std::vector<int32_t> tokens;
+    std::vector<uint32_t> tokens;
 
     // Model inputs.
-    hidl_vec<RequestArgument> inputs(testModel.inputIndexes.size());
+    hidl_vec<RequestArgument> inputs(testModel.main.inputIndexes.size());
     size_t inputSize = 0;
-    for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
-        const auto& op = testModel.operands[testModel.inputIndexes[i]];
+    for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
+        const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
         if (op.data.size() == 0) {
             // Omitted input.
             inputs[i] = {.hasNoValue = true};
@@ -343,10 +385,10 @@
     }
 
     // Model outputs.
-    hidl_vec<RequestArgument> outputs(testModel.outputIndexes.size());
+    hidl_vec<RequestArgument> outputs(testModel.main.outputIndexes.size());
     size_t outputSize = 0;
-    for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) {
-        const auto& op = testModel.operands[testModel.outputIndexes[i]];
+    for (uint32_t i = 0; i < testModel.main.outputIndexes.size(); i++) {
+        const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
         if (preferDeviceMemory) {
             SCOPED_TRACE("Output index = " + std::to_string(i));
             auto [buffer, token] = allocator.allocate<IOType::OUTPUT>(i);
@@ -391,9 +433,9 @@
     CHECK(inputMemory.get() != nullptr);
     uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
     CHECK(inputPtr != nullptr);
-    for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
+    for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
         if (!inputs[i].hasNoValue && inputs[i].location.poolIndex == kInputPoolIndex) {
-            const auto& op = testModel.operands[testModel.inputIndexes[i]];
+            const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
             const uint8_t* begin = op.data.get<uint8_t>();
             const uint8_t* end = begin + op.data.size();
             std::copy(begin, end, inputPtr + inputs[i].location.offset);
@@ -436,7 +478,7 @@
         if (outputLoc.poolIndex == kOutputPoolIndex) {
             outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset);
         } else {
-            const auto& op = testModel.operands[testModel.outputIndexes[i]];
+            const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
             if (op.data.size() == 0) {
                 outputBuffers.emplace_back();
             } else {
@@ -453,16 +495,18 @@
 
 static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
                                                 const Request& request, MeasureTiming measure,
+                                                const OptionalTimeoutDuration& loopTimeoutDuration,
                                                 sp<ExecutionCallback>& callback) {
-    return preparedModel->execute_1_3(request, measure, {}, callback);
+    return preparedModel->execute_1_3(request, measure, {}, loopTimeoutDuration, callback);
 }
 static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
                                                 const Request& request, MeasureTiming measure,
+                                                const OptionalTimeoutDuration& loopTimeoutDuration,
                                                 hidl_vec<OutputShape>* outputShapes,
                                                 Timing* timing) {
     ErrorStatus result;
     Return<void> ret = preparedModel->executeSynchronously_1_3(
-            request, measure, {},
+            request, measure, {}, loopTimeoutDuration,
             [&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
                                             const Timing& time) {
                 result = error;
@@ -503,6 +547,17 @@
         makeOutputInsufficientSize(/*outputIndex=*/0, &request);
     }
 
+    OptionalTimeoutDuration loopTimeoutDuration;
+    // OutputType::MISSED_DEADLINE is only used by
+    // TestKind::INTINITE_LOOP_TIMEOUT tests to verify that an infinite loop is
+    // aborted after a timeout.
+    if (testConfig.outputType == OutputType::MISSED_DEADLINE) {
+        // Override the default loop timeout duration with a small value to
+        // speed up test execution.
+        constexpr uint64_t kMillisecond = 1'000'000;
+        loopTimeoutDuration.nanoseconds(1 * kMillisecond);
+    }
+
     ErrorStatus executionStatus;
     hidl_vec<OutputShape> outputShapes;
     Timing timing;
@@ -512,8 +567,9 @@
 
             // launch execution
             sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-            Return<ErrorStatus> executionLaunchStatus = ExecutePreparedModel(
-                    preparedModel, request, testConfig.measureTiming, executionCallback);
+            Return<ErrorStatus> executionLaunchStatus =
+                    ExecutePreparedModel(preparedModel, request, testConfig.measureTiming,
+                                         loopTimeoutDuration, executionCallback);
             ASSERT_TRUE(executionLaunchStatus.isOk());
             EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
 
@@ -529,8 +585,9 @@
             SCOPED_TRACE("synchronous");
 
             // execute
-            Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
-                    preparedModel, request, testConfig.measureTiming, &outputShapes, &timing);
+            Return<ErrorStatus> executionReturnStatus =
+                    ExecutePreparedModel(preparedModel, request, testConfig.measureTiming,
+                                         loopTimeoutDuration, &outputShapes, &timing);
             ASSERT_TRUE(executionReturnStatus.isOk());
             executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
 
@@ -567,33 +624,29 @@
         case Executor::FENCED: {
             SCOPED_TRACE("fenced");
             ErrorStatus result;
-            hidl_handle sync_fence_handle;
-            sp<IFencedExecutionCallback> fenced_callback;
+            hidl_handle syncFenceHandle;
+            sp<IFencedExecutionCallback> fencedCallback;
             Return<void> ret = preparedModel->executeFenced(
-                    request, {}, testConfig.measureTiming,
-                    [&result, &sync_fence_handle, &fenced_callback](
+                    request, {}, testConfig.measureTiming, {}, loopTimeoutDuration, {},
+                    [&result, &syncFenceHandle, &fencedCallback](
                             ErrorStatus error, const hidl_handle& handle,
                             const sp<IFencedExecutionCallback>& callback) {
                         result = error;
-                        sync_fence_handle = handle;
-                        fenced_callback = callback;
+                        syncFenceHandle = handle;
+                        fencedCallback = callback;
                     });
             ASSERT_TRUE(ret.isOk());
             if (result != ErrorStatus::NONE) {
-                ASSERT_EQ(sync_fence_handle.getNativeHandle(), nullptr);
-                ASSERT_EQ(fenced_callback, nullptr);
+                ASSERT_EQ(syncFenceHandle.getNativeHandle(), nullptr);
+                ASSERT_EQ(fencedCallback, nullptr);
                 executionStatus = ErrorStatus::GENERAL_FAILURE;
-            } else if (sync_fence_handle.getNativeHandle()) {
-                constexpr int kInfiniteTimeout = -1;
-                int sync_fd = sync_fence_handle.getNativeHandle()->data[0];
-                ASSERT_GT(sync_fd, 0);
-                int r = sync_wait(sync_fd, kInfiniteTimeout);
-                ASSERT_GE(r, 0);
+            } else if (syncFenceHandle.getNativeHandle()) {
+                waitForSyncFence(syncFenceHandle.getNativeHandle()->data[0]);
             }
             if (result == ErrorStatus::NONE) {
-                ASSERT_NE(fenced_callback, nullptr);
-                Return<void> ret = fenced_callback->getExecutionInfo(
-                        [&executionStatus, &timing](ErrorStatus error, Timing t) {
+                ASSERT_NE(fencedCallback, nullptr);
+                Return<void> ret = fencedCallback->getExecutionInfo(
+                        [&executionStatus, &timing](ErrorStatus error, Timing t, Timing) {
                             executionStatus = error;
                             timing = t;
                         });
@@ -635,25 +688,30 @@
             // either empty, or have the same number of elements as the number of outputs.
             ASSERT_EQ(ErrorStatus::NONE, executionStatus);
             ASSERT_TRUE(outputShapes.size() == 0 ||
-                        outputShapes.size() == testModel.outputIndexes.size());
+                        outputShapes.size() == testModel.main.outputIndexes.size());
             break;
         case OutputType::UNSPECIFIED:
             // If the model output operands are not fully specified, outputShapes must have
             // the same number of elements as the number of outputs.
             ASSERT_EQ(ErrorStatus::NONE, executionStatus);
-            ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
+            ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
             break;
         case OutputType::INSUFFICIENT:
             ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
-            ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
+            ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
             ASSERT_FALSE(outputShapes[0].isSufficient);
             return;
+        case OutputType::MISSED_DEADLINE:
+            ASSERT_TRUE(executionStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
+                        executionStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT)
+                    << "executionStatus = " << executionStatus;
+            return;
     }
 
     // Go through all outputs, check returned output shapes.
     for (uint32_t i = 0; i < outputShapes.size(); i++) {
         EXPECT_TRUE(outputShapes[i].isSufficient);
-        const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions;
+        const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
         const std::vector<uint32_t> actual = outputShapes[i].dimensions;
         EXPECT_EQ(expect, actual);
     }
@@ -698,6 +756,12 @@
             LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel";
             return;
         } break;
+        case TestKind::INTINITE_LOOP_TIMEOUT: {
+            outputTypesList = {OutputType::MISSED_DEADLINE};
+            measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+            // Burst does not support V1_3 loop timeout.
+            executorList = {Executor::ASYNC, Executor::SYNC, Executor::FENCED};
+        } break;
     }
 
     for (const OutputType outputType : outputTypesList) {
@@ -756,7 +820,8 @@
         case TestKind::GENERAL:
         case TestKind::DYNAMIC_SHAPE:
         case TestKind::MEMORY_DOMAIN:
-        case TestKind::FENCED_COMPUTE: {
+        case TestKind::FENCED_COMPUTE:
+        case TestKind::INTINITE_LOOP_TIMEOUT: {
             createPreparedModel(device, model, &preparedModel);
             if (preparedModel == nullptr) return;
             EvaluatePreparedModel(device, preparedModel, testModel, testKind);
@@ -793,12 +858,6 @@
 void GeneratedTestBase::SetUp() {
     testing::TestWithParam<GeneratedTestParam>::SetUp();
     ASSERT_NE(kDevice, nullptr);
-
-    const Return<void> ret =
-            kDevice->supportsDeadlines([this](bool prepareModelDeadline, bool executionDeadline) {
-                mSupportsDeadlines = {prepareModelDeadline, executionDeadline};
-            });
-    ASSERT_TRUE(ret.isOk());
 }
 
 std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
@@ -825,24 +884,31 @@
 // Tag for the dynamic output shape tests
 class QuantizationCouplingTest : public GeneratedTest {};
 
+// Tag for the loop timeout tests
+class InfiniteLoopTimeoutTest : public GeneratedTest {};
+
 TEST_P(GeneratedTest, Test) {
-    Execute(kDevice, kTestModel, /*testKind=*/TestKind::GENERAL);
+    Execute(kDevice, kTestModel, TestKind::GENERAL);
 }
 
 TEST_P(DynamicOutputShapeTest, Test) {
-    Execute(kDevice, kTestModel, /*testKind=*/TestKind::DYNAMIC_SHAPE);
+    Execute(kDevice, kTestModel, TestKind::DYNAMIC_SHAPE);
 }
 
 TEST_P(MemoryDomainTest, Test) {
-    Execute(kDevice, kTestModel, /*testKind=*/TestKind::MEMORY_DOMAIN);
+    Execute(kDevice, kTestModel, TestKind::MEMORY_DOMAIN);
 }
 
 TEST_P(FencedComputeTest, Test) {
-    Execute(kDevice, kTestModel, /*testKind=*/TestKind::FENCED_COMPUTE);
+    Execute(kDevice, kTestModel, TestKind::FENCED_COMPUTE);
 }
 
 TEST_P(QuantizationCouplingTest, Test) {
-    Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING);
+    Execute(kDevice, kTestModel, TestKind::QUANTIZATION_COUPLING);
+}
+
+TEST_P(InfiniteLoopTimeoutTest, Test) {
+    Execute(kDevice, kTestModel, TestKind::INTINITE_LOOP_TIMEOUT);
 }
 
 INSTANTIATE_GENERATED_TEST(GeneratedTest,
@@ -859,7 +925,11 @@
                            [](const TestModel& testModel) { return !testModel.expectFailure; });
 
 INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) {
-    return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1;
+    return testModel.hasQuant8CoupledOperands() && testModel.main.operations.size() == 1;
+});
+
+INSTANTIATE_GENERATED_TEST(InfiniteLoopTimeoutTest, [](const TestModel& testModel) {
+    return testModel.isInfiniteLoopTimeoutTest();
 });
 
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
index e597fac..834d335 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
@@ -36,7 +36,6 @@
     void SetUp() override;
     const sp<IDevice> kDevice = getData(std::get<NamedDevice>(GetParam()));
     const test_helper::TestModel& kTestModel = *getData(std::get<NamedModel>(GetParam()));
-    std::pair<bool, bool> mSupportsDeadlines;
 };
 
 using FilterFn = std::function<bool(const test_helper::TestModel&)>;
@@ -70,7 +69,9 @@
     // Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result
     // (OK/SKIPPED/FAILED) as the model with all such tensors converted to
     // TENSOR_QUANT8_ASYMM_SIGNED.
-    QUANTIZATION_COUPLING
+    QUANTIZATION_COUPLING,
+    // Runs a test model and verifies that MISSED_DEADLINE_* is returned.
+    INTINITE_LOOP_TIMEOUT
 };
 
 void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>& preparedModel,
diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
index 62ffcda..879989e 100644
--- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
@@ -34,43 +34,52 @@
 using HidlToken =
         hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
 
-enum class DeadlineBoundType { NOW, UNLIMITED };
-constexpr std::array<DeadlineBoundType, 2> deadlineBounds = {DeadlineBoundType::NOW,
-                                                             DeadlineBoundType::UNLIMITED};
+enum class DeadlineBoundType { NOW, UNLIMITED, SHORT };
+constexpr std::array<DeadlineBoundType, 3> deadlineBounds = {
+        DeadlineBoundType::NOW, DeadlineBoundType::UNLIMITED, DeadlineBoundType::SHORT};
 std::string toString(DeadlineBoundType type) {
     switch (type) {
         case DeadlineBoundType::NOW:
             return "NOW";
         case DeadlineBoundType::UNLIMITED:
             return "UNLIMITED";
+        case DeadlineBoundType::SHORT:
+            return "SHORT";
     }
     LOG(FATAL) << "Unrecognized DeadlineBoundType: " << static_cast<int>(type);
     return {};
 }
 
+constexpr auto kShortDuration = std::chrono::milliseconds{5};
+
 using Results = std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing>;
 using MaybeResults = std::optional<Results>;
 
 using ExecutionFunction =
         std::function<MaybeResults(const sp<IPreparedModel>& preparedModel, const Request& request,
-                                   DeadlineBoundType deadlineBound)>;
+                                   const OptionalTimePoint& deadline)>;
 
-static OptionalTimePoint makeOptionalTimePoint(DeadlineBoundType deadlineBoundType) {
-    OptionalTimePoint deadline;
+static OptionalTimePoint makeDeadline(DeadlineBoundType deadlineBoundType) {
+    const auto getNanosecondsSinceEpoch = [](const auto& time) -> uint64_t {
+        const auto timeSinceEpoch = time.time_since_epoch();
+        return std::chrono::duration_cast<std::chrono::nanoseconds>(timeSinceEpoch).count();
+    };
+
+    std::chrono::steady_clock::time_point timePoint;
     switch (deadlineBoundType) {
-        case DeadlineBoundType::NOW: {
-            const auto currentTime = std::chrono::steady_clock::now();
-            const auto currentTimeInNanoseconds =
-                    std::chrono::time_point_cast<std::chrono::nanoseconds>(currentTime);
-            const uint64_t nanosecondsSinceEpoch =
-                    currentTimeInNanoseconds.time_since_epoch().count();
-            deadline.nanoseconds(nanosecondsSinceEpoch);
-        } break;
-        case DeadlineBoundType::UNLIMITED: {
-            uint64_t unlimited = std::numeric_limits<uint64_t>::max();
-            deadline.nanoseconds(unlimited);
-        } break;
+        case DeadlineBoundType::NOW:
+            timePoint = std::chrono::steady_clock::now();
+            break;
+        case DeadlineBoundType::UNLIMITED:
+            timePoint = std::chrono::steady_clock::time_point::max();
+            break;
+        case DeadlineBoundType::SHORT:
+            timePoint = std::chrono::steady_clock::now() + kShortDuration;
+            break;
     }
+
+    OptionalTimePoint deadline;
+    deadline.nanosecondsSinceEpoch(getNanosecondsSinceEpoch(timePoint));
     return deadline;
 }
 
@@ -78,7 +87,7 @@
                          std::optional<DeadlineBoundType> deadlineBound) {
     OptionalTimePoint deadline;
     if (deadlineBound.has_value()) {
-        deadline = makeOptionalTimePoint(deadlineBound.value());
+        deadline = makeDeadline(deadlineBound.value());
     }
 
     // see if service can handle model
@@ -125,11 +134,11 @@
     } else {
         switch (deadlineBound.value()) {
             case DeadlineBoundType::NOW:
-                // If the execution was launched with a deadline of NOW, the
-                // deadline has already passed when the driver would launch the
-                // execution. In this case, the driver must return
-                // MISSED_DEADLINE_*.
-                EXPECT_TRUE(prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
+            case DeadlineBoundType::SHORT:
+                // Either the driver successfully completed the task or it
+                // aborted and returned MISSED_DEADLINE_*.
+                EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE ||
+                            prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
                             prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT);
                 break;
             case DeadlineBoundType::UNLIMITED:
@@ -143,8 +152,7 @@
     ASSERT_EQ(prepareReturnStatus == ErrorStatus::NONE, preparedModel.get() != nullptr);
 }
 
-void runPrepareModelTests(const sp<IDevice>& device, const Model& model,
-                          bool supportsPrepareModelDeadline) {
+void runPrepareModelTests(const sp<IDevice>& device, const Model& model) {
     // test priority
     for (auto priority : hidl_enum_range<Priority>{}) {
         SCOPED_TRACE("priority: " + toString(priority));
@@ -153,23 +161,21 @@
     }
 
     // test deadline
-    if (supportsPrepareModelDeadline) {
-        for (auto deadlineBound : deadlineBounds) {
-            SCOPED_TRACE("deadlineBound: " + toString(deadlineBound));
-            runPrepareModelTest(device, model, kDefaultPriority, deadlineBound);
-        }
+    for (auto deadlineBound : deadlineBounds) {
+        SCOPED_TRACE("deadlineBound: " + toString(deadlineBound));
+        runPrepareModelTest(device, model, kDefaultPriority, deadlineBound);
     }
 }
 
 static MaybeResults executeAsynchronously(const sp<IPreparedModel>& preparedModel,
-                                          const Request& request, DeadlineBoundType deadlineBound) {
+                                          const Request& request,
+                                          const OptionalTimePoint& deadline) {
     SCOPED_TRACE("asynchronous");
     const MeasureTiming measure = MeasureTiming::NO;
-    const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound);
 
     // launch execution
     const sp<ExecutionCallback> callback = new ExecutionCallback();
-    Return<ErrorStatus> ret = preparedModel->execute_1_3(request, measure, deadline, callback);
+    Return<ErrorStatus> ret = preparedModel->execute_1_3(request, measure, deadline, {}, callback);
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(ErrorStatus::NONE, ret.withDefault(ErrorStatus::GENERAL_FAILURE));
     if (!ret.isOk() || ret != ErrorStatus::NONE) return std::nullopt;
@@ -185,18 +191,21 @@
 }
 
 static MaybeResults executeSynchronously(const sp<IPreparedModel>& preparedModel,
-                                         const Request& request, DeadlineBoundType deadlineBound) {
+                                         const Request& request,
+                                         const OptionalTimePoint& deadline) {
     SCOPED_TRACE("synchronous");
     const MeasureTiming measure = MeasureTiming::NO;
-    const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound);
 
     // configure results callback
     MaybeResults results;
-    const auto cb = [&results](const auto&... args) { *results = {args...}; };
+    const auto cb = [&results](ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+                               const Timing& timing) {
+        results.emplace(status, outputShapes, timing);
+    };
 
     // run execution
     const Return<void> ret =
-            preparedModel->executeSynchronously_1_3(request, measure, deadline, cb);
+            preparedModel->executeSynchronously_1_3(request, measure, deadline, {}, cb);
     EXPECT_TRUE(ret.isOk());
     if (!ret.isOk()) return std::nullopt;
 
@@ -207,9 +216,10 @@
 void runExecutionTest(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
                       const Request& request, bool synchronous, DeadlineBoundType deadlineBound) {
     const ExecutionFunction execute = synchronous ? executeSynchronously : executeAsynchronously;
+    const auto deadline = makeDeadline(deadlineBound);
 
     // Perform execution and unpack results.
-    const auto results = execute(preparedModel, request, deadlineBound);
+    const auto results = execute(preparedModel, request, deadline);
     if (!results.has_value()) return;
     const auto& [status, outputShapes, timing] = results.value();
 
@@ -220,13 +230,13 @@
     // Validate deadline information if applicable.
     switch (deadlineBound) {
         case DeadlineBoundType::NOW:
-            // If the execution was launched with a deadline of NOW, the
-            // deadline has already passed when the driver would launch the
-            // execution. In this case, the driver must return
-            // MISSED_DEADLINE_*.
-            ASSERT_TRUE(status == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
+        case DeadlineBoundType::SHORT:
+            // Either the driver successfully completed the task or it
+            // aborted and returned MISSED_DEADLINE_*.
+            ASSERT_TRUE(status == ErrorStatus::NONE ||
+                        status == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
                         status == ErrorStatus::MISSED_DEADLINE_PERSISTENT);
-            return;
+            break;
         case DeadlineBoundType::UNLIMITED:
             // If an unlimited deadline is supplied, we expect the execution to
             // proceed normally. In this case, check it normally by breaking out
@@ -237,12 +247,13 @@
 
     // If the model output operands are fully specified, outputShapes must be either
     // either empty, or have the same number of elements as the number of outputs.
-    ASSERT_TRUE(outputShapes.size() == 0 || outputShapes.size() == testModel.outputIndexes.size());
+    ASSERT_TRUE(outputShapes.size() == 0 ||
+                outputShapes.size() == testModel.main.outputIndexes.size());
 
     // Go through all outputs, check returned output shapes.
     for (uint32_t i = 0; i < outputShapes.size(); i++) {
         EXPECT_TRUE(outputShapes[i].isSufficient);
-        const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions;
+        const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
         const std::vector<uint32_t> actual = outputShapes[i].dimensions;
         EXPECT_EQ(expect, actual);
     }
@@ -253,7 +264,9 @@
     const std::vector<TestBuffer> outputs = getOutputBuffers(request10);
 
     // We want "close-enough" results.
-    checkResults(testModel, outputs);
+    if (status == ErrorStatus::NONE) {
+        checkResults(testModel, outputs);
+    }
 }
 
 void runExecutionTests(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
@@ -265,32 +278,27 @@
     }
 }
 
-void runTests(const sp<IDevice>& device, const TestModel& testModel,
-              std::pair<bool, bool> supportsDeadlines) {
+void runTests(const sp<IDevice>& device, const TestModel& testModel) {
     // setup
-    const auto [supportsPrepareModelDeadline, supportsExecutionDeadline] = supportsDeadlines;
-    if (!supportsPrepareModelDeadline && !supportsExecutionDeadline) return;
     const Model model = createModel(testModel);
 
     // run prepare model tests
-    runPrepareModelTests(device, model, supportsPrepareModelDeadline);
+    runPrepareModelTests(device, model);
 
-    if (supportsExecutionDeadline) {
-        // prepare model
-        sp<IPreparedModel> preparedModel;
-        createPreparedModel(device, model, &preparedModel);
-        if (preparedModel == nullptr) return;
+    // prepare model
+    sp<IPreparedModel> preparedModel;
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
 
-        // run execution tests
-        const Request request = nn::convertToV1_3(createRequest(testModel));
-        runExecutionTests(preparedModel, testModel, request);
-    }
+    // run execution tests
+    const Request request = nn::convertToV1_3(createRequest(testModel));
+    runExecutionTests(preparedModel, testModel, request);
 }
 
 class DeadlineTest : public GeneratedTestBase {};
 
 TEST_P(DeadlineTest, Test) {
-    runTests(kDevice, kTestModel, mSupportsDeadlines);
+    runTests(kDevice, kTestModel);
 }
 
 INSTANTIATE_GENERATED_TEST(DeadlineTest,
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 1245432..8f2d4b7 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -44,18 +44,12 @@
 }
 
 static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
-                                 const Model& model, ExecutionPreference preference,
-                                 bool testDeadline) {
+                                 const Model& model, ExecutionPreference preference) {
     SCOPED_TRACE(message + " [prepareModel_1_3]");
 
-    OptionalTimePoint deadline;
-    if (testDeadline) {
-        deadline.nanoseconds(std::numeric_limits<uint64_t>::max());
-    }
-
     sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
     Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3(
-            model, preference, kDefaultPriority, deadline, hidl_vec<hidl_handle>(),
+            model, preference, kDefaultPriority, {}, hidl_vec<hidl_handle>(),
             hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -79,13 +73,12 @@
 // to the model does not leave this function.
 static void validate(const sp<IDevice>& device, const std::string& message, Model model,
                      const std::function<void(Model*)>& mutation,
-                     ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER,
-                     bool testDeadline = false) {
+                     ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
     mutation(&model);
-    if (validExecutionPreference(preference) && !testDeadline) {
+    if (validExecutionPreference(preference)) {
         validateGetSupportedOperations(device, message, model);
     }
-    validatePrepareModel(device, message, model, preference, testDeadline);
+    validatePrepareModel(device, message, model, preference);
 }
 
 static uint32_t addOperand(Model* model) {
@@ -182,6 +175,7 @@
         case OperandType::TENSOR_FLOAT16:
         case OperandType::TENSOR_FLOAT32:
         case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
+        case OperandType::SUBGRAPH:
             return 1.0f;
         case OperandType::TENSOR_INT32:
             return -1.0f;
@@ -220,6 +214,7 @@
         case OperandType::TENSOR_FLOAT32:
         case OperandType::TENSOR_INT32:
         case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
+        case OperandType::SUBGRAPH:
             return {1};
         case OperandType::TENSOR_QUANT8_ASYMM:
             return {-1, 256};
@@ -527,9 +522,15 @@
                 }
             }
         }
-        // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have either one or two
-        // outputs depending on their mergeOutputs parameter.
-        if (operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM ||
+        // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have
+        // either one, two, three or four outputs depending on their
+        // mergeOutputs parameter and if state outputs are provided.
+        // UNIDIRECTIONAL_SEQUENCE_LSTM and UNIDIRECTIONAL_SEQUENCE_RNN can have
+        // either one or three outputs depending on whether state outputs are
+        // provided.
+        if (operation.type == OperationType::UNIDIRECTIONAL_SEQUENCE_LSTM ||
+            operation.type == OperationType::UNIDIRECTIONAL_SEQUENCE_RNN ||
+            operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_LSTM ||
             operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) {
             for (const size_t outOprand : operation.outputs) {
                 if (operand == outOprand) {
@@ -736,19 +737,9 @@
     }
 }
 
-///////////////////////// DEADLINE /////////////////////////
-
-static void deadlineTest(const sp<IDevice>& device, const Model& model) {
-    const std::string message = "deadlineTest: deadline not supported";
-    const auto noop = [](Model*) {};
-    validate(device, message, model, noop, ExecutionPreference::FAST_SINGLE_ANSWER,
-             /*testDeadline=*/true);
-}
-
 ////////////////////////// ENTRY POINT //////////////////////////////
 
-void validateModel(const sp<IDevice>& device, const Model& model,
-                   bool prepareModelDeadlineSupported) {
+void validateModel(const sp<IDevice>& device, const Model& model) {
     mutateOperandTypeTest(device, model);
     mutateOperandRankTest(device, model);
     mutateOperandScaleTest(device, model);
@@ -764,9 +755,6 @@
     addOperationInputTest(device, model);
     addOperationOutputTest(device, model);
     mutateExecutionPreferenceTest(device, model);
-    if (!prepareModelDeadlineSupported) {
-        deadlineTest(device, model);
-    }
 }
 
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 1ddd09c..5e806e5 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -45,8 +45,7 @@
 // that use the request. Note that the request here is passed by value, and any
 // mutation to the request does not leave this function.
 static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
-                     Request request, const std::function<void(Request*)>& mutation,
-                     bool testDeadline = false) {
+                     Request request, const std::function<void(Request*)>& mutation) {
     mutation(&request);
 
     // We'd like to test both with timing requested and without timing
@@ -59,18 +58,13 @@
     };
     MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO;
 
-    OptionalTimePoint deadline;
-    if (testDeadline) {
-        deadline.nanoseconds(std::numeric_limits<uint64_t>::max());
-    }
-
     // asynchronous
     {
         SCOPED_TRACE(message + " [execute_1_3]");
 
         sp<ExecutionCallback> executionCallback = new ExecutionCallback();
         Return<ErrorStatus> executeLaunchStatus =
-                preparedModel->execute_1_3(request, measure, deadline, executionCallback);
+                preparedModel->execute_1_3(request, measure, {}, {}, executionCallback);
         ASSERT_TRUE(executeLaunchStatus.isOk());
         ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
 
@@ -88,7 +82,7 @@
         SCOPED_TRACE(message + " [executeSynchronously_1_3]");
 
         Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
-                request, measure, deadline,
+                request, measure, {}, {},
                 [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
                    const Timing& timing) {
                     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
@@ -100,7 +94,7 @@
 
     // burst
     // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2.
-    if (!testDeadline) {
+    {
         SCOPED_TRACE(message + " [burst]");
 
         ASSERT_TRUE(nn::compliantWithV1_0(request));
@@ -142,16 +136,14 @@
     // dispatch
     {
         SCOPED_TRACE(message + " [executeFenced]");
-        Return<void> ret = preparedModel->executeFenced(
-                request, {}, MeasureTiming::NO,
-                [](ErrorStatus error, const hidl_handle& handle,
-                   const sp<IFencedExecutionCallback>& callback) {
-                    if (error != ErrorStatus::DEVICE_UNAVAILABLE) {
-                        ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
-                    }
-                    ASSERT_EQ(handle.getNativeHandle(), nullptr);
-                    ASSERT_EQ(callback, nullptr);
-                });
+        Return<void> ret =
+                preparedModel->executeFenced(request, {}, MeasureTiming::NO, {}, {}, {},
+                                             [](ErrorStatus error, const hidl_handle& handle,
+                                                const sp<IFencedExecutionCallback>& callback) {
+                                                 ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+                                                 ASSERT_EQ(handle.getNativeHandle(), nullptr);
+                                                 ASSERT_EQ(callback, nullptr);
+                                             });
         ASSERT_TRUE(ret.isOk());
     }
 }
@@ -176,29 +168,17 @@
     }
 }
 
-///////////////////////// DEADLINE ////////////////////////////////////
-
-static void deadlineTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
-    const std::string message = "deadlineTest: deadline not supported";
-    const auto noop = [](Request*) {};
-    validate(preparedModel, message, request, noop, /*testDeadline=*/true);
-}
-
 ///////////////////////////// ENTRY POINT //////////////////////////////////
 
-void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request,
-                     bool executionDeadlineSupported) {
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request) {
     removeInputTest(preparedModel, request);
     removeOutputTest(preparedModel, request);
-    if (!executionDeadlineSupported) {
-        deadlineTest(preparedModel, request);
-    }
 }
 
 void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request) {
     SCOPED_TRACE("Expecting request to fail [executeSynchronously_1_3]");
     Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
-            request, MeasureTiming::NO, {},
+            request, MeasureTiming::NO, {}, {},
             [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
                 ASSERT_NE(ErrorStatus::NONE, error);
                 EXPECT_EQ(outputShapes.size(), 0);
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
index c84f5b7..5b07034 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -123,11 +123,9 @@
 INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest);
 
 // Forward declaration from ValidateModel.cpp
-void validateModel(const sp<IDevice>& device, const Model& model,
-                   bool prepareModelDeadlineSupported);
+void validateModel(const sp<IDevice>& device, const Model& model);
 // Forward declaration from ValidateRequest.cpp
-void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request,
-                     bool executionDeadlineSupported);
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request);
 // Forward declaration from ValidateRequest.cpp
 void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request);
 // Forward declaration from ValidateBurst.cpp
@@ -136,31 +134,26 @@
 // Validate sync_fence handles for dispatch with valid input
 void validateExecuteFenced(const sp<IPreparedModel>& preparedModel, const Request& request) {
     SCOPED_TRACE("Expecting request to fail [executeFenced]");
-    Return<void> ret_null =
-            preparedModel->executeFenced(request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO,
-                                         [](ErrorStatus error, const hidl_handle& handle,
-                                            const sp<IFencedExecutionCallback>& callback) {
-                                             // TODO: fix this once sample driver impl is merged.
-                                             if (error != ErrorStatus::DEVICE_UNAVAILABLE) {
-                                                 ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
-                                             }
-                                             ASSERT_EQ(handle.getNativeHandle(), nullptr);
-                                             ASSERT_EQ(callback, nullptr);
-                                         });
+    Return<void> ret_null = preparedModel->executeFenced(
+            request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, {}, {}, {},
+            [](ErrorStatus error, const hidl_handle& handle,
+               const sp<IFencedExecutionCallback>& callback) {
+                ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+                ASSERT_EQ(handle.getNativeHandle(), nullptr);
+                ASSERT_EQ(callback, nullptr);
+            });
     ASSERT_TRUE(ret_null.isOk());
 }
 
-void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request,
-                        std::pair<bool, bool> supportsDeadlines) {
-    const auto [prepareModelDeadlineSupported, executionDeadlineSupported] = supportsDeadlines;
-    validateModel(device, model, prepareModelDeadlineSupported);
+void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request) {
+    validateModel(device, model);
 
     // Create IPreparedModel.
     sp<IPreparedModel> preparedModel;
     createPreparedModel(device, model, &preparedModel);
     if (preparedModel == nullptr) return;
 
-    validateRequest(preparedModel, request, executionDeadlineSupported);
+    validateRequest(preparedModel, request);
     validateExecuteFenced(preparedModel, request);
 
     // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2.
@@ -169,12 +162,10 @@
     validateBurst(preparedModel, request10);
 }
 
-void validateFailure(const sp<IDevice>& device, const Model& model, const Request& request,
-                     std::pair<bool, bool> supportsDeadlines) {
-    const bool prepareModelDeadlineSupported = supportsDeadlines.first;
+void validateFailure(const sp<IDevice>& device, const Model& model, const Request& request) {
     // TODO: Should this always succeed?
     //       What if the invalid input is part of the model (i.e., a parameter).
-    validateModel(device, model, prepareModelDeadlineSupported);
+    validateModel(device, model);
 
     // Create IPreparedModel.
     sp<IPreparedModel> preparedModel;
@@ -188,9 +179,9 @@
     const Model model = createModel(kTestModel);
     const Request request = nn::convertToV1_3(createRequest(kTestModel));
     if (kTestModel.expectFailure) {
-        validateFailure(kDevice, model, request, mSupportsDeadlines);
+        validateFailure(kDevice, model, request);
     } else {
-        validateEverything(kDevice, model, request, mSupportsDeadlines);
+        validateEverything(kDevice, model, request);
     }
 }
 
diff --git a/power/aidl/android/hardware/power/Boost.aidl b/power/aidl/android/hardware/power/Boost.aidl
index 162a36a..c992fd3 100644
--- a/power/aidl/android/hardware/power/Boost.aidl
+++ b/power/aidl/android/hardware/power/Boost.aidl
@@ -29,6 +29,13 @@
     INTERACTION,
 
     /**
+     * This boost indicates that the framework is likely to provide a new
+     * display frame soon. This implies that the device should ensure that the
+     * display processing path is powered up and ready to receive that update.
+     */
+    DISPLAY_UPDATE_IMMINENT,
+
+    /**
      * Below hints are currently not sent in Android framework but OEM might choose to
      * implement for power/perf optimizations.
      */
diff --git a/power/aidl/android/hardware/power/IPower.aidl b/power/aidl/android/hardware/power/IPower.aidl
index 9fb3fc0..2c4bd86 100644
--- a/power/aidl/android/hardware/power/IPower.aidl
+++ b/power/aidl/android/hardware/power/IPower.aidl
@@ -43,7 +43,7 @@
      */
     boolean isModeSupported(in Mode type);
 
-   /**
+    /**
      * setBoost() indicates the device may need to boost some resources, as the
      * the load is likely to increase before the kernel governors can react.
      * Depending on the boost, it may be appropriate to raise the frequencies of
diff --git a/power/aidl/android/hardware/power/Mode.aidl b/power/aidl/android/hardware/power/Mode.aidl
index 9bb5b98..ae113e3 100644
--- a/power/aidl/android/hardware/power/Mode.aidl
+++ b/power/aidl/android/hardware/power/Mode.aidl
@@ -26,20 +26,64 @@
     DOUBLE_TAP_TO_WAKE,
 
     /**
-     * This mode indidates Low power mode is activated or not. Low power
+     * This mode indicates Low power mode is activated or not. Low power
      * mode is intended to save battery at the cost of performance.
      */
     LOW_POWER,
 
     /**
-     * This mode indidates Sustained Performance mode is activated or not.
+     * This mode indicates Sustained Performance mode is activated or not.
      * Sustained performance mode is intended to provide a consistent level of
      * performance for a prolonged amount of time.
      */
     SUSTAINED_PERFORMANCE,
 
     /**
-     * This mode indidates VR Mode is activated or not. VR mode is intended
+     * Sets the device to a fixed performance level which can be sustained under
+     * normal indoor conditions for at least 10 minutes.
+     *
+     * This is similar to sustained performance mode, except that whereas
+     * sustained performance mode puts an upper bound on performance in the
+     * interest of long-term stability, fixed performance mode puts both upper
+     * and lower bounds on performance such that any workload run while in a
+     * fixed performance mode should complete in a repeatable amount of time
+     * (except if the device is under thermal throttling).
+     *
+     * This mode is not intended for general purpose use, but rather to enable
+     * games and other performance-sensitive applications to reduce the number
+     * of variables during profiling and performance debugging. As such, while
+     * it is valid to set the device to minimum clocks for all subsystems in
+     * this mode, it is preferable to attempt to make the relative performance
+     * of the CPU, GPU, and other subsystems match typical usage, even if the
+     * frequencies have to be reduced to provide sustainability.
+     *
+     * To calibrate this mode, follow these steps:
+     *
+     * 1) Build and push the HWUI macrobench as described in
+     *    //frameworks/base/libs/hwui/tests/macrobench/how_to_run.txt
+     * 2) Run the macrobench as follows:
+     *    while true; do \
+     *      adb shell /data/benchmarktest/hwuimacro/hwuimacro shadowgrid2 -c 200 -r 10; \
+     *    done
+     * 3) Determine a fixed set of device clocks such that the loop in (2) can
+     *    run for at least 10 minutes, starting from an idle device on a desk
+     *    at room temperature (roughly 22 Celsius), without hitting thermal
+     *    throttling.
+     * 4) After setting those clocks, set the system property
+     *    ro.power.fixed_performance_scale_factor to a value N, where N is the
+     *    number of times the loop from (2) runs during the 10 minute test
+     *    cycle. It is expected that in FIXED_PERFORMANCE mode, unless there is
+     *    thermal throttling, the loop will run N to N+1 times (inclusive).
+     *
+     * After calibrating this, while in FIXED_PERFORMANCE mode, the macrobench
+     * results obtained while running the loop in (2) should be consistent both
+     * within a given run and from the first run in the 10 minute window through
+     * the last run in the window.
+     */
+    FIXED_PERFORMANCE,
+
+    /**
+     * This mode indicates VR Mode is activated or not. VR mode is intended
      * to provide minimum guarantee for performance for the amount of time the
      * device can sustain it.
      */
@@ -76,6 +120,18 @@
      */
     INTERACTIVE,
 
+    /**
+     * This mode indicates the device is in device idle, externally known as doze.
+     * More details on:
+     * https://developer.android.com/training/monitoring-device-state/doze-standby
+     */
+    DEVICE_IDLE,
+
+    /**
+     * This mode indicates that display is either off or still on but is optimized
+     * for low-power.
+     */
+    DISPLAY_INACTIVE,
 
     /**
      * Below hints are currently not sent in Android framework but OEM might choose to
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index c0e0858..25a385e 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -16,6 +16,7 @@
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
 
+#include <android-base/properties.h>
 #include <android/hardware/power/Boost.h>
 #include <android/hardware/power/IPower.h>
 #include <android/hardware/power/Mode.h>
@@ -27,6 +28,7 @@
 using android::ProcessState;
 using android::sp;
 using android::String16;
+using android::base::GetUintProperty;
 using android::binder::Status;
 using android::hardware::power::Boost;
 using android::hardware::power::IPower;
@@ -77,7 +79,7 @@
     for (const auto& mode : kInvalidModes) {
         bool supported;
         ASSERT_TRUE(power->isModeSupported(mode, &supported).isOk());
-        // Should return false for values outsides enum
+        // Should return false for values outside enum
         ASSERT_FALSE(supported);
     }
 }
@@ -103,11 +105,27 @@
     for (const auto& boost : kInvalidBoosts) {
         bool supported;
         ASSERT_TRUE(power->isBoostSupported(boost, &supported).isOk());
-        // Should return false for values outsides enum
+        // Should return false for values outside enum
         ASSERT_FALSE(supported);
     }
 }
 
+// FIXED_PERFORMANCE mode is required for all devices which ship on Android 11
+// or later
+TEST_P(PowerAidl, hasFixedPerformance) {
+    auto apiLevel = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+    if (apiLevel == 0) {
+        apiLevel = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+    }
+    ASSERT_NE(apiLevel, 0);
+
+    if (apiLevel >= 30) {
+        bool supported;
+        ASSERT_TRUE(power->isModeSupported(Mode::FIXED_PERFORMANCE, &supported).isOk());
+        ASSERT_TRUE(supported);
+    }
+}
+
 INSTANTIATE_TEST_SUITE_P(Power, PowerAidl,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IPower::descriptor)),
                          android::PrintInstanceNameToString);
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
index 75abbbf..02dcbab 100644
--- a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
@@ -24,6 +24,9 @@
     /* Record the sim card state for the testing environment */
     CardState cardStateForTest = cardStatus.cardState;
 
+#if 0
+    /* This test has to be removed for Japan Model.
+     * After "setSimCardPower power down", Japan model can not "setSimCardPower power up" */
     /* Test setSimCardPower power down */
     serial = GetRandomSerialNumber();
     radio_v1_1->setSimCardPower_1_1(serial, CardPowerState::POWER_DOWN);
@@ -46,6 +49,7 @@
         }
         EXPECT_EQ(CardState::ABSENT, cardStatus.cardState);
     }
+#endif
 
     /* Test setSimCardPower power up */
     serial = GetRandomSerialNumber();
diff --git a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
index 4e48141..ca64305 100644
--- a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
@@ -75,38 +75,3 @@
             radioRsp_v1_3->rspInfo.error,
             {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
 }
-
-/*
- * Test IRadio.setSystemSelectionChannels() for the response returned.
- *
- * This test is excluded from manifest, due to non-implementation in Q. Tracked by b/130254624.
- */
-TEST_P(RadioHidlTest_v1_3, setSystemSelectionChannels) {
-    serial = GetRandomSerialNumber();
-
-    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
-                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-                                      .channels = {1, 2}};
-
-    Return<void> res = radio_v1_3->setSystemSelectionChannels(serial, true, {specifier});
-    ASSERT_OK(res);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial);
-    ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
-          toString(radioRsp_v1_3->rspInfo.error).c_str());
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_v1_3->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR}));
-
-    if (radioRsp_v1_3->rspInfo.error == RadioError::NONE) {
-        Return<void> res = radio_v1_3->setSystemSelectionChannels(serial, false, {specifier});
-        ASSERT_OK(res);
-        EXPECT_EQ(std::cv_status::no_timeout, wait());
-        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type);
-        EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial);
-        ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
-              toString(radioRsp_v1_3->rspInfo.error).c_str());
-        EXPECT_EQ(RadioError::NONE, radioRsp_v1_3->rspInfo.error);
-    }
-}
\ No newline at end of file
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index bc40500..0b50436 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -18,10 +18,8 @@
 
 import @1.0::CdmaSmsMessage;
 import @1.2::DataRequestReason;
-import @1.4::DataProfileInfo;
 import @1.4::IRadio;
 import @1.5::AccessNetwork;
-import @1.5::BarringInfo;
 import @1.5::DataProfileInfo;
 import @1.5::IndicationFilter;
 import @1.5::LinkAddress;
@@ -71,6 +69,35 @@
             SignalThresholdInfo signalThresholdInfo, AccessNetwork accessNetwork);
 
     /**
+     * Sets the link capacity reporting criteria.
+     *
+     * The resulting reporting criteria are the AND of all the supplied criteria.
+     *
+     * Note: Reporting criteria must be individually set for each RAN. If unset, reporting criteria
+     * for that RAN are implementation-defined.
+     *
+     * Response callback is IRadioResponse.setLinkCapacityReportingCriteriaResponse_1_5().
+     *
+     * @param serial Serial number of request.
+     * @param hysteresisMs A hysteresis time in milliseconds to prevent flapping. A value of 0
+     *     disables hysteresis.
+     * @param hysteresisDlKbps An interval in kbps defining the required magnitude change between DL
+     *     reports. hysteresisDlKbps must be smaller than the smallest threshold delta. A value of 0
+     *     disables hysteresis.
+     * @param hysteresisUlKbps An interval in kbps defining the required magnitude change between UL
+     *     reports. hysteresisUlKbps must be smaller than the smallest threshold delta. A value of 0
+     *     disables hysteresis.
+     * @param thresholdsDownlinkKbps A vector of trigger thresholds in kbps for downlink reports. A
+     *     vector size of 0 disables the use of DL thresholds for reporting.
+     * @param thresholdsUplinkKbps A vector of trigger thresholds in kbps for uplink reports. A
+     *     vector size of 0 disables the use of UL thresholds for reporting.
+     * @param accessNetwork The type of network for which to apply these thresholds.
+     */
+    oneway setLinkCapacityReportingCriteria_1_5(int32_t serial, int32_t hysteresisMs,
+            int32_t hysteresisDlKbps, int32_t hysteresisUlKbps, vec<int32_t> thresholdsDownlinkKbps,
+            vec<int32_t> thresholdsUplinkKbps, AccessNetwork accessNetwork);
+
+    /**
      * Enable or disable UiccApplications on the SIM. If disabled:
      *  - Modem will not register on any network.
      *  - SIM must be PRESENT, and the IccId of the SIM must still be accessible.
@@ -118,13 +145,13 @@
             vec<RadioAccessSpecifier> specifiers);
 
     /**
-     * Starts a network scan
+     * Starts a network scan.
      *
      * @param serial Serial number of request.
      * @param request Defines the radio networks/bands/channels which need to be scanned.
      *
-     * Same API as @1.4::IRadio.startNetworkScan_1_4, except using
-     * 1.5 version of NetworkScanRequest
+     * Same API as @1.4::IRadio.startNetworkScan_1_4, except using the
+     * 1.5 NetworkScanRequest as the input param.
      */
     oneway startNetworkScan_1_5(int32_t serial, NetworkScanRequest request);
 
@@ -166,14 +193,14 @@
      * Response function is IRadioResponse.setupDataCallResponse_1_5()
      *
      * Note this API is the same as the 1.4 version except using the
-     * 1.5 AccessNetwork, DataProfileInto, and link addresses as the input param.
+     * 1.5 AccessNetwork, DataProfileInto, and LinkAddress as the input param.
      */
     oneway setupDataCall_1_5(int32_t serial, AccessNetwork accessNetwork,
             DataProfileInfo dataProfileInfo, bool roamingAllowed,
             DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses);
 
     /**
-     * Set an apn to initial attach network
+     * Set an APN to initial attach network.
      *
      * @param serial Serial number of request.
      * @param dataProfileInfo data profile containing APN settings
@@ -189,7 +216,7 @@
      * Send data profiles of the current carrier to the modem.
      *
      * @param serial Serial number of request.
-     * @param profiles Array of DataProfile to set.
+     * @param profiles Array of DataProfileInfo to set.
      *
      * Response callback is IRadioResponse.setDataProfileResponse_1_5()
      *
@@ -230,7 +257,7 @@
      *
      * Prevents the reporting of specified unsolicited indications from the radio. This is used
      * for power saving in instances when those indications are not needed. If unset, defaults to
-     * @1.2::IndicationFilter:ALL.
+     * @1.5::IndicationFilter:ALL.
      *
      * @param serial Serial number of request.
      * @param indicationFilter 32-bit bitmap of IndicationFilter. Bits set to 1 indicate the
@@ -250,7 +277,7 @@
     oneway getBarringInfo(int32_t serial);
 
     /**
-     * Request current voice registration state
+     * Request current voice registration state.
      *
      * @param serial Serial number of request.
      *
@@ -259,7 +286,7 @@
     oneway getVoiceRegistrationState_1_5(int32_t serial);
 
     /**
-     * Request current data registration state
+     * Request current data registration state.
      *
      * @param serial Serial number of request.
      *
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index 6a2187f..e87cad2 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -20,11 +20,11 @@
 import @1.0::SendSmsResult;
 import @1.4::IRadioResponse;
 import @1.5::BarringInfo;
+import @1.5::CellIdentity;
 import @1.5::CellInfo;
+import @1.5::PersoSubstate;
 import @1.5::RegStateResult;
 import @1.5::SetupDataCallResult;
-import @1.4::SetupDataCallResult;
-import @1.5::PersoSubstate;
 
 /**
  * Interface declaring response functions to solicited radio requests.
@@ -45,6 +45,17 @@
      *
      * Valid errors returned:
      *   RadioError:NONE
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    oneway setLinkCapacityReportingCriteriaResponse_1_5(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
      *   RadioError:SIM_ABSENT
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
@@ -166,6 +177,7 @@
 
     /**
      * @param info Response info struct containing response type, serial no. and error
+     * @param cellIdentity CellIdentity for the barring infos.
      * @param barringInfos a vector of barring info for all barring service types
      *
      * Valid errors returned:
@@ -174,9 +186,11 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:MODEM_ERR
      */
-    oneway getBarringInfoResponse(RadioResponseInfo info, vec<BarringInfo> barringInfos);
+    oneway getBarringInfoResponse(RadioResponseInfo info, CellIdentity cellIdentity,
+            vec<BarringInfo> barringInfos);
 
     /**
+     * @param info Response info struct containing response type, serial no. and error
      * @param voiceRegResponse Current Voice registration response as defined by RegStateResult
      *        in types.hal
      *
@@ -215,7 +229,6 @@
      */
     oneway getCellInfoListResponse_1_5(RadioResponseInfo info, vec<CellInfo> cellInfo);
 
-
     /**
      * @param info Response info struct containing response type, serial no. and error
      *
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index cf195cc..4d3c2d5 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -19,19 +19,15 @@
 import @1.0::ApnAuthType;
 import @1.0::DataProfileId;
 import @1.0::DataProfileInfoType;
-import @1.0::CdmaSignalStrength;
-import @1.0::EvdoSignalStrength;
 import @1.0::GsmSignalStrength;
 import @1.0::LteSignalStrength;
 import @1.0::PersoSubstate;
-import @1.0::RadioAccessFamily;
 import @1.0::RadioError;
 import @1.0::RegState;
 import @1.0::TimeStampType;
 import @1.1::EutranBands;
 import @1.1::GeranBands;
 import @1.1::RadioAccessNetworks;
-import @1.1::RadioAccessSpecifier;
 import @1.1::ScanStatus;
 import @1.1::ScanType;
 import @1.1::UtranBands;
@@ -43,7 +39,6 @@
 import @1.2::CellIdentityLte;
 import @1.2::CellInfoCdma;
 import @1.2::IndicationFilter;
-import @1.2::NetworkScanRequest;
 import @1.2::TdscdmaSignalStrength;
 import @1.2::WcdmaSignalStrength;
 import @1.4::AccessNetwork;
@@ -51,11 +46,11 @@
 import @1.4::CellIdentityNr;
 import @1.4::DataCallFailCause;
 import @1.4::DataConnActiveStatus;
-import @1.4::DataProfileInfo;
 import @1.4::LteVopsInfo;
 import @1.4::NrIndicators;
 import @1.4::NrSignalStrength;
 import @1.4::PdpProtocolType;
+import @1.4::RadioAccessFamily;
 import @1.4::RadioTechnology;
 
 import android.hidl.safe_union@1.0::Monostate;
@@ -131,7 +126,7 @@
     /** Signal Measurement Type */
     SignalMeasurementType signalMeasurement;
 
-    /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis */
+    /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis. */
     int32_t hysteresisMs;
 
     /**
@@ -161,7 +156,8 @@
 
 enum AccessNetwork : @1.4::AccessNetwork {
     /**
-     *  Next-Generation Radio Access Network (NGRAN)
+     * Next-Generation Radio Access Network (NGRAN).
+     * Note NGRAN is only for standalone mode. Non-standalone mode uses AccessNetwork EUTRAN.
      */
     NGRAN = 6,
 };
@@ -175,7 +171,7 @@
 };
 
 /**
- * Overwritten from @1.1::RadioAccessSpecifier to add NGRAN and NgranBands
+ * Overwritten from @1.1::RadioAccessSpecifier to add NGRAN and NgranBands.
  */
 struct RadioAccessSpecifier {
     /**
@@ -264,8 +260,7 @@
 };
 
 /**
- * Overwritten from @1.2::NetworkScanRequest to update
- * RadioAccessSpecifier to 1.5 version
+ * Overwritten from @1.2::NetworkScanRequest to update RadioAccessSpecifier to 1.5 version.
  */
 struct NetworkScanRequest {
     ScanType type;
@@ -328,11 +323,10 @@
 };
 
 /**
- * Extended from @1.4::DataProfileInfo to update ApnTypes to 1.5 version and replace mtu with
+ * Overwritten from @1.4::DataProfileInfo to update ApnTypes to 1.5 version and replace mtu with
  * mtuV4 and mtuV6. In the future, this must be extended instead of overwritten.
  */
 struct DataProfileInfo {
-
     /** ID of the data profile. */
     DataProfileId profileId;
 
@@ -445,8 +439,8 @@
 };
 
 /**
- * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5
- * version. In 1.5 the type of addresses changes to vector of LinkAddress, and mtu is replaced by
+ * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5 version.
+ * In 1.5 the type of addresses changes to vector of LinkAddress, and mtu is replaced by
  * mtuV4 and mtuV6.
  */
 struct SetupDataCallResult {
@@ -687,7 +681,7 @@
     } ratSpecificInfo;
 };
 
-/** A union representing the CellIdentity of a single cell */
+/** A union representing the CellIdentity of a single cell. */
 safe_union CellIdentity {
     Monostate noinit;
 
@@ -699,125 +693,116 @@
     CellIdentityNr nr;
 };
 
-/**
- * Combined list of barring services for UTRAN, EUTRAN, and NGRAN.
- *
- * Barring information is defined in:
- * -UTRAN - 3gpp 25.331 Sec 10.2.48.8.6.
- * -EUTRAN - 3gpp 36.331 Sec 6.3.1 SystemInformationBlockType2
- * -NGRAN - 3gpp 38.331 Sec 6.3.2 UAC-BarringInfo and 22.261 Sec 6.22.2.[2-3]
- */
-enum BarringServiceType : int32_t {
-    /** Applicabe to UTRAN */
-    /** Barring for all CS services, including registration */
-    CS_SERVICE,
-    /** Barring for all PS services, including registration */
-    PS_SERVICE,
-    /** Barring for mobile-originated circuit-switched voice calls */
-    CS_VOICE,
-
-    /** Applicable to EUTRAN, NGRAN */
-    /** Barring for mobile-originated signalling for any purpose */
-    MO_SIGNALLING,
-    /** Barring for mobile-originated internet or other interactive data */
-    MO_DATA,
-    /** Barring for circuit-switched fallback calling */
-    CS_FALLBACK,
-    /** Barring for IMS voice calling */
-    MMTEL_VOICE,
-    /** Barring for IMS video calling */
-    MMTEL_VIDEO,
-
-    /** Applicable to UTRAN, EUTRAN, NGRAN */
-    /** Barring for emergency services, either CS or emergency MMTEL */
-    EMERGENCY,
-    /** Barring for short message services */
-    SMS,
-
-    /** Operator-specific barring codes; applicable to NGRAN */
-    OPERATOR_1 = 1001,
-    OPERATOR_2 = 1002,
-    OPERATOR_3 = 1003,
-    OPERATOR_4 = 1004,
-    OPERATOR_5 = 1005,
-    OPERATOR_6 = 1006,
-    OPERATOR_7 = 1007,
-    OPERATOR_8 = 1008,
-    OPERATOR_9 = 1009,
-    OPERATOR_10 = 1010,
-    OPERATOR_11 = 1011,
-    OPERATOR_12 = 1012,
-    OPERATOR_13 = 1013,
-    OPERATOR_14 = 1014,
-    OPERATOR_15 = 1015,
-    OPERATOR_16 = 1016,
-    OPERATOR_17 = 1017,
-    OPERATOR_18 = 1018,
-    OPERATOR_19 = 1019,
-    OPERATOR_20 = 1020,
-    OPERATOR_21 = 1021,
-    OPERATOR_22 = 1022,
-    OPERATOR_23 = 1023,
-    OPERATOR_24 = 1024,
-    OPERATOR_25 = 1025,
-    OPERATOR_26 = 1026,
-    OPERATOR_27 = 1027,
-    OPERATOR_28 = 1028,
-    OPERATOR_29 = 1029,
-    OPERATOR_30 = 1030,
-    OPERATOR_31 = 1031,
-    OPERATOR_32 = 1032,
-};
-
-enum BarringType : int32_t {
-    /** Device is not barred for the given service */
-    NONE,
-    /** Device may be barred based on time and probability factors */
-    CONDITIONAL,
-    /* Device is unconditionally barred */
-    UNCONDITIONAL,
-};
-
-struct ConditionalBarringInfo {
-    /** The barring factor as a percentage 0-100 */
-    int32_t barringFactor;
-
-    /** The number of seconds between re-evaluations of barring */
-    int32_t barringTimeSeconds;
-
-    /**
-     * Indicates whether barring is currently being applied.
-     *
-     * <p>True if the UE applies barring to a conditionally barred
-     * service based on the conditional barring parameters.
-     *
-     * <p>False if the service is conditionally barred but barring
-     * is not currently applied, which could be due to either the
-     * barring criteria not having been evaluated (if the UE has not
-     * attempted to use the service) or due to the criteria being
-     * evaluated and the UE being permitted to use the service
-     * despite conditional barring.
-     */
-    bool isBarred;
-};
-
-safe_union BarringTypeSpecificInfo {
-    /** Barring type is either none or unconditional */
-    Monostate noinit;
-
-    /** Must be included if barring is conditional */
-    ConditionalBarringInfo conditionalBarringInfo;
-};
-
 struct BarringInfo {
-    /** Barring service */
-    BarringServiceType service;
+    /**
+     * Combined list of barring services for UTRAN, EUTRAN, and NGRAN.
+     *
+     * Barring information is defined in:
+     * -UTRAN - 3gpp 25.331 Sec 10.2.48.8.6.
+     * -EUTRAN - 3gpp 36.331 Sec 6.3.1 SystemInformationBlockType2
+     * -NGRAN - 3gpp 38.331 Sec 6.3.2 UAC-BarringInfo and 22.261 Sec 6.22.2.[2-3]
+     */
+    enum ServiceType : int32_t {
+        /** Applicable to UTRAN */
+        /** Barring for all CS services, including registration */
+        CS_SERVICE,
+        /** Barring for all PS services, including registration */
+        PS_SERVICE,
+        /** Barring for mobile-originated circuit-switched voice calls */
+        CS_VOICE,
+
+        /** Applicable to EUTRAN, NGRAN */
+        /** Barring for mobile-originated signalling for any purpose */
+        MO_SIGNALLING,
+        /** Barring for mobile-originated internet or other interactive data */
+        MO_DATA,
+        /** Barring for circuit-switched fallback calling */
+        CS_FALLBACK,
+        /** Barring for IMS voice calling */
+        MMTEL_VOICE,
+        /** Barring for IMS video calling */
+        MMTEL_VIDEO,
+
+        /** Applicable to UTRAN, EUTRAN, NGRAN */
+        /** Barring for emergency services, either CS or emergency MMTEL */
+        EMERGENCY,
+        /** Barring for short message services */
+        SMS,
+
+        /** Operator-specific barring codes; applicable to NGRAN */
+        OPERATOR_1 = 1001,
+        OPERATOR_2 = 1002,
+        OPERATOR_3 = 1003,
+        OPERATOR_4 = 1004,
+        OPERATOR_5 = 1005,
+        OPERATOR_6 = 1006,
+        OPERATOR_7 = 1007,
+        OPERATOR_8 = 1008,
+        OPERATOR_9 = 1009,
+        OPERATOR_10 = 1010,
+        OPERATOR_11 = 1011,
+        OPERATOR_12 = 1012,
+        OPERATOR_13 = 1013,
+        OPERATOR_14 = 1014,
+        OPERATOR_15 = 1015,
+        OPERATOR_16 = 1016,
+        OPERATOR_17 = 1017,
+        OPERATOR_18 = 1018,
+        OPERATOR_19 = 1019,
+        OPERATOR_20 = 1020,
+        OPERATOR_21 = 1021,
+        OPERATOR_22 = 1022,
+        OPERATOR_23 = 1023,
+        OPERATOR_24 = 1024,
+        OPERATOR_25 = 1025,
+        OPERATOR_26 = 1026,
+        OPERATOR_27 = 1027,
+        OPERATOR_28 = 1028,
+        OPERATOR_29 = 1029,
+        OPERATOR_30 = 1030,
+        OPERATOR_31 = 1031,
+        OPERATOR_32 = 1032,
+    } serviceType;
 
     /** The type of barring applied to the service */
-    BarringType type;
+    enum BarringType : int32_t {
+        /** Device is not barred for the given service */
+        NONE,
+        /** Device may be barred based on time and probability factors */
+        CONDITIONAL,
+        /* Device is unconditionally barred */
+        UNCONDITIONAL,
+    } barringType;
 
     /** Type-specific barring info if applicable */
-    BarringTypeSpecificInfo typeSpecificInfo;
+    safe_union BarringTypeSpecificInfo {
+        /** Barring type is either none or unconditional */
+        Monostate noinit;
+
+        /** Must be included if barring is conditional */
+        struct Conditional {
+            /** The barring factor as a percentage 0-100 */
+            int32_t factor;
+
+            /** The number of seconds between re-evaluations of barring */
+            int32_t timeSeconds;
+
+            /**
+             * Indicates whether barring is currently being applied.
+             *
+             * <p>True if the UE applies barring to a conditionally barred
+             * service based on the conditional barring parameters.
+             *
+             * <p>False if the service is conditionally barred but barring
+             * is not currently applied, which could be due to either the
+             * barring criteria not having been evaluated (if the UE has not
+             * attempted to use the service) or due to the criteria being
+             * evaluated and the UE being permitted to use the service
+             * despite conditional barring.
+             */
+            bool isBarred;
+        } conditional;
+    } barringTypeSpecificInfo;
 };
 
 enum IndicationFilter : @1.2::IndicationFilter {
@@ -963,14 +948,14 @@
     string registeredPlmn;
 
     /**
-     * Access-technology-specific registration information, such as for Cdma2000.
+     * Access-technology-specific registration information, such as for CDMA2000.
      */
     safe_union AccessTechnologySpecificInfo {
         Monostate noinit;
 
         struct Cdma2000RegistrationInfo {
             /**
-             * concurrent services support indicator. if registered on a CDMA system.
+             * Concurrent services support indicator. if registered on a CDMA system.
              * false - Concurrent services not supported,
              * true - Concurrent services supported
              */
@@ -999,10 +984,10 @@
         struct EutranRegistrationInfo {
             /**
              * Network capabilities for voice over PS services. This info is valid only on LTE
-             * network and must be present when device is camped on LTE. vopsInfo must be empty when
+             * network and must be present when device is camped on LTE. VopsInfo must be empty when
              * device is camped only on 2G/3G.
              */
-            LteVopsInfo lteVopsInfo; // LTE network capability
+            LteVopsInfo lteVopsInfo;
 
             /**
              * The parameters of NR 5G Non-Standalone. This value is only valid on E-UTRAN,
@@ -1032,17 +1017,20 @@
 };
 
 /**
- * Additional personalization categories in addition to those specified in 3GPP TS 22.022 and 3GPP2 C.S0068-0.
+ * Additional personalization categories in addition to those specified in 3GPP TS 22.022 and
+ * 3GPP2 C.S0068-0.
  */
 enum PersoSubstate : @1.0::PersoSubstate {
     SIM_SPN,
     SIM_SPN_PUK,
-    SIM_SP_EHPLMN,              // Equivalent Home PLMN
+    /** Equivalent Home PLMN */
+    SIM_SP_EHPLMN,
     SIM_SP_EHPLMN_PUK,
     SIM_ICCID,
     SIM_ICCID_PUK,
     SIM_IMPI,
     SIM_IMPI_PUK,
-    SIM_NS_SP,                  // Network subset service provider
+    /** Network subset service provider */
+    SIM_NS_SP,
     SIM_NS_SP_PUK,
 };
diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp
index 182985e..85c4f99 100644
--- a/radio/1.5/vts/functional/Android.bp
+++ b/radio/1.5/vts/functional/Android.bp
@@ -34,7 +34,6 @@
         "android.hardware.radio@1.0",
         "android.hardware.radio.config@1.0",
         "android.hardware.radio.config@1.1",
-        "android.hardware.radio.config@1.3",
     ],
     header_libs: ["radio.util.header@1.0"],
     test_suites: ["general-tests"]
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 09305de..435bd23 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -310,6 +310,99 @@
 }
 
 /*
+ * Test IRadio.setLinkCapacityReportingCriteria_1_5() invalid hysteresisDlKbps
+ */
+TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisDlKbps) {
+    serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_5->setLinkCapacityReportingCriteria_1_5(
+            serial, 5000,
+            5000,  // hysteresisDlKbps too big for thresholds delta
+            100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000},
+            ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setLinkCapacityReportingCriteria_1_5_invalidHysteresisDlKbps, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria_1_5() may not be supported
+    // for GERAN
+    ASSERT_TRUE(
+            CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                             {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+}
+
+/*
+ * Test IRadio.setLinkCapacityReportingCriteria_1_5() invalid hysteresisUlKbps
+ */
+TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisUlKbps) {
+    serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_5->setLinkCapacityReportingCriteria_1_5(
+            serial, 5000, 500,
+            1000,  // hysteresisUlKbps too big for thresholds delta
+            {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000},
+            ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setLinkCapacityReportingCriteria_1_5_invalidHysteresisUlKbps, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria_1_5() may not be supported
+    // for GERAN
+    ASSERT_TRUE(
+            CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                             {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+}
+
+/*
+ * Test IRadio.setLinkCapacityReportingCriteria_1_5() empty params
+ */
+TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_emptyParams) {
+    serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_5->setLinkCapacityReportingCriteria_1_5(
+            serial, 0, 0, 0, {}, {}, ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setLinkCapacityReportingCriteria_1_5_emptyParams, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria_1_5() may not be supported
+    // for GERAN
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+}
+
+/*
+ * Test IRadio.setLinkCapacityReportingCriteria_1_5() for GERAN
+ */
+TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_Geran) {
+    serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_5->setLinkCapacityReportingCriteria_1_5(
+            serial, 5000, 500, 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000},
+            ::android::hardware::radio::V1_5::AccessNetwork::GERAN);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ALOGI("setLinkCapacityReportingCriteria_1_5_Geran, rspInfo.error = %s\n",
+          toString(radioRsp_v1_5->rspInfo.error).c_str());
+    // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria_1_5() may not be supported
+    // for GERAN
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+}
+
+/*
  * Test IRadio.enableUiccApplications() for the response returned.
  * For SIM ABSENT case.
  */
@@ -969,7 +1062,10 @@
     }
 }
 
-TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancalled) {
+/*
+ * Test IRadio.setRadioPower_1_5() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancelled) {
     // Set radio power to off.
     serial = GetRandomSerialNumber();
     radio_v1_5->setRadioPower_1_5(serial, false, false, false);
@@ -1066,3 +1162,110 @@
                 CHECK_GENERAL_ERROR));
     }
 }
+
+/*
+ * Test IRadio.getBarringInfo() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, getBarringInfo) {
+    serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_5->getBarringInfo(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ASSERT_TRUE(radioRsp_v1_5->barringInfos.size() > 0);
+
+    std::set<BarringInfo::ServiceType> reportedServices;
+
+    // validate that the service types are in range
+    for (const auto& info : radioRsp_v1_5->barringInfos) {
+        ASSERT_TRUE((info.serviceType >= BarringInfo::ServiceType::CS_SERVICE &&
+                     info.serviceType <= BarringInfo::ServiceType::SMS) ||
+                    (info.serviceType >= BarringInfo::ServiceType::OPERATOR_1 &&
+                     info.serviceType <= BarringInfo::ServiceType::OPERATOR_32));
+        reportedServices.insert(info.serviceType);
+
+        // Any type that is "conditional" must have sane values for conditional barring
+        // factor and time.
+        switch (info.barringType) {
+            case BarringInfo::BarringType::NONE:  // fall through
+            case BarringInfo::BarringType::UNCONDITIONAL:
+                break;
+            case BarringInfo::BarringType::CONDITIONAL: {
+                const int32_t barringFactor = info.barringTypeSpecificInfo.conditional().factor;
+                ASSERT_TRUE(barringFactor >= 0 && barringFactor <= 100);
+                ASSERT_TRUE(info.barringTypeSpecificInfo.conditional().timeSeconds > 0);
+                break;
+            }
+            default:
+                FAIL();
+        }
+    }
+
+    // Certain types of barring are relevant for certain RANs. Ensure that only the right
+    // types are reported. Note that no types are required, simply that for a given technology
+    // only certain types are valid. This is one way to sanity check that implementations are
+    // not providing information that they don't have.
+    static const std::set<BarringInfo::ServiceType> UTRA_SERVICES{
+            BarringInfo::ServiceType::CS_SERVICE, BarringInfo::ServiceType::PS_SERVICE,
+            BarringInfo::ServiceType::CS_VOICE,   BarringInfo::ServiceType::EMERGENCY,
+            BarringInfo::ServiceType::SMS,
+    };
+
+    static const std::set<BarringInfo::ServiceType> EUTRA_SERVICES{
+            BarringInfo::ServiceType::MO_SIGNALLING, BarringInfo::ServiceType::MO_DATA,
+            BarringInfo::ServiceType::CS_FALLBACK,   BarringInfo::ServiceType::MMTEL_VOICE,
+            BarringInfo::ServiceType::MMTEL_VIDEO,   BarringInfo::ServiceType::EMERGENCY,
+            BarringInfo::ServiceType::SMS,
+    };
+
+    static const std::set<BarringInfo::ServiceType> NGRA_SERVICES = {
+            BarringInfo::ServiceType::MO_SIGNALLING, BarringInfo::ServiceType::MO_DATA,
+            BarringInfo::ServiceType::CS_FALLBACK,   BarringInfo::ServiceType::MMTEL_VOICE,
+            BarringInfo::ServiceType::MMTEL_VIDEO,   BarringInfo::ServiceType::EMERGENCY,
+            BarringInfo::ServiceType::SMS,           BarringInfo::ServiceType::OPERATOR_1,
+            BarringInfo::ServiceType::OPERATOR_2,    BarringInfo::ServiceType::OPERATOR_3,
+            BarringInfo::ServiceType::OPERATOR_4,    BarringInfo::ServiceType::OPERATOR_5,
+            BarringInfo::ServiceType::OPERATOR_6,    BarringInfo::ServiceType::OPERATOR_7,
+            BarringInfo::ServiceType::OPERATOR_8,    BarringInfo::ServiceType::OPERATOR_9,
+            BarringInfo::ServiceType::OPERATOR_10,   BarringInfo::ServiceType::OPERATOR_11,
+            BarringInfo::ServiceType::OPERATOR_12,   BarringInfo::ServiceType::OPERATOR_13,
+            BarringInfo::ServiceType::OPERATOR_14,   BarringInfo::ServiceType::OPERATOR_15,
+            BarringInfo::ServiceType::OPERATOR_16,   BarringInfo::ServiceType::OPERATOR_17,
+            BarringInfo::ServiceType::OPERATOR_18,   BarringInfo::ServiceType::OPERATOR_19,
+            BarringInfo::ServiceType::OPERATOR_20,   BarringInfo::ServiceType::OPERATOR_21,
+            BarringInfo::ServiceType::OPERATOR_22,   BarringInfo::ServiceType::OPERATOR_23,
+            BarringInfo::ServiceType::OPERATOR_24,   BarringInfo::ServiceType::OPERATOR_25,
+            BarringInfo::ServiceType::OPERATOR_26,   BarringInfo::ServiceType::OPERATOR_27,
+            BarringInfo::ServiceType::OPERATOR_28,   BarringInfo::ServiceType::OPERATOR_29,
+            BarringInfo::ServiceType::OPERATOR_30,   BarringInfo::ServiceType::OPERATOR_31,
+    };
+
+    const std::set<BarringInfo::ServiceType>* compareTo = nullptr;
+
+    switch (radioRsp_v1_5->barringCellIdentity.getDiscriminator()) {
+        case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::wcdma:
+            // fall through
+        case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::tdscdma:
+            compareTo = &UTRA_SERVICES;
+            break;
+        case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::lte:
+            compareTo = &EUTRA_SERVICES;
+            break;
+        case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::nr:
+            compareTo = &NGRA_SERVICES;
+            break;
+
+        case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::cdma:
+            // fall through
+        default:
+            FAIL();
+            break;
+    }
+
+    std::set<BarringInfo::ServiceType> diff;
+
+    std::set_difference(reportedServices.begin(), reportedServices.end(), compareTo->begin(),
+                        compareTo->end(), std::inserter(diff, diff.begin()));
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
index c29ebf9..a5d236d 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
@@ -47,9 +47,9 @@
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
     EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
 
-    sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig =
+    sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig =
             ::testing::VtsHalHidlTargetTestBase::getService<
-                    ::android::hardware::radio::config::V1_3::IRadioConfig>();
+                    ::android::hardware::radio::config::V1_1::IRadioConfig>();
 
     /* Enforce Vts tesing with RadioConfig is existed. */
     ASSERT_NE(nullptr, radioConfig.get());
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index d1c17e6..a7c1cdc 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -22,7 +22,7 @@
 #include <condition_variable>
 #include <mutex>
 
-#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <android/hardware/radio/config/1.1/IRadioConfig.h>
 
 #include <android/hardware/radio/1.5/IRadio.h>
 #include <android/hardware/radio/1.5/IRadioIndication.h>
@@ -86,6 +86,10 @@
     // Whether Uicc applications are enabled or not.
     bool areUiccApplicationsEnabled;
 
+    // Barring Info Response
+    ::android::hardware::radio::V1_5::CellIdentity barringCellIdentity;
+    ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo> barringInfos;
+
     RadioResponse_v1_5(RadioHidlTest_v1_5& parent_v1_5);
     virtual ~RadioResponse_v1_5() = default;
 
@@ -114,9 +118,6 @@
     Return<void> supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info,
                                                         int32_t remainingRetries);
 
-    Return<void> supplySimDepersonalizationResponse(const RadioResponseInfo& info,
-            ::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries);
-
     Return<void> getCurrentCallsResponse(
             const RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& calls);
@@ -534,6 +535,8 @@
     /* 1.5 Api */
     Return<void> setSignalStrengthReportingCriteriaResponse_1_5(const RadioResponseInfo& info);
 
+    Return<void> setLinkCapacityReportingCriteriaResponse_1_5(const RadioResponseInfo& info);
+
     Return<void> enableUiccApplicationsResponse(const RadioResponseInfo& info);
 
     Return<void> areUiccApplicationsEnabledResponse(const RadioResponseInfo& info, bool enabled);
@@ -559,6 +562,7 @@
 
     Return<void> getBarringInfoResponse(
             const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>&
                     barringInfos);
 
@@ -579,6 +583,10 @@
 
     Return<void> sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info,
                                                const SendSmsResult& sms);
+
+    Return<void> supplySimDepersonalizationResponse(
+            const RadioResponseInfo& info,
+            ::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries);
 };
 
 /* Callback class for radio indication */
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index a62d086..e4f9ce8 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -62,13 +62,6 @@
     return Void();
 }
 
-Return<void> RadioResponse_v1_5::supplySimDepersonalizationResponse(
-        const RadioResponseInfo& /*info*/,
-        ::android::hardware::radio::V1_5::PersoSubstate /*persoType*/,
-        int32_t /*remainingRetries*/) {
-    return Void();
-}
-
 Return<void> RadioResponse_v1_5::getCurrentCallsResponse(
         const RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) {
@@ -901,6 +894,13 @@
     return Void();
 }
 
+Return<void> RadioResponse_v1_5::setLinkCapacityReportingCriteriaResponse_1_5(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
 Return<void> RadioResponse_v1_5::enableUiccApplicationsResponse(const RadioResponseInfo& info) {
     rspInfo = info;
     parent_v1_5.notify(info.serial);
@@ -970,8 +970,11 @@
 
 Return<void> RadioResponse_v1_5::getBarringInfoResponse(
         const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity,
         const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>&
-        /*barringInfos*/) {
+                barringInfos) {
+    this->barringCellIdentity = cellIdentity;
+    this->barringInfos = barringInfos;
     rspInfo = info;
     parent_v1_5.notify(info.serial);
     return Void();
@@ -1011,3 +1014,10 @@
                                                                const SendSmsResult& /*sms*/) {
     return Void();
 }
+
+Return<void> RadioResponse_v1_5::supplySimDepersonalizationResponse(
+        const RadioResponseInfo& /*info*/,
+        ::android::hardware::radio::V1_5::PersoSubstate /*persoType*/,
+        int32_t /*remainingRetries*/) {
+    return Void();
+}
diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp
deleted file mode 100644
index 7360270..0000000
--- a/radio/config/1.3/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-hidl_interface {
-    name: "android.hardware.radio.config@1.3",
-    root: "android.hardware",
-    vndk: {
-        enabled: true,
-    },
-    srcs: [
-        "types.hal",
-        "IRadioConfig.hal",
-        "IRadioConfigIndication.hal",
-        "IRadioConfigResponse.hal",
-    ],
-    interfaces: [
-        "android.hardware.radio.config@1.0",
-        "android.hardware.radio.config@1.1",
-        "android.hardware.radio.config@1.2",
-        "android.hardware.radio@1.0",
-        "android.hardware.radio@1.1",
-        "android.hardware.radio@1.4",
-        "android.hardware.radio@1.5",
-        "android.hidl.base@1.0",
-    ],
-    gen_java: true,
-}
diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal
deleted file mode 100644
index d01f54b..0000000
--- a/radio/config/1.3/IRadioConfig.hal
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.radio.config@1.3;
-
-import @1.1::IRadioConfig;
-
-/**
- * This interface is used by telephony and telecom to talk to cellular radio for the purpose of
- * radio configuration, and it is not associated with any specific modem or slot.
- * All the functions have minimum one parameter:
- * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
- * duration of a method call. If clients provide colliding serials (including passing the same
- * serial to different methods), multiple responses (one for each method call) must still be served.
- */
-interface IRadioConfig extends @1.1::IRadioConfig {
-    /**
-     * Request current phone capability.
-     *
-     * @param serial Serial number of request.
-     *
-     * Response callback is IRadioResponse.getPhoneCapabilityResponse_1_3() which
-     * will return <@1.3::PhoneCapability>.
-     */
-    oneway getPhoneCapability_1_3(int32_t serial);
-};
diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal
deleted file mode 100644
index e13aa1e..0000000
--- a/radio/config/1.3/IRadioConfigResponse.hal
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.radio.config@1.3;
-
-import android.hardware.radio@1.0::RadioResponseInfo;
-import @1.2::IRadioConfigResponse;
-import @1.3::PhoneCapability;
-
-/**
- * Interface declaring response functions to solicited radio config requests.
- */
-interface IRadioConfigResponse extends @1.2::IRadioConfigResponse {
-    /**
-     * @param info Response info struct containing response type, serial no. and error
-     * @param phoneCapability <@1.3::PhoneCapability> it defines modem's capability for example
-     *        how many logical modems it has, how many data connections it supports.
-     *
-     * Valid errors returned:
-     *   RadioError:NONE
-     *   RadioError:RADIO_NOT_AVAILABLE
-     */
-    oneway getPhoneCapabilityResponse_1_3(RadioResponseInfo info, PhoneCapability phoneCapability);
-};
diff --git a/radio/config/1.3/default/Android.bp b/radio/config/1.3/default/Android.bp
deleted file mode 100644
index 163c5c5..0000000
--- a/radio/config/1.3/default/Android.bp
+++ /dev/null
@@ -1,28 +0,0 @@
-cc_binary {
-    name: "android.hardware.radio.config@1.3-service",
-    init_rc: ["android.hardware.radio.config@1.3-service.rc"],
-    relative_install_path: "hw",
-    vintf_fragments: ["radio-config-default.xml"],
-    vendor: true,
-    srcs: [
-        "RadioConfig.cpp",
-        "RadioConfigIndication.cpp",
-        "RadioConfigResponse.cpp",
-        "service.cpp",
-    ],
-    shared_libs: [
-        "libhidlbase",
-        "liblog",
-        "libutils",
-        "android.hardware.radio.config@1.0",
-        "android.hardware.radio.config@1.1",
-        "android.hardware.radio.config@1.2",
-        "android.hardware.radio.config@1.3",
-        "android.hardware.radio@1.0",
-        "android.hardware.radio@1.1",
-        "android.hardware.radio@1.2",
-        "android.hardware.radio@1.3",
-        "android.hardware.radio@1.4",
-        "android.hardware.radio@1.5",
-    ],
-}
diff --git a/radio/config/1.3/default/RadioConfig.cpp b/radio/config/1.3/default/RadioConfig.cpp
deleted file mode 100644
index 01e98f1..0000000
--- a/radio/config/1.3/default/RadioConfig.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.1 (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.1
- *
- * 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 "RadioConfig.h"
-
-namespace android {
-namespace hardware {
-namespace radio {
-namespace config {
-namespace V1_3 {
-namespace implementation {
-
-using namespace ::android::hardware::radio::V1_0;
-
-// Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow.
-Return<void> RadioConfig::setResponseFunctions(
-        const sp<V1_0::IRadioConfigResponse>& radioConfigResponse,
-        const sp<V1_0::IRadioConfigIndication>& radioConfigIndication) {
-    mRadioConfigResponse = radioConfigResponse;
-    mRadioConfigIndication = radioConfigIndication;
-
-    mRadioConfigResponseV1_3 =
-            V1_3::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
-    mRadioConfigIndicationV1_3 =
-            V1_3::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
-    if (mRadioConfigResponseV1_3 == nullptr || mRadioConfigIndicationV1_3 == nullptr) {
-        mRadioConfigResponseV1_3 = nullptr;
-        mRadioConfigIndicationV1_3 = nullptr;
-    }
-
-    mRadioConfigResponseV1_2 =
-            V1_2::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
-    mRadioConfigIndicationV1_2 =
-            V1_2::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
-    if (mRadioConfigResponseV1_2 == nullptr || mRadioConfigIndicationV1_2 == nullptr) {
-        mRadioConfigResponseV1_2 = nullptr;
-        mRadioConfigIndicationV1_2 = nullptr;
-    }
-
-    mRadioConfigResponseV1_1 =
-            V1_1::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
-    mRadioConfigIndicationV1_1 =
-            V1_1::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
-    if (mRadioConfigResponseV1_1 == nullptr || mRadioConfigIndicationV1_1 == nullptr) {
-        mRadioConfigResponseV1_1 = nullptr;
-        mRadioConfigIndicationV1_1 = nullptr;
-    }
-
-    return Void();
-}
-
-Return<void> RadioConfig::getSimSlotsStatus(int32_t /* serial */) {
-    hidl_vec<V1_0::SimSlotStatus> slotStatus;
-    RadioResponseInfo info;
-    mRadioConfigResponse->getSimSlotsStatusResponse(info, slotStatus);
-    return Void();
-}
-
-Return<void> RadioConfig::setSimSlotsMapping(int32_t /* serial */,
-                                             const hidl_vec<uint32_t>& /* slotMap */) {
-    RadioResponseInfo info;
-    mRadioConfigResponse->setSimSlotsMappingResponse(info);
-    return Void();
-}
-
-// Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow.
-Return<void> RadioConfig::getPhoneCapability(int32_t /* serial */) {
-    V1_1::PhoneCapability phoneCapability;
-    RadioResponseInfo info;
-    mRadioConfigResponseV1_1->getPhoneCapabilityResponse(info, phoneCapability);
-    return Void();
-}
-
-Return<void> RadioConfig::setPreferredDataModem(int32_t /* serial */, uint8_t /* modemId */) {
-    RadioResponseInfo info;
-    mRadioConfigResponseV1_1->setPreferredDataModemResponse(info);
-    return Void();
-}
-
-Return<void> RadioConfig::setModemsConfig(int32_t /* serial */,
-                                          const V1_1::ModemsConfig& /* modemsConfig */) {
-    RadioResponseInfo info;
-    mRadioConfigResponseV1_1->setModemsConfigResponse(info);
-    return Void();
-}
-
-Return<void> RadioConfig::getModemsConfig(int32_t /* serial */) {
-    V1_1::ModemsConfig modemsConfig;
-    RadioResponseInfo info;
-    mRadioConfigResponseV1_1->getModemsConfigResponse(info, modemsConfig);
-    return Void();
-}
-
-// Methods from ::android::hardware::radio::config::V1_3::IRadioConfig follow.
-Return<void> RadioConfig::getPhoneCapability_1_3(int32_t /* serial */) {
-    V1_3::PhoneCapability phoneCapability;
-    RadioResponseInfo info;
-    mRadioConfigResponseV1_3->getPhoneCapabilityResponse_1_3(info, phoneCapability);
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace config
-}  // namespace radio
-}  // namespace hardware
-}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfig.h b/radio/config/1.3/default/RadioConfig.h
deleted file mode 100644
index 57ff368..0000000
--- a/radio/config/1.3/default/RadioConfig.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.1 (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.1
- *
- * 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_RADIO_CONFIG_V1_3_RADIOCONFIG_H
-#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H
-
-#include <android/hardware/radio/config/1.3/IRadioConfig.h>
-#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
-#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace radio {
-namespace config {
-namespace V1_3 {
-namespace implementation {
-
-using namespace ::android::hardware::radio::config;
-
-using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-struct RadioConfig : public V1_3::IRadioConfig {
-    sp<V1_0::IRadioConfigResponse> mRadioConfigResponse;
-    sp<V1_0::IRadioConfigIndication> mRadioConfigIndication;
-    sp<V1_1::IRadioConfigResponse> mRadioConfigResponseV1_1;
-    sp<V1_1::IRadioConfigIndication> mRadioConfigIndicationV1_1;
-    sp<V1_2::IRadioConfigResponse> mRadioConfigResponseV1_2;
-    sp<V1_2::IRadioConfigIndication> mRadioConfigIndicationV1_2;
-    sp<V1_3::IRadioConfigResponse> mRadioConfigResponseV1_3;
-    sp<V1_3::IRadioConfigIndication> mRadioConfigIndicationV1_3;
-
-    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow.
-    Return<void> setResponseFunctions(
-            const sp<V1_0::IRadioConfigResponse>& radioConfigResponse,
-            const sp<V1_0::IRadioConfigIndication>& radioConfigIndication);
-    Return<void> getSimSlotsStatus(int32_t serial);
-    Return<void> setSimSlotsMapping(int32_t serial, const hidl_vec<uint32_t>& slotMap);
-
-    // Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow.
-    Return<void> getPhoneCapability(int32_t serial);
-    Return<void> setPreferredDataModem(int32_t serial, uint8_t modemId);
-    Return<void> setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig);
-    Return<void> getModemsConfig(int32_t serial);
-
-    // Methods from ::android::hardware::radio::config::V1_3::IRadioConfig follow.
-    Return<void> getPhoneCapability_1_3(int32_t serial);
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace config
-}  // namespace radio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H
diff --git a/radio/config/1.3/default/RadioConfigIndication.cpp b/radio/config/1.3/default/RadioConfigIndication.cpp
deleted file mode 100644
index 608fa1c..0000000
--- a/radio/config/1.3/default/RadioConfigIndication.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.1 (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.1
- *
- * 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 "RadioConfigIndication.h"
-
-namespace android {
-namespace hardware {
-namespace radio {
-namespace config {
-namespace V1_3 {
-namespace implementation {
-
-// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow.
-Return<void> RadioConfigIndication::simSlotsStatusChanged(
-        RadioIndicationType /* type */, const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
-    // TODO implement
-    return Void();
-}
-
-// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow.
-Return<void> RadioConfigIndication::simSlotsStatusChanged_1_2(
-        RadioIndicationType /* type */, const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
-    // TODO implement
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace config
-}  // namespace radio
-}  // namespace hardware
-}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfigIndication.h b/radio/config/1.3/default/RadioConfigIndication.h
deleted file mode 100644
index c92446c..0000000
--- a/radio/config/1.3/default/RadioConfigIndication.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.1 (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.1
- *
- * 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_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
-#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
-
-#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace radio {
-namespace config {
-namespace V1_3 {
-namespace implementation {
-
-using namespace ::android::hardware::radio::V1_0;
-using namespace ::android::hardware::radio::config;
-
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-struct RadioConfigIndication : public IRadioConfigIndication {
-    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow.
-    Return<void> simSlotsStatusChanged(RadioIndicationType type,
-                                       const hidl_vec<V1_0::SimSlotStatus>& slotStatus) override;
-
-    // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow.
-    Return<void> simSlotsStatusChanged_1_2(
-            RadioIndicationType type, const hidl_vec<V1_2::SimSlotStatus>& slotStatus) override;
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace config
-}  // namespace radio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
diff --git a/radio/config/1.3/default/RadioConfigResponse.cpp b/radio/config/1.3/default/RadioConfigResponse.cpp
deleted file mode 100644
index 1d48a13..0000000
--- a/radio/config/1.3/default/RadioConfigResponse.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.1 (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.1
- *
- * 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 "RadioConfigResponse.h"
-
-namespace android {
-namespace hardware {
-namespace radio {
-namespace config {
-namespace V1_3 {
-namespace implementation {
-
-// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
-Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
-        const RadioResponseInfo& /* info */,
-        const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
-    // TODO implement
-    return Void();
-}
-
-Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) {
-    // TODO implement
-    return Void();
-}
-
-// Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow.
-Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
-        const RadioResponseInfo& /* info */, const V1_1::PhoneCapability& /* phoneCapability */) {
-    // TODO implement
-    return Void();
-}
-
-Return<void> RadioConfigResponse::setPreferredDataModemResponse(
-        const RadioResponseInfo& /* info */) {
-    // TODO implement
-    return Void();
-}
-
-Return<void> RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) {
-    // TODO implement
-    return Void();
-}
-
-Return<void> RadioConfigResponse::getModemsConfigResponse(
-        const RadioResponseInfo& /* info */, const V1_1::ModemsConfig& /* modemsConfig */) {
-    // TODO implement
-    return Void();
-}
-
-// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow.
-Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
-        const RadioResponseInfo& /* info */,
-        const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
-    // TODO implement
-    return Void();
-}
-
-// Methods from ::android::hardware::radio::config::V1_3::IRadioConfigResponse follow.
-Return<void> RadioConfigResponse::getPhoneCapabilityResponse_1_3(
-        const RadioResponseInfo& /* info */, const V1_3::PhoneCapability& /* phoneCapability */) {
-    // TODO implement
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace config
-}  // namespace radio
-}  // namespace hardware
-}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfigResponse.h b/radio/config/1.3/default/RadioConfigResponse.h
deleted file mode 100644
index dc169bb..0000000
--- a/radio/config/1.3/default/RadioConfigResponse.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.1 (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.1
- *
- * 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_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
-#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
-
-#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace radio {
-namespace config {
-namespace V1_3 {
-namespace implementation {
-
-using namespace ::android::hardware::radio::config;
-
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-
-using ::android::hardware::radio::V1_0::RadioResponseInfo;
-
-struct RadioConfigResponse : public IRadioConfigResponse {
-    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
-    Return<void> getSimSlotsStatusResponse(
-            const RadioResponseInfo& info,
-            const hidl_vec<V1_0::SimSlotStatus>& slotStatus) override;
-    Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info) override;
-
-    // Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow.
-    Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
-                                            const V1_1::PhoneCapability& phoneCapability) override;
-    Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info) override;
-    Return<void> setModemsConfigResponse(const RadioResponseInfo& info) override;
-    Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
-                                         const V1_1::ModemsConfig& modemsConfig) override;
-
-    // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow.
-    Return<void> getSimSlotsStatusResponse_1_2(
-            const RadioResponseInfo& info,
-            const hidl_vec<V1_2::SimSlotStatus>& slotStatus) override;
-
-    // Methods from ::android::hardware::radio::config::V1_3::IRadioConfigResponse follow.
-    Return<void> getPhoneCapabilityResponse_1_3(
-            const RadioResponseInfo& info, const V1_3::PhoneCapability& phoneCapability) override;
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace config
-}  // namespace radio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
diff --git a/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc b/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc
deleted file mode 100644
index 6df9b52..0000000
--- a/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc
+++ /dev/null
@@ -1,7 +0,0 @@
-service vendor.radio-config-hal-1-3 /vendor/bin/hw/android.hardware.radio.config@1.3-service
-    interface android.hardware.radio.config@1.0::IRadioConfig default
-    interface android.hardware.radio.config@1.1::IRadioConfig default
-    interface android.hardware.radio.config@1.3::IRadioConfig default
-    class hal
-    user system
-    group system
diff --git a/radio/config/1.3/default/radio-config-default.xml b/radio/config/1.3/default/radio-config-default.xml
deleted file mode 100644
index 72f363e..0000000
--- a/radio/config/1.3/default/radio-config-default.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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.
-*/
--->
-<manifest version="1.0" type="device">
-    <hal format="hidl">
-        <name>android.hardware.radio.config</name>
-        <transport>hwbinder</transport>
-        <version>1.3</version>
-        <interface>
-            <name>IRadioConfig</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</manifest>
diff --git a/radio/config/1.3/default/service.cpp b/radio/config/1.3/default/service.cpp
deleted file mode 100644
index b1e6736..0000000
--- a/radio/config/1.3/default/service.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.1 (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.1
- *
- * 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 "android.hardware.radio.config@1.3-service"
-
-#include <android/hardware/radio/config/1.3/IRadioConfig.h>
-#include <hidl/HidlTransportSupport.h>
-
-#include "RadioConfig.h"
-
-using android::OK;
-using android::sp;
-using android::status_t;
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-using android::hardware::radio::config::V1_3::IRadioConfig;
-using android::hardware::radio::config::V1_3::implementation::RadioConfig;
-
-int main() {
-    configureRpcThreadpool(1, true);
-    sp<IRadioConfig> radioConfig = new RadioConfig;
-    const status_t status = radioConfig->registerAsService();
-    ALOGW_IF(status != OK, "Could not register IRadioConfig 1.3");
-    ALOGD("Default service is ready.");
-
-    joinRpcThreadpool();
-    return 1;
-}
diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal
deleted file mode 100644
index 7860006..0000000
--- a/radio/config/1.3/types.hal
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.radio.config@1.3;
-
-import android.hardware.radio@1.1::GeranBands;
-import android.hardware.radio@1.1::EutranBands;
-import android.hardware.radio@1.4::RadioAccessFamily;
-import android.hardware.radio@1.5::NgranBands;
-import android.hardware.radio@1.5::UtranBands;
-
-/** Type for the SIM slot. */
-enum SlotType : int32_t {
-    /** Slot type for UICC/pSIM (physical SIM). */
-    UICC       = 1,
-    /** Slot type for iUICC/iSIM (integrated SIM). */
-    IUICC      = 2,
-    /** Slot type for eUICC/eSIM (embedded SIM). */
-    EUICC      = 3,
-    /** Slot type for soft SIM (no physical SIM). */
-    SOFT_SIM   = 4,
-};
-
-/** A field in PhoneCapability that holds information about the SIM slot. */
-struct SimSlotCapability {
-    /** Corresponds to physicalSlotId in Radio@1.2::CardStatus. */
-    uint32_t physicalSlotId;
-
-    /** Type of slot. */
-    SlotType slotType;
-};
-
-/** Bitmask of features that can be supported by a single modem. */
-enum ModemFeatures : int32_t {
-    /** 3GPP2 capability. */
-    THREE_GPP2_REG            = 1 << 0,
-    /** 3GPP capability. */
-    THREE_GPP_REG             = 1 << 1,
-    /** CDMA 2000 with EHRPD capability. */
-    CDMA2000_EHRPD_REG        = 1 << 2,
-    /** GSM capability. */
-    GERAN_REG                 = 1 << 3,
-    /** UMTS capability. */
-    UTRAN_REG                 = 1 << 4,
-    /** LTE capability. */
-    EUTRAN_REG                = 1 << 5,
-    /** 5G capability. */
-    NGRAN_REG                 = 1 << 6,
-    /** Dual Connectivity capability. */
-    EN_DC_REG                 = 1 << 7,
-    /** VoLTE capability (IMS registered). */
-    PS_VOICE_REG              = 1 << 8,
-    /** CS voice call capability. */
-    CS_VOICE_SESSION          = 1 << 9,
-    /** Internet connection capability. */
-    INTERACTIVE_DATA_SESSION  = 1 << 10,
-    /** Dedicated bearer capability. */
-    DEDICATED_BEARER          = 1 << 11,
-    /** Network scanning capability. */
-    NETWORK_SCAN              = 1 << 12,
-    /** CDMA capability for SIM associated with modem. */
-    CSIM                      = 1 << 13,
-};
-
-struct ConcurrentModemFeatures {
-    /**
-     * A vector of concurrently supportable modem features across all modems.
-     * Each entry in the vector is a bitfield of ModemFeatures that can be used
-     * concurrently with the other ModemFeatures in that list.
-     * Each bitfield must be the full set of features for a single modem.
-     *
-     * On a Dual-SIM device, each entry will be a vector of length 2.
-     * The examples below depict the modemFeatures for four Dual-SIM setups:
-     * 1. Only one modem can PS attach (IMS registered).
-     *    {
-     *        (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
-     *            CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
-     *        (GERAN_REG | UTRAN_REG)
-     *    }
-     *    or
-     *    {
-     *        (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
-     *            INTERACTIVE_DATA_SESSION),
-     *        (GERAN_REG | UTRAN_REG | CS_VOICE_SESSION)
-     *    }
-     * 2. Both modems can PS attach (dual VoLTE).
-     *    {
-     *        (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
-     *            CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
-     *        (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG)
-     *    }
-     * 3. Both modems can maintain an Internet connection, but they share
-     *    one RF hardware.
-     *    {
-     *        (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
-     *            CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
-     *        (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
-     *            INTERACTIVE_DATA_SESSION)
-     *    }
-     * 4. Both modems can maintain an Internet connection, and they have
-     *    their own RF hardware.
-     *    {
-     *        (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
-     *            CS_VOICE_SESSION | INTERACTIVE_DATA_SESSION | DEDICATED_BEARER),
-     *        (GERAN_REG | UTRAN_REG | EUTRAN_REG | PS_VOICE_REG |
-     *            INTERACTIVE_DATA_SESSION | DEDICATED_BEARER)
-     *    }
-     */
-    vec<bitfield<ModemFeatures>> modemFeatures;
-};
-
-/**
- * Overwritten from @1.1::PhoneCapability to add new capabilities and deprecate
- * maxActiveData, maxActiveInternetData, isInternetLingeringSupported, logicalModemList.
- * Replaces RadioConfig@1.1::ModemInfo and should replace Radio@1.4::RadioCapabilities
- * in the next major version upgrade. In the future, this should be extended instead of overwritten.
- */
-struct PhoneCapability {
-    /**
-     * 3GPP UE category for UTRAN downlink direction.
-     * 25.306 Table 5.1a
-     */
-    uint8_t utranUeCategoryDl;
-    /**
-     * 3GPP UE category for UTRAN uplink direction.
-     * 25.306 Table 5.1g
-     */
-    uint8_t utranUeCategoryUl;
-    /**
-     * 3GPP UE category for EUTRAN downlink direction.
-     * 25.306 Table 4.1a
-     */
-    uint8_t eutranUeCategoryDl;
-    /**
-     * 3GPP UE category for EUTRAN uplink direction.
-     * 25.306 Table 4.1a-2
-     */
-    uint8_t eutranUeCategoryUl;
-
-    /**
-     * Length of grace period for switching between logical modems, in milliseconds.
-     * Used only when the number of logical modems is greater than the number of
-     * Internet connections the device can support, otherwise must be 0.
-     */
-    uint64_t psDataConnectionLingerTimeMillis;
-
-    vec<GeranBands> geranBands;
-    vec<UtranBands> utranBands;
-    vec<EutranBands> eutranBands;
-    vec<NgranBands> ngranBands;
-
-    /**
-     * 32-bit bitmap of supported Radio@1.4::RadioAccessFamily types.
-     * Note that RadioAccessFamily is actually the radio access technologies, so it should be
-     * renamed in the next major version upgrade.
-     */
-    bitfield<RadioAccessFamily> supportedRats;
-
-    /**
-     * List of unique logical modem UUIDs from Radio@1.4::RadioCapabilities.
-     * A UUID is typically "com.xxxx.lmX" where X is the logical modem ID.
-     * Must be equal to the number of logical modems in the device.
-     * Radio@1.2::RadioConst::MAX_UUID_LENGTH is the max length of each UUID.
-     */
-    vec<string> logicalModemUuids;
-
-    /**
-     * List of SIM slot capabilities. The order of physical slot IDs must correspond to
-     * the order of modems in logicalModemUuids.
-     */
-    vec<SimSlotCapability> simSlotCapabilities;
-
-    /**
-     * A vector of all sets of concurrently supportable modem feature sets. The order of modems
-     * in modemFeatures must correspond to the order of modems in logicalModemUuids.
-     * Each entry in concurrentFeatureSupport is independent of others in the list
-     * and represents a set of concurrently supportable features across all modems.
-     * Each entry in ConcurrentModemFeatures::modemFeatures is a bitfield of
-     * concurrently supported ModemFeatures for one modem.
-     */
-    vec<ConcurrentModemFeatures> concurrentFeatureSupport;
-};
diff --git a/radio/config/1.3/vts/functional/Android.bp b/radio/config/1.3/vts/functional/Android.bp
deleted file mode 100644
index 6b28faf..0000000
--- a/radio/config/1.3/vts/functional/Android.bp
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_test {
-    name: "VtsHalRadioConfigV1_3TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
-    srcs: [
-        "radio_config_hidl_hal_api.cpp",
-        "radio_config_hidl_hal_test.cpp",
-        "radio_config_response.cpp",
-        "VtsHalRadioConfigV1_3TargetTest.cpp",
-    ],
-    static_libs: [
-        "RadioVtsTestUtilBase",
-        "android.hardware.radio.config@1.0",
-        "android.hardware.radio.config@1.1",
-        "android.hardware.radio.config@1.2",
-        "android.hardware.radio.config@1.3",
-    ],
-    header_libs: ["radio.util.header@1.0"],
-    test_suites: ["general-tests", "vts-core"],
-}
diff --git a/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
deleted file mode 100644
index 3bacacf..0000000
--- a/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <radio_config_hidl_hal_utils.h>
-
-INSTANTIATE_TEST_SUITE_P(
-        PerInstance, RadioConfigHidlTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
-                ::android::hardware::radio::config::V1_3::IRadioConfig::descriptor)),
-        android::hardware::PrintInstanceNameToString);
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
deleted file mode 100644
index 7f90023..0000000
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <radio_config_hidl_hal_utils.h>
-
-#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
-
-/*
- * Test IRadioConfig.getPhoneCapability_1_3()
- */
-TEST_P(RadioConfigHidlTest, getPhoneCapability_1_3) {
-    serial = GetRandomSerialNumber();
-    Return<void> res = radioConfig->getPhoneCapability_1_3(serial);
-    ASSERT_OK(res);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
-    EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
-    ALOGI("getPhoneCapability_1_3, rspInfo.error = %s\n",
-          toString(radioConfigRsp->rspInfo.error).c_str());
-
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioConfigRsp->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR}));
-
-    if (radioConfigRsp->rspInfo.error == RadioError ::NONE) {
-        int numModems = radioConfigRsp->phoneCap_1_3.logicalModemUuids.size();
-        EXPECT_GE(numModems, 0);
-        // length of simSlotCapabilities should be equal to length of logicalModemUuids.
-        EXPECT_EQ(numModems, radioConfigRsp->phoneCap_1_3.simSlotCapabilities.size());
-        // length of modemFeatures in each ConcurrentModemFeatures should be
-        // equal to length of logicalModemUuids.
-        for (V1_3::ConcurrentModemFeatures cmf :
-             radioConfigRsp->phoneCap_1_3.concurrentFeatureSupport) {
-            EXPECT_EQ(numModems, cmf.modemFeatures.size());
-        }
-    }
-}
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
deleted file mode 100644
index cd48b25..0000000
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <radio_config_hidl_hal_utils.h>
-
-void RadioConfigHidlTest::SetUp() {
-    radioConfig = V1_3::IRadioConfig::getService(GetParam());
-    ASSERT_NE(nullptr, radioConfig.get());
-
-    radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
-    ASSERT_NE(nullptr, radioConfigRsp.get());
-
-    count_ = 0;
-
-    radioConfig->setResponseFunctions(radioConfigRsp, nullptr);
-}
-
-/*
- * Notify that the response message is received.
- */
-void RadioConfigHidlTest::notify(int receivedSerial) {
-    std::unique_lock<std::mutex> lock(mtx_);
-    if (serial == receivedSerial) {
-        count_++;
-        cv_.notify_one();
-    }
-}
-
-/*
- * Wait till the response message is notified or till TIMEOUT_PERIOD.
- */
-std::cv_status RadioConfigHidlTest::wait() {
-    std::unique_lock<std::mutex> lock(mtx_);
-
-    std::cv_status status = std::cv_status::no_timeout;
-    auto now = std::chrono::system_clock::now();
-    while (count_ == 0) {
-        status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
-        if (status == std::cv_status::timeout) {
-            return status;
-        }
-    }
-    count_--;
-    return status;
-}
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
deleted file mode 100644
index b21c7c0..0000000
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-
-#include <chrono>
-#include <condition_variable>
-#include <mutex>
-
-#include <android/hardware/radio/config/1.3/IRadioConfig.h>
-#include <android/hardware/radio/config/1.3/IRadioConfigIndication.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>
-#include <log/log.h>
-
-#include "vts_test_util.h"
-
-using namespace ::android::hardware::radio::config;
-
-using ::android::sp;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-using ::android::hardware::radio::V1_0::RadioIndicationType;
-using ::android::hardware::radio::V1_0::RadioResponseInfo;
-using ::android::hardware::radio::V1_0::RadioResponseType;
-
-#define TIMEOUT_PERIOD 75
-
-class RadioConfigHidlTest;
-
-/* Callback class for radio config response */
-class RadioConfigResponse : public V1_3::IRadioConfigResponse {
-  protected:
-    RadioConfigHidlTest& parent;
-
-  public:
-    RadioResponseInfo rspInfo;
-    V1_1::PhoneCapability phoneCap_1_1;
-    V1_3::PhoneCapability phoneCap_1_3;
-
-    RadioConfigResponse(RadioConfigHidlTest& parent);
-    virtual ~RadioConfigResponse() = default;
-
-    /* 1.0 Api */
-    Return<void> getSimSlotsStatusResponse(const RadioResponseInfo& info,
-                                           const hidl_vec<V1_0::SimSlotStatus>& slotStatus);
-
-    Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info);
-
-    /* 1.1 Api */
-    Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
-                                            const V1_1::PhoneCapability& phoneCapability);
-
-    Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info);
-
-    Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
-                                         const V1_1::ModemsConfig& mConfig);
-
-    Return<void> setModemsConfigResponse(const RadioResponseInfo& info);
-
-    /* 1.2 Api */
-    Return<void> getSimSlotsStatusResponse_1_2(const RadioResponseInfo& info,
-                                               const hidl_vec<V1_2::SimSlotStatus>& slotStatus);
-
-    /* 1.3 Api */
-    Return<void> getPhoneCapabilityResponse_1_3(const RadioResponseInfo& info,
-                                                const V1_3::PhoneCapability& phoneCapability);
-};
-
-/* Callback class for radio config indication */
-class RadioConfigIndication : public V1_3::IRadioConfigIndication {
-  protected:
-    RadioConfigHidlTest& parent;
-
-  public:
-    RadioConfigIndication(RadioConfigHidlTest& parent);
-    virtual ~RadioConfigIndication() = default;
-
-    /* 1.2 Api */
-    Return<void> simSlotsStatusChanged_1_2(RadioIndicationType type,
-                                           const hidl_vec<V1_2::SimSlotStatus>& slotStatus);
-};
-
-// The main test class for Radio config HIDL.
-class RadioConfigHidlTest : public ::testing::TestWithParam<std::string> {
-  protected:
-    std::mutex mtx_;
-    std::condition_variable cv_;
-    int count_;
-
-  public:
-    virtual void SetUp() override;
-
-    /* Used as a mechanism to inform the test about data/event callback */
-    void notify(int receivedSerial);
-
-    /* Test code calls this function to wait for response */
-    std::cv_status wait();
-
-    void updateSimCardStatus();
-
-    /* Serial number for radio request */
-    int serial;
-
-    /* radio config service handle */
-    sp<V1_3::IRadioConfig> radioConfig;
-
-    /* radio config response handle */
-    sp<RadioConfigResponse> radioConfigRsp;
-};
diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp
deleted file mode 100644
index 22098d3..0000000
--- a/radio/config/1.3/vts/functional/radio_config_response.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <radio_config_hidl_hal_utils.h>
-
-using namespace ::android::hardware::radio::config;
-
-using ::android::hardware::hidl_vec;
-
-using ::android::hardware::radio::V1_0::RadioResponseInfo;
-
-RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {}
-
-/* 1.0 Apis */
-Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
-        const RadioResponseInfo& /* info */,
-        const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
-    return Void();
-}
-
-Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) {
-    return Void();
-}
-
-/* 1.1 Apis */
-Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
-        const RadioResponseInfo& info, const V1_1::PhoneCapability& phoneCapability) {
-    rspInfo = info;
-    phoneCap_1_1 = phoneCapability;
-    parent.notify(info.serial);
-    return Void();
-}
-
-Return<void> RadioConfigResponse::setPreferredDataModemResponse(
-        const RadioResponseInfo& /* info */) {
-    return Void();
-}
-
-Return<void> RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */,
-                                                          const V1_1::ModemsConfig& /* mConfig */) {
-    return Void();
-}
-
-Return<void> RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) {
-    return Void();
-}
-
-/* 1.2 Apis */
-Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
-        const RadioResponseInfo& /* info */,
-        const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
-    return Void();
-}
-
-/* 1.3 Apis */
-Return<void> RadioConfigResponse::getPhoneCapabilityResponse_1_3(
-        const RadioResponseInfo& info, const V1_3::PhoneCapability& phoneCapability) {
-    rspInfo = info;
-    phoneCap_1_3 = phoneCapability;
-    parent.notify(info.serial);
-    return Void();
-}
diff --git a/rebootescrow/aidl/default/RebootEscrow.cpp b/rebootescrow/aidl/default/RebootEscrow.cpp
index 94d0901..dbc0921 100644
--- a/rebootescrow/aidl/default/RebootEscrow.cpp
+++ b/rebootescrow/aidl/default/RebootEscrow.cpp
@@ -29,7 +29,7 @@
 using ::android::base::unique_fd;
 
 ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector<int8_t>& kek) {
-    int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
+    int rawFd = TEMP_FAILURE_RETRY(::open(devicePath_.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
     unique_fd fd(rawFd);
     if (fd.get() < 0) {
         LOG(WARNING) << "Could not open reboot escrow device";
@@ -48,20 +48,19 @@
 }
 
 ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector<int8_t>* _aidl_return) {
-    int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+    int rawFd = TEMP_FAILURE_RETRY(::open(devicePath_.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
     unique_fd fd(rawFd);
     if (fd.get() < 0) {
         LOG(WARNING) << "Could not open reboot escrow device";
         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
     }
 
-    std::string encodedString;
-    if (!::android::base::ReadFdToString(fd, &encodedString)) {
-        LOG(WARNING) << "Could not read device to string";
+    std::vector<uint8_t> encodedBytes(hadamard::OUTPUT_SIZE_BYTES);
+    if (!::android::base::ReadFully(fd, &encodedBytes[0], encodedBytes.size())) {
+        LOG(WARNING) << "Could not read device";
         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
     }
 
-    std::vector<uint8_t> encodedBytes(encodedString.begin(), encodedString.end());
     auto keyBytes = hadamard::DecodeKey(encodedBytes);
 
     std::vector<int8_t> signedKeyBytes(keyBytes.begin(), keyBytes.end());
diff --git a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
index 1ed7397..00ff16b 100644
--- a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
+++ b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
@@ -23,11 +23,14 @@
 namespace hardware {
 namespace rebootescrow {
 
-static const char* REBOOT_ESCROW_DEVICE = "/dev/access-kregistry";
-
 class RebootEscrow : public BnRebootEscrow {
+  public:
+    explicit RebootEscrow(const std::string& devicePath) : devicePath_(devicePath) {}
     ndk::ScopedAStatus storeKey(const std::vector<int8_t>& kek) override;
     ndk::ScopedAStatus retrieveKey(std::vector<int8_t>* _aidl_return) override;
+
+  private:
+    const std::string devicePath_;
 };
 
 }  // namespace rebootescrow
diff --git a/rebootescrow/aidl/default/service.cpp b/rebootescrow/aidl/default/service.cpp
index bd2378e..8a8086b 100644
--- a/rebootescrow/aidl/default/service.cpp
+++ b/rebootescrow/aidl/default/service.cpp
@@ -17,15 +17,21 @@
 #include "rebootescrow-impl/RebootEscrow.h"
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
 using aidl::android::hardware::rebootescrow::RebootEscrow;
 
+constexpr auto kRebootEscrowDeviceProperty = "ro.rebootescrow.device";
+constexpr auto kRebootEscrowDeviceDefault = "/dev/access-kregistry";
+
 int main() {
     ABinderProcess_setThreadPoolMaxThreadCount(0);
 
-    auto re = ndk::SharedRefBase::make<RebootEscrow>();
+    auto rebootEscrowDevicePath =
+            android::base::GetProperty(kRebootEscrowDeviceProperty, kRebootEscrowDeviceDefault);
+    auto re = ndk::SharedRefBase::make<RebootEscrow>(rebootEscrowDevicePath);
     const std::string instance = std::string() + RebootEscrow::descriptor + "/default";
     binder_status_t status = AServiceManager_addService(re->asBinder().get(), instance.c_str());
     CHECK(status == STATUS_OK);
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 1167fd4..aaefccb 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -20,7 +20,7 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "SensorsHidlEnvironmentV1_0.cpp",
-        "VtsHalSensorsV1_0TargetTest.cpp"
+        "VtsHalSensorsV1_0TargetTest.cpp",
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
@@ -31,6 +31,8 @@
         "android.hardware.sensors@1.0",
         "VtsHalSensorsTargetTestUtils",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
-
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
index 29bfa50..485ed1e 100644
--- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
@@ -29,8 +29,9 @@
 using ::android::sp;
 
 class SensorsHidlTest;
-class SensorsHidlEnvironmentV1_0 : public SensorsHidlEnvironmentBase {
-   public:
+class SensorsHidlEnvironmentV1_0
+    : public SensorsHidlEnvironmentBase<::android::hardware::sensors::V1_0::Event> {
+  public:
     using Event = ::android::hardware::sensors::V1_0::Event;
     SensorsHidlEnvironmentV1_0(const std::string& service_name)
         : SensorsHidlEnvironmentBase(service_name) {}
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
index 2cad54d..e298651 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -33,8 +33,7 @@
 using namespace ::android::hardware::sensors::V1_0;
 
 // The main test class for SENSORS HIDL HAL.
-
-class SensorsHidlTest : public SensorsHidlTestBase {
+class SensorsHidlTest : public SensorsHidlTestBase<SensorType, Event, SensorInfo> {
   public:
     virtual void SetUp() override {
         mEnvironment = new SensorsHidlEnvironmentV1_0(GetParam());
@@ -80,7 +79,7 @@
 
     inline sp<ISensors>& S() { return mEnvironment->sensors; }
 
-    SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; }
+    SensorsHidlEnvironmentBase<Event>* getEnvironment() override { return mEnvironment; }
 
   private:
     // Test environment for sensors HAL.
@@ -257,55 +256,55 @@
 // Test if sensor hal can do UI speed accelerometer streaming properly
 TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
     testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), sAccelNormChecker);
+                           std::chrono::seconds(5), mAccelNormChecker);
 }
 
 // Test if sensor hal can do normal speed accelerometer streaming properly
 TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
     testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), sAccelNormChecker);
+                           std::chrono::seconds(5), mAccelNormChecker);
 }
 
 // Test if sensor hal can do game speed accelerometer streaming properly
 TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) {
     testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), sAccelNormChecker);
+                           std::chrono::seconds(5), mAccelNormChecker);
 }
 
 // Test if sensor hal can do UI speed gyroscope streaming properly
 TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
     testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), sGyroNormChecker);
+                           std::chrono::seconds(5), mGyroNormChecker);
 }
 
 // Test if sensor hal can do normal speed gyroscope streaming properly
 TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
     testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), sGyroNormChecker);
+                           std::chrono::seconds(5), mGyroNormChecker);
 }
 
 // Test if sensor hal can do game speed gyroscope streaming properly
 TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) {
     testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), sGyroNormChecker);
+                           std::chrono::seconds(5), mGyroNormChecker);
 }
 
 // Test if sensor hal can do UI speed magnetometer streaming properly
 TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
     testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), NullChecker());
+                           std::chrono::seconds(5), NullChecker<Event>());
 }
 
 // Test if sensor hal can do normal speed magnetometer streaming properly
 TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
     testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), NullChecker());
+                           std::chrono::seconds(5), NullChecker<Event>());
 }
 
 // Test if sensor hal can do game speed magnetometer streaming properly
 TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) {
     testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), NullChecker());
+                           std::chrono::seconds(5), NullChecker<Event>());
 }
 
 // Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
@@ -344,109 +343,109 @@
 // Test sensor event direct report with ashmem for accel sensor at normal rate
 TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              sAccelNormChecker);
+                              mAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for accel sensor at fast rate
 TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
-                              sAccelNormChecker);
+                              mAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for accel sensor at very fast rate
 TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM,
-                              RateLevel::VERY_FAST, sAccelNormChecker);
+                              RateLevel::VERY_FAST, mAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at normal rate
 TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at fast rate
 TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at very fast rate
 TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for mag sensor at normal rate
 TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              NullChecker());
+                              NullChecker<Event>());
 }
 
 // Test sensor event direct report with ashmem for mag sensor at fast rate
 TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
-                              NullChecker());
+                              NullChecker<Event>());
 }
 
 // Test sensor event direct report with ashmem for mag sensor at very fast rate
 TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM,
-                              RateLevel::VERY_FAST, NullChecker());
+                              RateLevel::VERY_FAST, NullChecker<Event>());
 }
 
 // Test sensor event direct report with gralloc for accel sensor at normal rate
 TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              sAccelNormChecker);
+                              mAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for accel sensor at fast rate
 TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
-                              sAccelNormChecker);
+                              mAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for accel sensor at very fast rate
 TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC,
-                              RateLevel::VERY_FAST, sAccelNormChecker);
+                              RateLevel::VERY_FAST, mAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at normal rate
 TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at fast rate
 TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at very fast rate
 TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for mag sensor at normal rate
 TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              NullChecker());
+                              NullChecker<Event>());
 }
 
 // Test sensor event direct report with gralloc for mag sensor at fast rate
 TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
-                              NullChecker());
+                              NullChecker<Event>());
 }
 
 // Test sensor event direct report with gralloc for mag sensor at very fast rate
 TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC,
-                              RateLevel::VERY_FAST, NullChecker());
+                              RateLevel::VERY_FAST, NullChecker<Event>());
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/sensors/2.0/default/Android.bp b/sensors/2.0/default/Android.bp
index 62c9487..bb38327 100644
--- a/sensors/2.0/default/Android.bp
+++ b/sensors/2.0/default/Android.bp
@@ -20,13 +20,17 @@
     relative_install_path: "hw",
     srcs: [
         "service.cpp",
-        "Sensor.cpp",
-        "Sensors.cpp",
     ],
     init_rc: ["android.hardware.sensors@2.0-service-mock.rc"],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
     shared_libs: [
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
+        // Needed to compile some shared utilities for both 2.0/2.1 impls, but
+        // isn't normally needed for a HAL that only supports 2.0.
+        "android.hardware.sensors@2.1",
         "libcutils",
         "libfmq",
         "libhidlbase",
@@ -34,5 +38,9 @@
         "libpower",
         "libutils",
     ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.X-shared-impl",
+    ],
     vintf_fragments: ["android.hardware.sensors@2.0.xml"],
 }
diff --git a/sensors/2.0/default/Sensors.cpp b/sensors/2.0/default/Sensors.cpp
deleted file mode 100644
index 23dd26b..0000000
--- a/sensors/2.0/default/Sensors.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2018 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 "Sensors.h"
-
-#include <android/hardware/sensors/2.0/types.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::sensors::V1_0::Event;
-using ::android::hardware::sensors::V1_0::OperationMode;
-using ::android::hardware::sensors::V1_0::RateLevel;
-using ::android::hardware::sensors::V1_0::Result;
-using ::android::hardware::sensors::V1_0::SharedMemInfo;
-using ::android::hardware::sensors::V2_0::SensorTimeout;
-using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
-
-constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP";
-
-Sensors::Sensors()
-    : mEventQueueFlag(nullptr),
-      mNextHandle(1),
-      mOutstandingWakeUpEvents(0),
-      mReadWakeLockQueueRun(false),
-      mAutoReleaseWakeLockTime(0),
-      mHasWakeLock(false) {
-    AddSensor<AccelSensor>();
-    AddSensor<GyroSensor>();
-    AddSensor<AmbientTempSensor>();
-    AddSensor<DeviceTempSensor>();
-    AddSensor<PressureSensor>();
-    AddSensor<MagnetometerSensor>();
-    AddSensor<LightSensor>();
-    AddSensor<ProximitySensor>();
-    AddSensor<RelativeHumiditySensor>();
-}
-
-Sensors::~Sensors() {
-    deleteEventFlag();
-    mReadWakeLockQueueRun = false;
-    mWakeLockThread.join();
-}
-
-// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
-Return<void> Sensors::getSensorsList(getSensorsList_cb _hidl_cb) {
-    std::vector<SensorInfo> sensors;
-    for (const auto& sensor : mSensors) {
-        sensors.push_back(sensor.second->getSensorInfo());
-    }
-
-    // Call the HIDL callback with the SensorInfo
-    _hidl_cb(sensors);
-
-    return Void();
-}
-
-Return<Result> Sensors::setOperationMode(OperationMode mode) {
-    for (auto sensor : mSensors) {
-        sensor.second->setOperationMode(mode);
-    }
-    return Result::OK;
-}
-
-Return<Result> Sensors::activate(int32_t sensorHandle, bool enabled) {
-    auto sensor = mSensors.find(sensorHandle);
-    if (sensor != mSensors.end()) {
-        sensor->second->activate(enabled);
-        return Result::OK;
-    }
-    return Result::BAD_VALUE;
-}
-
-Return<Result> Sensors::initialize(
-    const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
-    const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
-    const sp<ISensorsCallback>& sensorsCallback) {
-    Result result = Result::OK;
-
-    // Ensure that all sensors are disabled
-    for (auto sensor : mSensors) {
-        sensor.second->activate(false /* enable */);
-    }
-
-    // Stop the Wake Lock thread if it is currently running
-    if (mReadWakeLockQueueRun.load()) {
-        mReadWakeLockQueueRun = false;
-        mWakeLockThread.join();
-    }
-
-    // Save a reference to the callback
-    mCallback = sensorsCallback;
-
-    // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
-    mEventQueue =
-        std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
-
-    // Ensure that any existing EventFlag is properly deleted
-    deleteEventFlag();
-
-    // Create the EventFlag that is used to signal to the framework that sensor events have been
-    // written to the Event FMQ
-    if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
-        result = Result::BAD_VALUE;
-    }
-
-    // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
-    // events have been successfully read and handled by the framework.
-    mWakeLockQueue =
-        std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
-
-    if (!mCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
-        result = Result::BAD_VALUE;
-    }
-
-    // Start the thread to read events from the Wake Lock FMQ
-    mReadWakeLockQueueRun = true;
-    mWakeLockThread = std::thread(startReadWakeLockThread, this);
-
-    return result;
-}
-
-Return<Result> Sensors::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
-                              int64_t /* maxReportLatencyNs */) {
-    auto sensor = mSensors.find(sensorHandle);
-    if (sensor != mSensors.end()) {
-        sensor->second->batch(samplingPeriodNs);
-        return Result::OK;
-    }
-    return Result::BAD_VALUE;
-}
-
-Return<Result> Sensors::flush(int32_t sensorHandle) {
-    auto sensor = mSensors.find(sensorHandle);
-    if (sensor != mSensors.end()) {
-        return sensor->second->flush();
-    }
-    return Result::BAD_VALUE;
-}
-
-Return<Result> Sensors::injectSensorData(const Event& event) {
-    auto sensor = mSensors.find(event.sensorHandle);
-    if (sensor != mSensors.end()) {
-        return sensor->second->injectEvent(event);
-    }
-
-    return Result::BAD_VALUE;
-}
-
-Return<void> Sensors::registerDirectChannel(const SharedMemInfo& /* mem */,
-                                            registerDirectChannel_cb _hidl_cb) {
-    _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
-    return Return<void>();
-}
-
-Return<Result> Sensors::unregisterDirectChannel(int32_t /* channelHandle */) {
-    return Result::INVALID_OPERATION;
-}
-
-Return<void> Sensors::configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */,
-                                         RateLevel /* rate */, configDirectReport_cb _hidl_cb) {
-    _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
-    return Return<void>();
-}
-
-void Sensors::postEvents(const std::vector<Event>& events, bool wakeup) {
-    std::lock_guard<std::mutex> lock(mWriteLock);
-    if (mEventQueue->write(events.data(), events.size())) {
-        mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
-
-        if (wakeup) {
-            // Keep track of the number of outstanding WAKE_UP events in order to properly hold
-            // a wake lock until the framework has secured a wake lock
-            updateWakeLock(events.size(), 0 /* eventsHandled */);
-        }
-    }
-}
-
-void Sensors::updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) {
-    std::lock_guard<std::mutex> lock(mWakeLockLock);
-    int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled;
-    if (newVal < 0) {
-        mOutstandingWakeUpEvents = 0;
-    } else {
-        mOutstandingWakeUpEvents = newVal;
-    }
-
-    if (eventsWritten > 0) {
-        // Update the time at which the last WAKE_UP event was sent
-        mAutoReleaseWakeLockTime = ::android::uptimeMillis() +
-                                   static_cast<uint32_t>(SensorTimeout::WAKE_LOCK_SECONDS) * 1000;
-    }
-
-    if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 &&
-        acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) {
-        mHasWakeLock = true;
-    } else if (mHasWakeLock) {
-        // Check if the wake lock should be released automatically if
-        // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written to
-        // the Wake Lock FMQ.
-        if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) {
-            ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock",
-                  SensorTimeout::WAKE_LOCK_SECONDS);
-            mOutstandingWakeUpEvents = 0;
-        }
-
-        if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) {
-            mHasWakeLock = false;
-        }
-    }
-}
-
-void Sensors::readWakeLockFMQ() {
-    while (mReadWakeLockQueueRun.load()) {
-        constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000;  // 500 ms
-        uint32_t eventsHandled = 0;
-
-        // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to ensure
-        // that any held wake lock is able to be released if it is held for too long.
-        mWakeLockQueue->readBlocking(&eventsHandled, 1 /* count */, 0 /* readNotification */,
-                                     static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN),
-                                     kReadTimeoutNs);
-        updateWakeLock(0 /* eventsWritten */, eventsHandled);
-    }
-}
-
-void Sensors::startReadWakeLockThread(Sensors* sensors) {
-    sensors->readWakeLockFMQ();
-}
-
-void Sensors::deleteEventFlag() {
-    status_t status = EventFlag::deleteEventFlag(&mEventQueueFlag);
-    if (status != OK) {
-        ALOGI("Failed to delete event flag: %d", status);
-    }
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
diff --git a/sensors/2.0/default/Sensors.h b/sensors/2.0/default/Sensors.h
deleted file mode 100644
index d06dd78..0000000
--- a/sensors/2.0/default/Sensors.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2018 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_SENSORS_V2_0_SENSORS_H
-#define ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H
-
-#include "Sensor.h"
-
-#include <android/hardware/sensors/2.0/ISensors.h>
-#include <fmq/MessageQueue.h>
-#include <hardware_legacy/power.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include <atomic>
-#include <memory>
-#include <thread>
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::hardware::EventFlag;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::MessageQueue;
-using ::android::hardware::MQDescriptor;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-struct Sensors : public ISensors, public ISensorsEventCallback {
-    using Event = ::android::hardware::sensors::V1_0::Event;
-    using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
-    using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
-    using Result = ::android::hardware::sensors::V1_0::Result;
-    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
-
-    Sensors();
-    virtual ~Sensors();
-
-    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
-    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
-
-    Return<Result> setOperationMode(OperationMode mode) override;
-
-    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
-
-    Return<Result> initialize(
-        const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
-        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
-        const sp<ISensorsCallback>& sensorsCallback) override;
-
-    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
-                         int64_t maxReportLatencyNs) override;
-
-    Return<Result> flush(int32_t sensorHandle) override;
-
-    Return<Result> injectSensorData(const Event& event) override;
-
-    Return<void> registerDirectChannel(const SharedMemInfo& mem,
-                                       registerDirectChannel_cb _hidl_cb) override;
-
-    Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
-
-    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
-                                    configDirectReport_cb _hidl_cb) override;
-
-    void postEvents(const std::vector<Event>& events, bool wakeup) override;
-
-   private:
-    /**
-     * Add a new sensor
-     */
-    template <class SensorType>
-    void AddSensor() {
-        std::shared_ptr<SensorType> sensor =
-                std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
-        mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
-    }
-
-    /**
-     * Utility function to delete the Event Flag
-     */
-    void deleteEventFlag();
-
-    /**
-     * Function to read the Wake Lock FMQ and release the wake lock when appropriate
-     */
-    void readWakeLockFMQ();
-
-    static void startReadWakeLockThread(Sensors* sensors);
-
-    /**
-     * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events
-     */
-    void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled);
-
-    using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
-    using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
-
-    /**
-     * The Event FMQ where sensor events are written
-     */
-    std::unique_ptr<EventMessageQueue> mEventQueue;
-
-    /**
-     * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
-     */
-    std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
-
-    /**
-     * Event Flag to signal to the framework when sensor events are available to be read
-     */
-    EventFlag* mEventQueueFlag;
-
-    /**
-     * Callback for asynchronous events, such as dynamic sensor connections.
-     */
-    sp<ISensorsCallback> mCallback;
-
-    /**
-     * A map of the available sensors
-     */
-    std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
-
-    /**
-     * The next available sensor handle
-     */
-    int32_t mNextHandle;
-
-    /**
-     * Lock to protect writes to the FMQs
-     */
-    std::mutex mWriteLock;
-
-    /**
-     * Lock to protect acquiring and releasing the wake lock
-     */
-    std::mutex mWakeLockLock;
-
-    /**
-     * Track the number of WAKE_UP events that have not been handled by the framework
-     */
-    uint32_t mOutstandingWakeUpEvents;
-
-    /**
-     * A thread to read the Wake Lock FMQ
-     */
-    std::thread mWakeLockThread;
-
-    /**
-     * Flag to indicate that the Wake Lock Thread should continue to run
-     */
-    std::atomic_bool mReadWakeLockQueueRun;
-
-    /**
-     * Track the time when the wake lock should automatically be released
-     */
-    int64_t mAutoReleaseWakeLockTime;
-
-    /**
-     * Flag to indicate if a wake lock has been acquired
-     */
-    bool mHasWakeLock;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H
diff --git a/sensors/2.0/default/SensorsV2_0.h b/sensors/2.0/default/SensorsV2_0.h
new file mode 100644
index 0000000..345835a
--- /dev/null
+++ b/sensors/2.0/default/SensorsV2_0.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_0_H
+#define ANDROID_HARDWARE_SENSORS_V2_0_H
+
+#include "Sensors.h"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+struct SensorsV2_0 : public ::android::hardware::sensors::V2_X::implementation::Sensors<ISensors> {
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_0_H
\ No newline at end of file
diff --git a/sensors/2.0/default/service.cpp b/sensors/2.0/default/service.cpp
index 5c13e33..e20bf85 100644
--- a/sensors/2.0/default/service.cpp
+++ b/sensors/2.0/default/service.cpp
@@ -20,17 +20,17 @@
 #include <hidl/HidlTransportSupport.h>
 #include <log/log.h>
 #include <utils/StrongPointer.h>
-#include "Sensors.h"
+#include "SensorsV2_0.h"
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::sensors::V2_0::ISensors;
-using android::hardware::sensors::V2_0::implementation::Sensors;
+using android::hardware::sensors::V2_0::implementation::SensorsV2_0;
 
 int main(int /* argc */, char** /* argv */) {
     configureRpcThreadpool(1, true);
 
-    android::sp<ISensors> sensors = new Sensors();
+    android::sp<ISensors> sensors = new SensorsV2_0();
     if (sensors->registerAsService() != ::android::OK) {
         ALOGE("Failed to register Sensors HAL instance");
         return -1;
diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp
index 811c455..24c475c 100644
--- a/sensors/2.0/multihal/Android.bp
+++ b/sensors/2.0/multihal/Android.bp
@@ -46,7 +46,7 @@
     ],
     init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
     vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
-    shared_libs: ["android.hardware.sensors@2.0-ScopedWakelock"]
+    shared_libs: ["android.hardware.sensors@2.0-ScopedWakelock"],
 }
 
 cc_library_headers {
@@ -66,8 +66,8 @@
     ],
     vendor_available: true,
     export_header_lib_headers: [
-        "android.hardware.sensors@2.0-multihal.header"
-    ]
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
 }
 
 // The below targets should only be used for testing.
@@ -85,7 +85,7 @@
         "android.hardware.sensors@2.0-multihal.header",
     ],
     export_shared_lib_headers: [
-	"android.hardware.sensors@2.0-ScopedWakelock",
+        "android.hardware.sensors@2.0-ScopedWakelock",
     ],
     shared_libs: [
         "libutils",
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
index 7c52661..ac6f17a 100644
--- a/sensors/2.0/multihal/HalProxy.cpp
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -290,6 +290,8 @@
     stream << "  Wakelock ref count: " << mWakelockRefCount << std::endl;
     stream << "  # of events on pending write writes queue: " << mSizePendingWriteEventsQueue
            << std::endl;
+    stream << " Most events seen on pending write events queue: "
+           << mMostEventsObservedPendingWriteEventsQueue << std::endl;
     if (!mPendingWriteEventsQueue.empty()) {
         stream << "  Size of events list on front of pending writes queue: "
                << mPendingWriteEventsQueue.front().first.size() << std::endl;
@@ -571,6 +573,8 @@
         std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
         mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
         mSizePendingWriteEventsQueue += numLeft;
+        mMostEventsObservedPendingWriteEventsQueue =
+                std::max(mMostEventsObservedPendingWriteEventsQueue, mSizePendingWriteEventsQueue);
         mEventQueueWriteCV.notify_one();
     }
 }
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
index ce28e67..978f7cf 100644
--- a/sensors/2.0/multihal/include/HalProxy.h
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -200,6 +200,9 @@
      */
     std::queue<std::pair<std::vector<Event>, size_t>> mPendingWriteEventsQueue;
 
+    //! The most events observed on the pending write events queue for debug purposes.
+    size_t mMostEventsObservedPendingWriteEventsQueue = 0;
+
     //! The max number of events allowed in the pending write events queue
     static constexpr size_t kMaxSizePendingWriteEventsQueue = 100000;
 
diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp
index 1637312..a9feaf7 100644
--- a/sensors/2.0/multihal/tests/Android.bp
+++ b/sensors/2.0/multihal/tests/Android.bp
@@ -25,7 +25,7 @@
     shared_libs: [
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
-	"android.hardware.sensors@2.0-ScopedWakelock",
+        "android.hardware.sensors@2.0-ScopedWakelock",
         "libcutils",
         "libfmq",
         "libhardware",
@@ -38,7 +38,7 @@
         "android.hardware.sensors@2.0-HalProxy",
     ],
     cflags: [
-        "-DLOG_TAG=\"FakeSubHal\""
+        "-DLOG_TAG=\"FakeSubHal\"",
     ],
 }
 
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
index 4765fa2..08c59b6 100644
--- a/sensors/2.0/vts/functional/Android.bp
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -19,8 +19,10 @@
     cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "SensorsHidlEnvironmentV2_0.cpp",
-        "VtsHalSensorsV2_0TargetTest.cpp"
+        "VtsHalSensorsV2_0TargetTest.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
@@ -29,9 +31,15 @@
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
+        "android.hardware.sensors@1.0-convert",
         "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
         "libfmq",
         "VtsHalSensorsTargetTestUtils",
+        "VtsHalSensorsV2_0TargetTest-lib",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
     ],
 }
-
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index c5eb442..8895350 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -14,1130 +14,19 @@
  * limitations under the License.
  */
 
-#include "SensorsHidlEnvironmentV2_0.h"
-#include "sensors-vts-utils/SensorsHidlTestBase.h"
-#include "sensors-vts-utils/SensorsTestSharedMemory.h"
+#include "VtsHalSensorsV2_XTargetTest.h"
 
-#include <android/hardware/sensors/2.0/ISensors.h>
-#include <android/hardware/sensors/2.0/types.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
-#include <log/log.h>
-#include <utils/SystemClock.h>
-
-#include <cinttypes>
-#include <condition_variable>
-#include <cstring>
-#include <map>
-#include <vector>
-
-using ::android::sp;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::sensors::V1_0::MetaDataEventType;
-using ::android::hardware::sensors::V1_0::OperationMode;
-using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
-using ::android::hardware::sensors::V1_0::SensorStatus;
-using ::android::hardware::sensors::V1_0::SharedMemType;
-using ::android::hardware::sensors::V1_0::Vec3;
-using std::chrono::duration_cast;
-using std::chrono::microseconds;
-using std::chrono::milliseconds;
-using std::chrono::nanoseconds;
-
-constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
-
-class EventCallback : public IEventCallback {
-   public:
-    void reset() {
-        mFlushMap.clear();
-        mEventMap.clear();
-    }
-
-    void onEvent(const ::android::hardware::sensors::V1_0::Event& event) override {
-        if (event.sensorType == SensorType::META_DATA &&
-            event.u.meta.what == MetaDataEventType::META_DATA_FLUSH_COMPLETE) {
-            std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
-            mFlushMap[event.sensorHandle]++;
-            mFlushCV.notify_all();
-        } else if (event.sensorType != SensorType::ADDITIONAL_INFO) {
-            std::unique_lock<std::recursive_mutex> lock(mEventMutex);
-            mEventMap[event.sensorHandle].push_back(event);
-            mEventCV.notify_all();
-        }
-    }
-
-    int32_t getFlushCount(int32_t sensorHandle) {
-        std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
-        return mFlushMap[sensorHandle];
-    }
-
-    void waitForFlushEvents(const std::vector<SensorInfo>& sensorsToWaitFor,
-                            int32_t numCallsToFlush, milliseconds timeout) {
-        std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
-        mFlushCV.wait_for(lock, timeout,
-                          [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); });
-    }
-
-    const std::vector<Event> getEvents(int32_t sensorHandle) {
-        std::unique_lock<std::recursive_mutex> lock(mEventMutex);
-        return mEventMap[sensorHandle];
-    }
-
-    void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor, milliseconds timeout) {
-        std::unique_lock<std::recursive_mutex> lock(mEventMutex);
-        mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); });
-    }
-
-   protected:
-    bool flushesReceived(const std::vector<SensorInfo>& sensorsToWaitFor, int32_t numCallsToFlush) {
-        for (const SensorInfo& sensor : sensorsToWaitFor) {
-            if (getFlushCount(sensor.sensorHandle) < numCallsToFlush) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    bool eventsReceived(const std::vector<SensorInfo>& sensorsToWaitFor) {
-        for (const SensorInfo& sensor : sensorsToWaitFor) {
-            if (getEvents(sensor.sensorHandle).size() == 0) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    std::map<int32_t, int32_t> mFlushMap;
-    std::recursive_mutex mFlushMutex;
-    std::condition_variable_any mFlushCV;
-
-    std::map<int32_t, std::vector<Event>> mEventMap;
-    std::recursive_mutex mEventMutex;
-    std::condition_variable_any mEventCV;
-};
-
-// The main test class for SENSORS HIDL HAL.
-
-class SensorsHidlTest : public SensorsHidlTestBase {
-  public:
-    virtual void SetUp() override {
-        mEnvironment = new SensorsHidlEnvironmentV2_0(GetParam());
-        mEnvironment->HidlSetUp();
-        // Ensure that we have a valid environment before performing tests
-        ASSERT_NE(getSensors(), nullptr);
-    }
-
-    virtual void TearDown() override { mEnvironment->HidlTearDown(); }
-
-  protected:
-    SensorInfo defaultSensorByType(SensorType type) override;
-    std::vector<SensorInfo> getSensorsList();
-    // implementation wrapper
-    Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) override {
-        return getSensors()->getSensorsList(_hidl_cb);
-    }
-
-    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
-
-    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
-                         int64_t maxReportLatencyNs) override {
-        return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
-    }
-
-    Return<Result> flush(int32_t sensorHandle) override {
-        return getSensors()->flush(sensorHandle);
-    }
-
-    Return<Result> injectSensorData(const Event& event) override {
-        return getSensors()->injectSensorData(event);
-    }
-
-    Return<void> registerDirectChannel(const SharedMemInfo& mem,
-                                       ISensors::registerDirectChannel_cb _hidl_cb) override;
-
-    Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
-        return getSensors()->unregisterDirectChannel(channelHandle);
-    }
-
-    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
-                                    ISensors::configDirectReport_cb _hidl_cb) override {
-        return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
-    }
-
-    inline sp<::android::hardware::sensors::V2_0::ISensors>& getSensors() {
-        return mEnvironment->mSensors;
-    }
-
-    SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; }
-
-    // Test helpers
-    void runSingleFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
-                            int32_t expectedFlushCount, Result expectedResponse);
-    void runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
-                      int32_t flushCalls, int32_t expectedFlushCount, Result expectedResponse);
-
-    // Helper functions
-    void activateAllSensors(bool enable);
-    std::vector<SensorInfo> getNonOneShotSensors();
-    std::vector<SensorInfo> getNonOneShotAndNonSpecialSensors();
-    std::vector<SensorInfo> getOneShotSensors();
-    std::vector<SensorInfo> getInjectEventSensors();
-    int32_t getInvalidSensorHandle();
-    bool getDirectChannelSensor(SensorInfo* sensor, SharedMemType* memType, RateLevel* rate);
-    void verifyDirectChannel(SharedMemType memType);
-    void verifyRegisterDirectChannel(std::shared_ptr<SensorsTestSharedMemory> mem,
-                                     int32_t* directChannelHandle, bool supportsSharedMemType,
-                                     bool supportsAnyDirectChannel);
-    void verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
-                         int32_t directChannelHandle, bool directChannelSupported);
-    void verifyUnregisterDirectChannel(int32_t directChannelHandle, bool directChannelSupported);
-    void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel);
-    void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
-                                   bool* supportsAnyDirectChannel);
-
-  private:
-    // Test environment for sensors HAL.
-    SensorsHidlEnvironmentV2_0* mEnvironment;
-};
-
-Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
-    // If activating a sensor, add the handle in a set so that when test fails it can be turned off.
-    // The handle is not removed when it is deactivating on purpose so that it is not necessary to
-    // check the return value of deactivation. Deactivating a sensor more than once does not have
-    // negative effect.
-    if (enabled) {
-        mSensorHandles.insert(sensorHandle);
-    }
-    return getSensors()->activate(sensorHandle, enabled);
-}
-
-Return<void> SensorsHidlTest::registerDirectChannel(const SharedMemInfo& mem,
-                                                    ISensors::registerDirectChannel_cb cb) {
-    // If registeration of a channel succeeds, add the handle of channel to a set so that it can be
-    // unregistered when test fails. Unregister a channel does not remove the handle on purpose.
-    // Unregistering a channel more than once should not have negative effect.
-    getSensors()->registerDirectChannel(mem, [&](auto result, auto channelHandle) {
-        if (result == Result::OK) {
-            mDirectChannelHandles.insert(channelHandle);
-        }
-        cb(result, channelHandle);
-    });
-    return Void();
-}
-
-SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) {
-    SensorInfo ret;
-
-    ret.type = (SensorType)-1;
-    getSensors()->getSensorsList([&](const auto& list) {
-        const size_t count = list.size();
-        for (size_t i = 0; i < count; ++i) {
-            if (list[i].type == type) {
-                ret = list[i];
-                return;
-            }
-        }
-    });
-
-    return ret;
-}
-
-std::vector<SensorInfo> SensorsHidlTest::getSensorsList() {
-    std::vector<SensorInfo> ret;
-
-    getSensors()->getSensorsList([&](const auto& list) {
-        const size_t count = list.size();
-        ret.reserve(list.size());
-        for (size_t i = 0; i < count; ++i) {
-            ret.push_back(list[i]);
-        }
-    });
-
-    return ret;
-}
-
-std::vector<SensorInfo> SensorsHidlTest::getNonOneShotSensors() {
-    std::vector<SensorInfo> sensors;
-    for (const SensorInfo& info : getSensorsList()) {
-        if (extractReportMode(info.flags) != SensorFlagBits::ONE_SHOT_MODE) {
-            sensors.push_back(info);
-        }
-    }
-    return sensors;
-}
-
-std::vector<SensorInfo> SensorsHidlTest::getNonOneShotAndNonSpecialSensors() {
-    std::vector<SensorInfo> sensors;
-    for (const SensorInfo& info : getSensorsList()) {
-        SensorFlagBits reportMode = extractReportMode(info.flags);
-        if (reportMode != SensorFlagBits::ONE_SHOT_MODE &&
-            reportMode != SensorFlagBits::SPECIAL_REPORTING_MODE) {
-            sensors.push_back(info);
-        }
-    }
-    return sensors;
-}
-
-std::vector<SensorInfo> SensorsHidlTest::getOneShotSensors() {
-    std::vector<SensorInfo> sensors;
-    for (const SensorInfo& info : getSensorsList()) {
-        if (extractReportMode(info.flags) == SensorFlagBits::ONE_SHOT_MODE) {
-            sensors.push_back(info);
-        }
-    }
-    return sensors;
-}
-
-std::vector<SensorInfo> SensorsHidlTest::getInjectEventSensors() {
-    std::vector<SensorInfo> sensors;
-    for (const SensorInfo& info : getSensorsList()) {
-        if (info.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION)) {
-            sensors.push_back(info);
-        }
-    }
-    return sensors;
-}
-
-int32_t SensorsHidlTest::getInvalidSensorHandle() {
-    // Find a sensor handle that does not exist in the sensor list
-    int32_t maxHandle = 0;
-    for (const SensorInfo& sensor : getSensorsList()) {
-        maxHandle = max(maxHandle, sensor.sensorHandle);
-    }
-    return maxHandle + 1;
-}
-
-// Test if sensor list returned is valid
-TEST_P(SensorsHidlTest, SensorListValid) {
+TEST_P(SensorsHidlTest, SensorListDoesntContainInvalidType) {
     getSensors()->getSensorsList([&](const auto& list) {
         const size_t count = list.size();
         for (size_t i = 0; i < count; ++i) {
             const auto& s = list[i];
-            SCOPED_TRACE(::testing::Message()
-                         << i << "/" << count << ": "
-                         << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
-                         << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
-                         << " name=" << s.name);
-
-            // Test non-empty type string
-            EXPECT_FALSE(s.typeAsString.empty());
-
-            // Test defined type matches defined string type
-            EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
-
-            // Test if all sensor has name and vendor
-            EXPECT_FALSE(s.name.empty());
-            EXPECT_FALSE(s.vendor.empty());
-
-            // Test power > 0, maxRange > 0
-            EXPECT_LE(0, s.power);
-            EXPECT_LT(0, s.maxRange);
-
-            // Info type, should have no sensor
-            EXPECT_FALSE(s.type == SensorType::ADDITIONAL_INFO || s.type == SensorType::META_DATA);
-
-            // Test fifoMax >= fifoReserved
-            EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
-                << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
-
-            // Test Reporting mode valid
-            EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
-
-            // Test min max are in the right order
-            EXPECT_LE(s.minDelay, s.maxDelay);
-            // Test min/max delay matches reporting mode
-            EXPECT_NO_FATAL_FAILURE(
-                assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
+            EXPECT_FALSE(s.type == ::android::hardware::sensors::V2_1::SensorType::HINGE_ANGLE);
         }
     });
 }
 
-// Test that SetOperationMode returns the expected value
-TEST_P(SensorsHidlTest, SetOperationMode) {
-    std::vector<SensorInfo> sensors = getInjectEventSensors();
-    if (getInjectEventSensors().size() > 0) {
-        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
-        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
-        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
-    } else {
-        ASSERT_EQ(Result::BAD_VALUE, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
-    }
-}
-
-// Test that an injected event is written back to the Event FMQ
-TEST_P(SensorsHidlTest, InjectSensorEventData) {
-    std::vector<SensorInfo> sensors = getInjectEventSensors();
-    if (sensors.size() == 0) {
-        return;
-    }
-
-    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
-
-    EventCallback callback;
-    getEnvironment()->registerCallback(&callback);
-
-    // AdditionalInfo event should not be sent to Event FMQ
-    Event additionalInfoEvent;
-    additionalInfoEvent.sensorType = SensorType::ADDITIONAL_INFO;
-    additionalInfoEvent.timestamp = android::elapsedRealtimeNano();
-
-    Event injectedEvent;
-    injectedEvent.timestamp = android::elapsedRealtimeNano();
-    Vec3 data = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
-    injectedEvent.u.vec3 = data;
-
-    for (const auto& s : sensors) {
-        additionalInfoEvent.sensorHandle = s.sensorHandle;
-        EXPECT_EQ(Result::OK, getSensors()->injectSensorData(additionalInfoEvent));
-
-        injectedEvent.sensorType = s.type;
-        injectedEvent.sensorHandle = s.sensorHandle;
-        EXPECT_EQ(Result::OK, getSensors()->injectSensorData(injectedEvent));
-    }
-
-    // Wait for events to be written back to the Event FMQ
-    callback.waitForEvents(sensors, milliseconds(1000) /* timeout */);
-
-    for (const auto& s : sensors) {
-        auto events = callback.getEvents(s.sensorHandle);
-        auto lastEvent = events.back();
-
-        // Verify that only a single event has been received
-        ASSERT_EQ(events.size(), 1);
-
-        // Verify that the event received matches the event injected and is not the additional
-        // info event
-        ASSERT_EQ(lastEvent.sensorType, s.type);
-        ASSERT_EQ(lastEvent.sensorType, s.type);
-        ASSERT_EQ(lastEvent.timestamp, injectedEvent.timestamp);
-        ASSERT_EQ(lastEvent.u.vec3.x, injectedEvent.u.vec3.x);
-        ASSERT_EQ(lastEvent.u.vec3.y, injectedEvent.u.vec3.y);
-        ASSERT_EQ(lastEvent.u.vec3.z, injectedEvent.u.vec3.z);
-        ASSERT_EQ(lastEvent.u.vec3.status, injectedEvent.u.vec3.status);
-    }
-
-    getEnvironment()->unregisterCallback();
-    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
-}
-
-// Test if sensor hal can do UI speed accelerometer streaming properly
-TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
-    testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), sAccelNormChecker);
-}
-
-// Test if sensor hal can do normal speed accelerometer streaming properly
-TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
-    testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), sAccelNormChecker);
-}
-
-// Test if sensor hal can do game speed accelerometer streaming properly
-TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) {
-    testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), sAccelNormChecker);
-}
-
-// Test if sensor hal can do UI speed gyroscope streaming properly
-TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
-    testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), sGyroNormChecker);
-}
-
-// Test if sensor hal can do normal speed gyroscope streaming properly
-TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
-    testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), sGyroNormChecker);
-}
-
-// Test if sensor hal can do game speed gyroscope streaming properly
-TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) {
-    testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), sGyroNormChecker);
-}
-
-// Test if sensor hal can do UI speed magnetometer streaming properly
-TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
-    testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), NullChecker());
-}
-
-// Test if sensor hal can do normal speed magnetometer streaming properly
-TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
-    testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), NullChecker());
-}
-
-// Test if sensor hal can do game speed magnetometer streaming properly
-TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) {
-    testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), NullChecker());
-}
-
-// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
-TEST_P(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
-    testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
-    testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/);
-}
-
-// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
-TEST_P(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
-    testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
-    testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/);
-}
-
-// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
-TEST_P(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
-    testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
-    testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
-}
-
-// Test if sensor hal can do accelerometer batching properly
-TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) {
-    testBatchingOperation(SensorType::ACCELEROMETER);
-}
-
-// Test if sensor hal can do gyroscope batching properly
-TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) {
-    testBatchingOperation(SensorType::GYROSCOPE);
-}
-
-// Test if sensor hal can do magnetometer batching properly
-TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) {
-    testBatchingOperation(SensorType::MAGNETIC_FIELD);
-}
-
-// Test sensor event direct report with ashmem for accel sensor at normal rate
-TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
-    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              sAccelNormChecker);
-}
-
-// Test sensor event direct report with ashmem for accel sensor at fast rate
-TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
-    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
-                              sAccelNormChecker);
-}
-
-// Test sensor event direct report with ashmem for accel sensor at very fast rate
-TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
-    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM,
-                              RateLevel::VERY_FAST, sAccelNormChecker);
-}
-
-// Test sensor event direct report with ashmem for gyro sensor at normal rate
-TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
-    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              sGyroNormChecker);
-}
-
-// Test sensor event direct report with ashmem for gyro sensor at fast rate
-TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
-    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
-                              sGyroNormChecker);
-}
-
-// Test sensor event direct report with ashmem for gyro sensor at very fast rate
-TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
-    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
-                              sGyroNormChecker);
-}
-
-// Test sensor event direct report with ashmem for mag sensor at normal rate
-TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
-    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              NullChecker());
-}
-
-// Test sensor event direct report with ashmem for mag sensor at fast rate
-TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
-    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
-                              NullChecker());
-}
-
-// Test sensor event direct report with ashmem for mag sensor at very fast rate
-TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
-    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM,
-                              RateLevel::VERY_FAST, NullChecker());
-}
-
-// Test sensor event direct report with gralloc for accel sensor at normal rate
-TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
-    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              sAccelNormChecker);
-}
-
-// Test sensor event direct report with gralloc for accel sensor at fast rate
-TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
-    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
-                              sAccelNormChecker);
-}
-
-// Test sensor event direct report with gralloc for accel sensor at very fast rate
-TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
-    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC,
-                              RateLevel::VERY_FAST, sAccelNormChecker);
-}
-
-// Test sensor event direct report with gralloc for gyro sensor at normal rate
-TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
-    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              sGyroNormChecker);
-}
-
-// Test sensor event direct report with gralloc for gyro sensor at fast rate
-TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
-    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
-                              sGyroNormChecker);
-}
-
-// Test sensor event direct report with gralloc for gyro sensor at very fast rate
-TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
-    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
-                              sGyroNormChecker);
-}
-
-// Test sensor event direct report with gralloc for mag sensor at normal rate
-TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
-    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              NullChecker());
-}
-
-// Test sensor event direct report with gralloc for mag sensor at fast rate
-TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
-    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
-                              NullChecker());
-}
-
-// Test sensor event direct report with gralloc for mag sensor at very fast rate
-TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
-    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC,
-                              RateLevel::VERY_FAST, NullChecker());
-}
-
-void SensorsHidlTest::activateAllSensors(bool enable) {
-    for (const SensorInfo& sensorInfo : getSensorsList()) {
-        if (isValidType(sensorInfo.type)) {
-            batch(sensorInfo.sensorHandle, sensorInfo.minDelay, 0 /* maxReportLatencyNs */);
-            activate(sensorInfo.sensorHandle, enable);
-        }
-    }
-}
-
-// Test that if initialize is called twice, then the HAL writes events to the FMQs from the second
-// call to the function.
-TEST_P(SensorsHidlTest, CallInitializeTwice) {
-    // Create a helper class so that a second environment is able to be instantiated
-    class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_0 {
-      public:
-        SensorsHidlEnvironmentTest(const std::string& service_name)
-            : SensorsHidlEnvironmentV2_0(service_name) {}
-    };
-
-    if (getSensorsList().size() == 0) {
-        // No sensors
-        return;
-    }
-
-    constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000;  // 1s
-    constexpr int32_t kNumEvents = 1;
-
-    // Create a new environment that calls initialize()
-    std::unique_ptr<SensorsHidlEnvironmentTest> newEnv =
-            std::make_unique<SensorsHidlEnvironmentTest>(GetParam());
-    newEnv->HidlSetUp();
-    if (HasFatalFailure()) {
-        return;  // Exit early if setting up the new environment failed
-    }
-
-    activateAllSensors(true);
-    // Verify that the old environment does not receive any events
-    ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0);
-    // Verify that the new event queue receives sensor events
-    ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, newEnv.get()).size(), kNumEvents);
-    activateAllSensors(false);
-
-    // Cleanup the test environment
-    newEnv->HidlTearDown();
-
-    // Restore the test environment for future tests
-    getEnvironment()->HidlTearDown();
-    getEnvironment()->HidlSetUp();
-    if (HasFatalFailure()) {
-        return;  // Exit early if resetting the environment failed
-    }
-
-    // Ensure that the original environment is receiving events
-    activateAllSensors(true);
-    ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
-    activateAllSensors(false);
-}
-
-TEST_P(SensorsHidlTest, CleanupConnectionsOnInitialize) {
-    activateAllSensors(true);
-
-    // Verify that events are received
-    constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000;  // 1s
-    constexpr int32_t kNumEvents = 1;
-    ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents);
-
-    // Clear the active sensor handles so they are not disabled during TearDown
-    auto handles = mSensorHandles;
-    mSensorHandles.clear();
-    getEnvironment()->HidlTearDown();
-    getEnvironment()->HidlSetUp();
-    if (HasFatalFailure()) {
-        return;  // Exit early if resetting the environment failed
-    }
-
-    // Verify no events are received until sensors are re-activated
-    ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0);
-    activateAllSensors(true);
-    ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents);
-
-    // Disable sensors
-    activateAllSensors(false);
-
-    // Restore active sensors prior to clearing the environment
-    mSensorHandles = handles;
-}
-
-void SensorsHidlTest::runSingleFlushTest(const std::vector<SensorInfo>& sensors,
-                                         bool activateSensor, int32_t expectedFlushCount,
-                                         Result expectedResponse) {
-    runFlushTest(sensors, activateSensor, 1 /* flushCalls */, expectedFlushCount, expectedResponse);
-}
-
-void SensorsHidlTest::runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
-                                   int32_t flushCalls, int32_t expectedFlushCount,
-                                   Result expectedResponse) {
-    EventCallback callback;
-    getEnvironment()->registerCallback(&callback);
-
-    for (const SensorInfo& sensor : sensors) {
-        // Configure and activate the sensor
-        batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */);
-        activate(sensor.sensorHandle, activateSensor);
-
-        // Flush the sensor
-        for (int32_t i = 0; i < flushCalls; i++) {
-            Result flushResult = flush(sensor.sensorHandle);
-            ASSERT_EQ(flushResult, expectedResponse);
-        }
-    }
-
-    // Wait up to one second for the flush events
-    callback.waitForFlushEvents(sensors, flushCalls, milliseconds(1000) /* timeout */);
-
-    // Deactivate all sensors after waiting for flush events so pending flush events are not
-    // abandoned by the HAL.
-    for (const SensorInfo& sensor : sensors) {
-        activate(sensor.sensorHandle, false);
-    }
-    getEnvironment()->unregisterCallback();
-
-    // Check that the correct number of flushes are present for each sensor
-    for (const SensorInfo& sensor : sensors) {
-        ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount);
-    }
-}
-
-TEST_P(SensorsHidlTest, FlushSensor) {
-    // Find a sensor that is not a one-shot sensor
-    std::vector<SensorInfo> sensors = getNonOneShotSensors();
-    if (sensors.size() == 0) {
-        return;
-    }
-
-    constexpr int32_t kFlushes = 5;
-    runSingleFlushTest(sensors, true /* activateSensor */, 1 /* expectedFlushCount */, Result::OK);
-    runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, Result::OK);
-}
-
-TEST_P(SensorsHidlTest, FlushOneShotSensor) {
-    // Find a sensor that is a one-shot sensor
-    std::vector<SensorInfo> sensors = getOneShotSensors();
-    if (sensors.size() == 0) {
-        return;
-    }
-
-    runSingleFlushTest(sensors, true /* activateSensor */, 0 /* expectedFlushCount */,
-                       Result::BAD_VALUE);
-}
-
-TEST_P(SensorsHidlTest, FlushInactiveSensor) {
-    // Attempt to find a non-one shot sensor, then a one-shot sensor if necessary
-    std::vector<SensorInfo> sensors = getNonOneShotSensors();
-    if (sensors.size() == 0) {
-        sensors = getOneShotSensors();
-        if (sensors.size() == 0) {
-            return;
-        }
-    }
-
-    runSingleFlushTest(sensors, false /* activateSensor */, 0 /* expectedFlushCount */,
-                       Result::BAD_VALUE);
-}
-
-TEST_P(SensorsHidlTest, FlushNonexistentSensor) {
-    SensorInfo sensor;
-    std::vector<SensorInfo> sensors = getNonOneShotSensors();
-    if (sensors.size() == 0) {
-        sensors = getOneShotSensors();
-        if (sensors.size() == 0) {
-            return;
-        }
-    }
-    sensor = sensors.front();
-    sensor.sensorHandle = getInvalidSensorHandle();
-    runSingleFlushTest(std::vector<SensorInfo>{sensor}, false /* activateSensor */,
-                       0 /* expectedFlushCount */, Result::BAD_VALUE);
-}
-
-TEST_P(SensorsHidlTest, Batch) {
-    if (getSensorsList().size() == 0) {
-        return;
-    }
-
-    activateAllSensors(false /* enable */);
-    for (const SensorInfo& sensor : getSensorsList()) {
-        // Call batch on inactive sensor
-        // One shot sensors have minDelay set to -1 which is an invalid
-        // parameter. Use 0 instead to avoid errors.
-        int64_t samplingPeriodNs = extractReportMode(sensor.flags) == SensorFlagBits::ONE_SHOT_MODE
-                                           ? 0
-                                           : sensor.minDelay;
-        ASSERT_EQ(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */),
-                  Result::OK);
-
-        // Activate the sensor
-        activate(sensor.sensorHandle, true /* enabled */);
-
-        // Call batch on an active sensor
-        ASSERT_EQ(batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */),
-                  Result::OK);
-    }
-    activateAllSensors(false /* enable */);
-
-    // Call batch on an invalid sensor
-    SensorInfo sensor = getSensorsList().front();
-    sensor.sensorHandle = getInvalidSensorHandle();
-    ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
-              Result::BAD_VALUE);
-}
-
-TEST_P(SensorsHidlTest, Activate) {
-    if (getSensorsList().size() == 0) {
-        return;
-    }
-
-    // Verify that sensor events are generated when activate is called
-    for (const SensorInfo& sensor : getSensorsList()) {
-        batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */);
-        ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);
-
-        // Call activate on a sensor that is already activated
-        ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);
-
-        // Deactivate the sensor
-        ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK);
-
-        // Call deactivate on a sensor that is already deactivated
-        ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK);
-    }
-
-    // Attempt to activate an invalid sensor
-    int32_t invalidHandle = getInvalidSensorHandle();
-    ASSERT_EQ(activate(invalidHandle, true), Result::BAD_VALUE);
-    ASSERT_EQ(activate(invalidHandle, false), Result::BAD_VALUE);
-}
-
-TEST_P(SensorsHidlTest, NoStaleEvents) {
-    constexpr milliseconds kFiveHundredMs(500);
-    constexpr milliseconds kOneSecond(1000);
-
-    // Register the callback to receive sensor events
-    EventCallback callback;
-    getEnvironment()->registerCallback(&callback);
-
-    // This test is not valid for one-shot or special-report-mode sensors
-    const std::vector<SensorInfo> sensors = getNonOneShotAndNonSpecialSensors();
-    milliseconds maxMinDelay(0);
-    for (const SensorInfo& sensor : sensors) {
-        milliseconds minDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
-        maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
-    }
-
-    // Activate the sensors so that they start generating events
-    activateAllSensors(true);
-
-    // According to the CDD, the first sample must be generated within 400ms + 2 * sample_time
-    // and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount
-    // of time to guarantee that a sample has arrived.
-    callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
-    activateAllSensors(false);
-
-    // Save the last received event for each sensor
-    std::map<int32_t, int64_t> lastEventTimestampMap;
-    for (const SensorInfo& sensor : sensors) {
-        // Some on-change sensors may not report an event without stimulus
-        if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) {
-            ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
-        }
-        if (callback.getEvents(sensor.sensorHandle).size() >= 1) {
-            lastEventTimestampMap[sensor.sensorHandle] =
-                    callback.getEvents(sensor.sensorHandle).back().timestamp;
-        }
-    }
-
-    // Allow some time to pass, reset the callback, then reactivate the sensors
-    usleep(duration_cast<microseconds>(kOneSecond + (5 * maxMinDelay)).count());
-    callback.reset();
-    activateAllSensors(true);
-    callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
-    activateAllSensors(false);
-
-    for (const SensorInfo& sensor : sensors) {
-        // Skip sensors that did not previously report an event
-        if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
-            continue;
-        }
-        // Skip on-change sensors that do not consistently report an initial event
-        if (callback.getEvents(sensor.sensorHandle).size() < 1) {
-            continue;
-        }
-        // Ensure that the first event received is not stale by ensuring that its timestamp is
-        // sufficiently different from the previous event
-        const Event newEvent = callback.getEvents(sensor.sensorHandle).front();
-        milliseconds delta = duration_cast<milliseconds>(
-                nanoseconds(newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]));
-        milliseconds sensorMinDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
-        ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay));
-    }
-}
-
-void SensorsHidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle,
-                                     RateLevel rateLevel) {
-    configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel,
-                       [&](Result result, int32_t reportToken) {
-                           if (isDirectReportRateSupported(sensor, rateLevel)) {
-                               ASSERT_EQ(result, Result::OK);
-                               if (rateLevel != RateLevel::STOP) {
-                                   ASSERT_GT(reportToken, 0);
-                               }
-                           } else {
-                               ASSERT_EQ(result, Result::BAD_VALUE);
-                           }
-                       });
-}
-
-void SensorsHidlTest::queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
-                                                bool* supportsAnyDirectChannel) {
-    *supportsSharedMemType = false;
-    *supportsAnyDirectChannel = false;
-    for (const SensorInfo& curSensor : getSensorsList()) {
-        if (isDirectChannelTypeSupported(curSensor, memType)) {
-            *supportsSharedMemType = true;
-        }
-        if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM) ||
-            isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) {
-            *supportsAnyDirectChannel = true;
-        }
-
-        if (*supportsSharedMemType && *supportsAnyDirectChannel) {
-            break;
-        }
-    }
-}
-
-void SensorsHidlTest::verifyRegisterDirectChannel(std::shared_ptr<SensorsTestSharedMemory> mem,
-                                                  int32_t* directChannelHandle,
-                                                  bool supportsSharedMemType,
-                                                  bool supportsAnyDirectChannel) {
-    char* buffer = mem->getBuffer();
-    memset(buffer, 0xff, mem->getSize());
-
-    registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
-        if (supportsSharedMemType) {
-            ASSERT_EQ(result, Result::OK);
-            ASSERT_GT(channelHandle, 0);
-
-            // Verify that the memory has been zeroed
-            for (size_t i = 0; i < mem->getSize(); i++) {
-                ASSERT_EQ(buffer[i], 0x00);
-            }
-        } else {
-            Result expectedResult =
-                    supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
-            ASSERT_EQ(result, expectedResult);
-            ASSERT_EQ(channelHandle, -1);
-        }
-        *directChannelHandle = channelHandle;
-    });
-}
-
-void SensorsHidlTest::verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
-                                      int32_t directChannelHandle, bool supportsAnyDirectChannel) {
-    if (isDirectChannelTypeSupported(sensor, memType)) {
-        // Verify that each rate level is properly supported
-        checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL);
-        checkRateLevel(sensor, directChannelHandle, RateLevel::FAST);
-        checkRateLevel(sensor, directChannelHandle, RateLevel::VERY_FAST);
-        checkRateLevel(sensor, directChannelHandle, RateLevel::STOP);
-
-        // Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP
-        configDirectReport(
-            -1 /* sensorHandle */, directChannelHandle, RateLevel::NORMAL,
-            [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); });
-        configDirectReport(
-            -1 /* sensorHandle */, directChannelHandle, RateLevel::STOP,
-            [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
-    } else {
-        // directChannelHandle will be -1 here, HAL should either reject it as a bad value if there
-        // is some level of direct channel report, otherwise return INVALID_OPERATION if direct
-        // channel is not supported at all
-        Result expectedResult =
-                supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
-        configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL,
-                           [expectedResult](Result result, int32_t /* reportToken */) {
-                               ASSERT_EQ(result, expectedResult);
-                           });
-    }
-}
-
-void SensorsHidlTest::verifyUnregisterDirectChannel(int32_t directChannelHandle,
-                                                    bool supportsAnyDirectChannel) {
-    Result expectedResult = supportsAnyDirectChannel ? Result::OK : Result::INVALID_OPERATION;
-    ASSERT_EQ(unregisterDirectChannel(directChannelHandle), expectedResult);
-}
-
-void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) {
-    constexpr size_t kNumEvents = 1;
-    constexpr size_t kMemSize = kNumEvents * kEventSize;
-
-    std::shared_ptr<SensorsTestSharedMemory> mem(
-        SensorsTestSharedMemory::create(memType, kMemSize));
-    ASSERT_NE(mem, nullptr);
-
-    bool supportsSharedMemType;
-    bool supportsAnyDirectChannel;
-    queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel);
-
-    for (const SensorInfo& sensor : getSensorsList()) {
-        int32_t directChannelHandle = 0;
-        verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType,
-                                    supportsAnyDirectChannel);
-        verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel);
-        verifyUnregisterDirectChannel(directChannelHandle, supportsAnyDirectChannel);
-    }
-}
-
-TEST_P(SensorsHidlTest, DirectChannelAshmem) {
-    verifyDirectChannel(SharedMemType::ASHMEM);
-}
-
-TEST_P(SensorsHidlTest, DirectChannelGralloc) {
-    verifyDirectChannel(SharedMemType::GRALLOC);
-}
-
-bool SensorsHidlTest::getDirectChannelSensor(SensorInfo* sensor, SharedMemType* memType,
-                                             RateLevel* rate) {
-    bool found = false;
-    for (const SensorInfo& curSensor : getSensorsList()) {
-        if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM)) {
-            *memType = SharedMemType::ASHMEM;
-            *sensor = curSensor;
-            found = true;
-            break;
-        } else if (isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) {
-            *memType = SharedMemType::GRALLOC;
-            *sensor = curSensor;
-            found = true;
-            break;
-        }
-    }
-
-    if (found) {
-        // Find a supported rate level
-        constexpr int kNumRateLevels = 3;
-        RateLevel rates[kNumRateLevels] = {RateLevel::NORMAL, RateLevel::FAST,
-                                           RateLevel::VERY_FAST};
-        *rate = RateLevel::STOP;
-        for (int i = 0; i < kNumRateLevels; i++) {
-            if (isDirectReportRateSupported(*sensor, rates[i])) {
-                *rate = rates[i];
-            }
-        }
-
-        // At least one rate level must be supported
-        EXPECT_NE(*rate, RateLevel::STOP);
-    }
-    return found;
-}
-
-TEST_P(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) {
-    SensorInfo sensor;
-    SharedMemType memType;
-    RateLevel rate;
-    if (!getDirectChannelSensor(&sensor, &memType, &rate)) {
-        return;
-    }
-
-    // Verify that an invalid channel handle produces a BAD_VALUE result
-    configDirectReport(sensor.sensorHandle, -1, rate, [](Result result, int32_t /* reportToken */) {
-        ASSERT_EQ(result, Result::BAD_VALUE);
-    });
-}
-
-TEST_P(SensorsHidlTest, CleanupDirectConnectionOnInitialize) {
-    constexpr size_t kNumEvents = 1;
-    constexpr size_t kMemSize = kNumEvents * kEventSize;
-
-    SensorInfo sensor;
-    SharedMemType memType;
-    RateLevel rate;
-
-    if (!getDirectChannelSensor(&sensor, &memType, &rate)) {
-        return;
-    }
-
-    std::shared_ptr<SensorsTestSharedMemory> mem(
-        SensorsTestSharedMemory::create(memType, kMemSize));
-    ASSERT_NE(mem, nullptr);
-
-    int32_t directChannelHandle = 0;
-    registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
-        ASSERT_EQ(result, Result::OK);
-        directChannelHandle = channelHandle;
-    });
-
-    // Configure the channel and expect success
-    configDirectReport(
-        sensor.sensorHandle, directChannelHandle, rate,
-        [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
-
-    // Call initialize() via the environment setup to cause the HAL to re-initialize
-    // Clear the active direct connections so they are not stopped during TearDown
-    auto handles = mDirectChannelHandles;
-    mDirectChannelHandles.clear();
-    getEnvironment()->HidlTearDown();
-    getEnvironment()->HidlSetUp();
-    if (HasFatalFailure()) {
-        return;  // Exit early if resetting the environment failed
-    }
-
-    // Attempt to configure the direct channel and expect it to fail
-    configDirectReport(
-        sensor.sensorHandle, directChannelHandle, rate,
-        [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); });
-
-    // Restore original handles, though they should already be deactivated
-    mDirectChannelHandles = handles;
-}
-
 INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest,
                          testing::ValuesIn(android::hardware::getAllHalInstanceNames(
                                  android::hardware::sensors::V2_0::ISensors::descriptor)),
-                         android::hardware::PrintInstanceNameToString);
-// vim: set ts=2 sw=2
+                         android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/sensors/2.1/Android.bp b/sensors/2.1/Android.bp
new file mode 100644
index 0000000..8e80e1f
--- /dev/null
+++ b/sensors/2.1/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.sensors@2.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ISensors.hal",
+        "ISensorsCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/sensors/2.1/ISensors.hal b/sensors/2.1/ISensors.hal
new file mode 100644
index 0000000..d401fa5
--- /dev/null
+++ b/sensors/2.1/ISensors.hal
@@ -0,0 +1,148 @@
+/*
+ * 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.sensors@2.1;
+
+import @1.0::Result;
+import @2.0::ISensors;
+import @2.1::ISensorsCallback;
+
+interface ISensors extends @2.0::ISensors {
+    /**
+     * Enumerate all available (static) sensors.
+     *
+     * The SensorInfo for each sensor returned by getSensorsList must be stable
+     * from the initial call to getSensorsList after a device boot until the
+     * entire system restarts. The SensorInfo for each sensor must not change
+     * between subsequent calls to getSensorsList, even across restarts of the
+     * HAL and its dependencies (for example, the sensor handle for a given
+     * sensor must not change across HAL restarts).
+     */
+    getSensorsList_2_1() generates (vec<SensorInfo> list);
+
+    /**
+     * Initialize the Sensors HAL's Fast Message Queues (FMQ) and callback.
+     *
+     * The Fast Message Queues (FMQ) that are used to send data between the
+     * framework and the HAL. The callback is used by the HAL to notify the
+     * framework of asynchronous events, such as a dynamic sensor connection.
+     *
+     * The Event FMQ is used to transport sensor events from the HAL to the
+     * framework. The Event FMQ is created using the eventQueueDescriptor.
+     * Data may only be written to the Event FMQ. Data must not be read from
+     * the Event FMQ since the framework is the only reader. Upon receiving
+     * sensor events, the HAL writes the sensor events to the Event FMQ.
+     *
+     * Once the HAL is finished writing sensor events to the Event FMQ, the HAL
+     * must notify the framework that sensor events are available to be read and
+     * processed. This is accomplished by either:
+     *     1) Calling the Event FMQ’s EventFlag::wake() function with
+              EventQueueFlagBits::READ_AND_PROCESS
+     *     2) Setting the write notification in the Event FMQ’s writeBlocking()
+     *        function to EventQueueFlagBits::READ_AND_PROCESS.
+     *
+     * If the Event FMQ’s writeBlocking() function is used, the read
+     * notification must be set to EventQueueFlagBits::EVENTS_READ in order to
+     * be notified and unblocked when the framework has successfully read events
+     * from the Event FMQ.
+     *
+     * The Wake Lock FMQ is used by the framework to notify the HAL when it is
+     * safe to release its wake_lock. When the framework receives WAKE_UP events
+     * from the Event FMQ and the framework has acquired a wake_lock, the
+     * framework must write the number of WAKE_UP events processed to the Wake
+     * Lock FMQ. When the HAL reads the data from the Wake Lock FMQ, the HAL
+     * decrements its current count of unprocessed WAKE_UP events and releases
+     * its wake_lock if the current count of unprocessed WAKE_UP events is
+     * zero. It is important to note that the HAL must acquire the wake lock and
+     * update its internal state regarding the number of outstanding WAKE_UP
+     * events _before_ posting the event to the Wake Lock FMQ, in order to avoid
+     * a race condition that can lead to loss of wake lock synchronization with
+     * the framework.
+     *
+     * The framework must use the WakeLockQueueFlagBits::DATA_WRITTEN value to
+     * notify the HAL that data has been written to the Wake Lock FMQ and must
+     * be read by HAL.
+     *
+     * The ISensorsCallback is used by the HAL to notify the framework of
+     * asynchronous events, such as a dynamic sensor connection.
+     *
+     * The name of any wake_lock acquired by the Sensors HAL for WAKE_UP events
+     * must begin with "SensorsHAL_WAKEUP".
+     *
+     * If WAKE_LOCK_TIMEOUT_SECONDS has elapsed since the most recent WAKE_UP
+     * event was written to the Event FMQ without receiving a message on the
+     * Wake Lock FMQ, then any held wake_lock for WAKE_UP events must be
+     * released.
+     *
+     * If either the Event FMQ or the Wake Lock FMQ is already initialized when
+     * initialize is invoked, then both existing FMQs must be discarded and the
+     * new descriptors must be used to create new FMQs within the HAL. The
+     * number of outstanding WAKE_UP events should also be reset to zero, and
+     * any outstanding wake_locks held as a result of WAKE_UP events should be
+     * released.
+     *
+     * All active sensor requests and direct channels must be closed and
+     * properly cleaned up when initialize is called in order to ensure that the
+     * HAL and framework's state is consistent (e.g. after a runtime restart).
+     *
+     * initialize must be thread safe and prevent concurrent calls
+     * to initialize from simultaneously modifying state.
+     *
+     * @param eventQueueDescriptor Fast Message Queue descriptor that is used to
+     *     create the Event FMQ which is where sensor events are written. The
+     *     descriptor is obtained from the framework's FMQ that is used to read
+     *     sensor events.
+     * @param wakeLockDescriptor Fast Message Queue descriptor that is used to
+     *     create the Wake Lock FMQ which is where wake_lock events are read
+     *     from. The descriptor is obtained from the framework's FMQ that is
+     *     used to write wake_lock events.
+     * @param sensorsCallback sensors callback that receives asynchronous data
+     *     from the Sensors HAL.
+     * @return result OK on success; BAD_VALUE if descriptor is invalid (such
+     *     as null)
+     */
+    @entry
+    @callflow(next = {"getSensorsList"})
+    initialize_2_1(fmq_sync<Event> eventQueueDescriptor,
+                   fmq_sync<uint32_t> wakeLockDescriptor,
+                   ISensorsCallback sensorsCallback)
+        generates
+              (Result result);
+
+    /**
+     * Inject a single sensor event or push operation environment parameters to
+     * device.
+     *
+     * When device is in NORMAL mode, this function is called to push operation
+     * environment data to device. In this operation, Event is always of
+     * SensorType::AdditionalInfo type. See operation evironment parameters
+     * section in AdditionalInfoType.
+     *
+     * When device is in DATA_INJECTION mode, this function is also used for
+     * injecting sensor events.
+     *
+     * Regardless of OperationMode, injected SensorType::ADDITIONAL_INFO
+     * type events should not be routed back to the sensor event queue.
+     *
+     * @see AdditionalInfoType
+     * @see OperationMode
+     * @param event sensor event to be injected
+     * @return result OK on success; PERMISSION_DENIED if operation is not
+     *     allowed; INVALID_OPERATION, if this functionality is unsupported;
+     *     BAD_VALUE if sensor event cannot be injected.
+     */
+    injectSensorData_2_1(Event event) generates (Result result);
+};
diff --git a/sensors/2.1/ISensorsCallback.hal b/sensors/2.1/ISensorsCallback.hal
new file mode 100644
index 0000000..de521d5
--- /dev/null
+++ b/sensors/2.1/ISensorsCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.sensors@2.1;
+
+import @2.0::ISensorsCallback;
+import @2.1::SensorInfo;
+
+interface ISensorsCallback extends @2.0::ISensorsCallback {
+    /**
+     * Notify the framework that new dynamic sensors have been connected.
+     *
+     * If a dynamic sensor was previously connected and has not been
+     * disconnected, then that sensor must not be included in sensorInfos.
+     *
+     * @param sensorInfos vector of SensorInfo for each dynamic sensor that
+     *     was connected.
+     */
+    oneway onDynamicSensorsConnected_2_1(vec<SensorInfo> sensorInfos);
+};
diff --git a/sensors/2.1/default/Android.bp b/sensors/2.1/default/Android.bp
new file mode 100644
index 0000000..27b439d
--- /dev/null
+++ b/sensors/2.1/default/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2018 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.
+
+cc_binary {
+    name: "android.hardware.sensors@2.1-service.mock",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "SensorsV2_1.cpp",
+        "service.cpp",
+    ],
+    init_rc: ["android.hardware.sensors@2.1-service-mock.rc"],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.X-shared-impl",
+    ],
+    vintf_fragments: ["android.hardware.sensors@2.1.xml"],
+}
diff --git a/sensors/2.1/default/OWNERS b/sensors/2.1/default/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/sensors/2.1/default/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/sensors/2.1/default/SensorsV2_1.cpp b/sensors/2.1/default/SensorsV2_1.cpp
new file mode 100644
index 0000000..2e3d315
--- /dev/null
+++ b/sensors/2.1/default/SensorsV2_1.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 "SensorsV2_1.h"
+
+#include "Sensor.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+using V2_X::implementation::ISensorsEventCallback;
+using V2_X::implementation::OnChangeSensor;
+
+class HingeAngleSensor : public OnChangeSensor {
+  public:
+    HingeAngleSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+        : OnChangeSensor(callback) {
+        mSensorInfo.sensorHandle = sensorHandle;
+        mSensorInfo.name = "Hinge Angle Sensor";
+        mSensorInfo.vendor = "Vendor String";
+        mSensorInfo.version = 1;
+        mSensorInfo.type = SensorType::HINGE_ANGLE;
+        mSensorInfo.typeAsString = "";
+        mSensorInfo.maxRange = 360.0f;
+        mSensorInfo.resolution = 1.0f;
+        mSensorInfo.power = 0.001f;
+        mSensorInfo.minDelay = 40 * 1000;  // microseconds
+        mSensorInfo.maxDelay = V2_X::implementation::kDefaultMaxDelayUs;
+        mSensorInfo.fifoReservedEventCount = 0;
+        mSensorInfo.fifoMaxEventCount = 0;
+        mSensorInfo.requiredPermission = "";
+        mSensorInfo.flags = static_cast<uint32_t>(V1_0::SensorFlagBits::ON_CHANGE_MODE);
+    }
+};
+
+SensorsV2_1::SensorsV2_1() {
+    AddSensor<HingeAngleSensor>();
+}
+
+// Methods from ::android::hardware::sensors::V2_1::ISensors follow.
+Return<void> SensorsV2_1::getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        sensors.push_back(sensor.second->getSensorInfo());
+    }
+
+    // Call the HIDL callback with the SensorInfo
+    _hidl_cb(sensors);
+
+    return Void();
+}
+
+Return<Result> SensorsV2_1::initialize_2_1(
+        const ::android::hardware::MQDescriptorSync<V2_1::Event>& eventQueueDescriptor,
+        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+        const sp<V2_1::ISensorsCallback>& sensorsCallback) {
+    auto eventQueue = std::make_unique<MessageQueue<V2_1::Event, kSynchronizedReadWrite>>(
+            eventQueueDescriptor, true /* resetPointers */);
+    std::unique_ptr<EventMessageQueueWrapperBase> wrapper =
+            std::make_unique<EventMessageQueueWrapperV2_1>(eventQueue);
+    mCallbackWrapper = new ISensorsCallbackWrapper(sensorsCallback);
+    return initializeBase(wrapper, wakeLockDescriptor, mCallbackWrapper);
+}
+
+Return<Result> SensorsV2_1::injectSensorData_2_1(const V2_1::Event& event) {
+    return injectSensorData(convertToOldEvent(event));
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/sensors/2.1/default/SensorsV2_1.h b/sensors/2.1/default/SensorsV2_1.h
new file mode 100644
index 0000000..9f7fe04
--- /dev/null
+++ b/sensors/2.1/default/SensorsV2_1.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_1_H
+#define ANDROID_HARDWARE_SENSORS_V2_1_H
+
+#include "Sensors.h"
+
+#include "EventMessageQueueWrapper.h"
+
+#include <android/hardware/sensors/2.1/ISensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+using Result = ::android::hardware::sensors::V1_0::Result;
+using Sensors = ::android::hardware::sensors::V2_X::implementation::Sensors<ISensors>;
+
+class ISensorsCallbackWrapper : public V2_0::ISensorsCallback {
+  public:
+    ISensorsCallbackWrapper(const sp<V2_1::ISensorsCallback>& callback) : mCallback(callback) {}
+
+    Return<void> onDynamicSensorsConnected(const hidl_vec<V1_0::SensorInfo>& sensorInfos) override {
+        return mCallback->onDynamicSensorsConnected_2_1(convertToNewSensorInfos(sensorInfos));
+    }
+
+    Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& sensorHandles) override {
+        return mCallback->onDynamicSensorsDisconnected(sensorHandles);
+    }
+
+  private:
+    sp<V2_1::ISensorsCallback> mCallback;
+};
+
+struct SensorsV2_1 : public Sensors {
+    SensorsV2_1();
+
+    // Methods from ::android::hardware::sensors::V2_1::ISensors follow.
+    Return<void> getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) override;
+
+    Return<Result> initialize_2_1(
+            const ::android::hardware::MQDescriptorSync<V2_1::Event>& eventQueueDescriptor,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+            const sp<V2_1::ISensorsCallback>& sensorsCallback) override;
+
+    Return<Result> injectSensorData_2_1(const V2_1::Event& event) override;
+
+  private:
+    sp<ISensorsCallbackWrapper> mCallbackWrapper;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_1_H
\ No newline at end of file
diff --git a/sensors/2.1/default/android.hardware.sensors@2.1-service-mock.rc b/sensors/2.1/default/android.hardware.sensors@2.1-service-mock.rc
new file mode 100644
index 0000000..d4147e7
--- /dev/null
+++ b/sensors/2.1/default/android.hardware.sensors@2.1-service-mock.rc
@@ -0,0 +1,7 @@
+service vendor.sensors-hal-2-1-mock /vendor/bin/hw/android.hardware.sensors@2.1-service.mock
+    interface android.hardware.sensors@2.0::ISensors default
+    interface android.hardware.sensors@2.1::ISensors default
+    class hal
+    user system
+    group system
+    rlimit rtprio 10 10
diff --git a/sensors/2.1/default/android.hardware.sensors@2.1.xml b/sensors/2.1/default/android.hardware.sensors@2.1.xml
new file mode 100644
index 0000000..18bd3ae
--- /dev/null
+++ b/sensors/2.1/default/android.hardware.sensors@2.1.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.sensors</name>
+        <transport>hwbinder</transport>
+        <version>2.1</version>
+        <interface>
+            <name>ISensors</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/sensors/2.1/default/service.cpp b/sensors/2.1/default/service.cpp
new file mode 100644
index 0000000..1f3087c
--- /dev/null
+++ b/sensors/2.1/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 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 "android.hardware.sensors@2.1-service"
+
+#include <android/hardware/sensors/2.1/ISensors.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include "SensorsV2_1.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::sensors::V2_1::ISensors;
+using android::hardware::sensors::V2_1::implementation::SensorsV2_1;
+
+int main(int /* argc */, char** /* argv */) {
+    configureRpcThreadpool(1, true);
+
+    android::sp<ISensors> sensors = new SensorsV2_1();
+    if (sensors->registerAsService() != ::android::OK) {
+        ALOGE("Failed to register Sensors HAL instance");
+        return -1;
+    }
+
+    joinRpcThreadpool();
+    return 1;  // joinRpcThreadpool shouldn't exit
+}
diff --git a/sensors/2.1/types.hal b/sensors/2.1/types.hal
new file mode 100644
index 0000000..503bece
--- /dev/null
+++ b/sensors/2.1/types.hal
@@ -0,0 +1,160 @@
+/*
+ * 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.sensors@2.1;
+
+import @1.0::EventPayload;
+import @1.0::SensorType;
+import @1.0::SensorFlagBits;
+
+@export(name="", value_prefix="SENSOR_TYPE_")
+enum SensorType : @1.0::SensorType {
+    /**
+     * HINGE_ANGLE
+     * reporting-mode: on-change
+     * wake-up sensor: yes
+     *
+     * A sensor of this type measures the angle, in degrees, between two
+     * integral parts of the device. Movement of a hinge measured by this sensor
+     * type is expected to alter the ways in which the user may interact with
+     * the device, for example by unfolding or revealing a display.
+     *
+     * Sensor data is output using @1.0::EventPayload.scalar.
+     *
+     * Implement wake-up proximity sensor before implementing a non wake-up
+     * proximity sensor.
+     */
+    HINGE_ANGLE                     = 36,
+};
+
+struct Event {
+    /** Time measured in nanoseconds, in "elapsedRealtimeNano()'s" timebase. */
+    int64_t timestamp;
+
+    /** sensor identifier */
+    int32_t sensorHandle;
+
+    @2.1::SensorType sensorType;
+
+    /** Union discriminated on sensorType */
+    EventPayload u;
+};
+
+struct SensorInfo {
+    /**
+     * handle that identifies this sensors. This handle is used to reference
+     * this sensor throughout the HAL API.
+     */
+    int32_t sensorHandle;
+
+    /**
+     * Name of this sensor.
+     * All sensors of the same "type" must have a different "name".
+     */
+    string name;
+
+    /** vendor of the hardware part */
+    string vendor;
+
+    /**
+     * version of the hardware part + driver. The value of this field
+     * must increase when the driver is updated in a way that changes the
+     * output of this sensor. This is important for fused sensors when the
+     * fusion algorithm is updated.
+     */
+    int32_t version;
+
+    /** this sensor's type. */
+    @2.1::SensorType type;
+
+    /**
+     * type of this sensor as a string.
+     *
+     * When defining an OEM specific sensor or sensor manufacturer specific
+     * sensor, use your reserve domain name as a prefix.
+     * e.g. com.google.glass.onheaddetector
+     *
+     * For sensors of known type defined in SensorType (value <
+     * SensorType::DEVICE_PRIVATE_BASE), this can be an empty string.
+     */
+    string typeAsString;
+
+    /** maximum range of this sensor's value in SI units */
+    float maxRange;
+
+    /** smallest difference between two values reported by this sensor */
+    float resolution;
+
+    /** rough estimate of this sensor's power consumption in mA */
+    float power;
+
+    /**
+     * this value depends on the reporting mode:
+     *
+     *   continuous: minimum sample period allowed in microseconds
+     *   on-change : 0
+     *   one-shot  :-1
+     *   special   : 0, unless otherwise noted
+     */
+    int32_t minDelay;
+
+    /**
+     * number of events reserved for this sensor in the batch mode FIFO.
+     * If there is a dedicated FIFO for this sensor, then this is the
+     * size of this FIFO. If the FIFO is shared with other sensors,
+     * this is the size reserved for that sensor and it can be zero.
+     */
+    uint32_t fifoReservedEventCount;
+
+    /**
+     * maximum number of events of this sensor that could be batched.
+     * This is especially relevant when the FIFO is shared between
+     * several sensors; this value is then set to the size of that FIFO.
+     */
+    uint32_t fifoMaxEventCount;
+
+    /**
+     * permission required to see this sensor, register to it and receive data.
+     * Set to "" if no permission is required. Some sensor types like the
+     * heart rate monitor have a mandatory require_permission.
+     * For sensors that always require a specific permission, like the heart
+     * rate monitor, the android framework might overwrite this string
+     * automatically.
+     */
+    string requiredPermission;
+
+    /**
+     * This value is defined only for continuous mode and on-change sensors.
+     * It is the delay between two sensor events corresponding to the lowest
+     * frequency that this sensor supports. When lower frequencies are requested
+     * through batch()/setDelay() the events will be generated at this frequency
+     * instead.
+     * It can be used by the framework or applications to estimate when the
+     * batch FIFO may be full.
+     *
+     * NOTE: periodNs is in nanoseconds where as maxDelay/minDelay are in
+     *       microseconds.
+     *
+     *       continuous, on-change: maximum sampling period allowed in
+     *                              microseconds.
+     *
+     *          one-shot, special : 0
+     */
+    int32_t maxDelay;
+
+    /** Bitmask of SensorFlagBits */
+    bitfield<SensorFlagBits> flags;
+};
\ No newline at end of file
diff --git a/sensors/2.1/vts/functional/Android.bp b/sensors/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..c4f5e9d
--- /dev/null
+++ b/sensors/2.1/vts/functional/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_test {
+    name: "VtsHalSensorsV2_1TargetTest",
+    cflags: [
+        "-DLOG_TAG=\"sensors_hidl_hal_test\"",
+    ],
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalSensorsV2_1TargetTest.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libfmq",
+        "VtsHalSensorsTargetTestUtils",
+        "VtsHalSensorsV2_1TargetTest-lib",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/sensors/2.1/vts/functional/AndroidTest.xml b/sensors/2.1/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..0d8593e
--- /dev/null
+++ b/sensors/2.1/vts/functional/AndroidTest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalSensorsV2_1TargetTest.">
+    <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.RunCommandTargetPreparer">
+        <option name="run-command" value="stop"/>
+        <option name="teardown-command" value="start"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalSensorsV2_1TargetTest->/data/local/tmp/VtsHalSensorsV2_1TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-timeout" value="900000" />
+        <option name="runtime-hint" value="300000"/>
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalSensorsV2_1TargetTest" />
+    </test>
+</configuration>
diff --git a/sensors/2.1/vts/functional/OWNERS b/sensors/2.1/vts/functional/OWNERS
new file mode 100644
index 0000000..892da15
--- /dev/null
+++ b/sensors/2.1/vts/functional/OWNERS
@@ -0,0 +1,8 @@
+# Sensors team
+arthuri@google.com
+bduddie@google.com
+stange@google.com
+
+# VTS team
+trong@google.com
+yim@google.com
diff --git a/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp b/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp
new file mode 100644
index 0000000..230bb6c
--- /dev/null
+++ b/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp
@@ -0,0 +1,22 @@
+/*
+ * 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 "VtsHalSensorsV2_XTargetTest.h"
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 android::hardware::sensors::V2_1::ISensors::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/sensors/common/default/2.X/Android.bp b/sensors/common/default/2.X/Android.bp
new file mode 100644
index 0000000..8b0d52f
--- /dev/null
+++ b/sensors/common/default/2.X/Android.bp
@@ -0,0 +1,37 @@
+//
+// 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.
+
+cc_library_static {
+    name: "android.hardware.sensors@2.X-shared-impl",
+    vendor: true,
+    export_include_dirs: ["."],
+    srcs: [
+        "Sensor.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+}
diff --git a/sensors/common/default/2.X/OWNERS b/sensors/common/default/2.X/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/sensors/common/default/2.X/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/sensors/2.0/default/Sensor.cpp b/sensors/common/default/2.X/Sensor.cpp
similarity index 94%
rename from sensors/2.0/default/Sensor.cpp
rename to sensors/common/default/2.X/Sensor.cpp
index c09173f..1841dff 100644
--- a/sensors/2.0/default/Sensor.cpp
+++ b/sensors/common/default/2.X/Sensor.cpp
@@ -23,14 +23,17 @@
 namespace android {
 namespace hardware {
 namespace sensors {
-namespace V2_0 {
+namespace V2_X {
 namespace implementation {
 
 using ::android::hardware::sensors::V1_0::MetaDataEventType;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
 using ::android::hardware::sensors::V1_0::SensorFlagBits;
 using ::android::hardware::sensors::V1_0::SensorStatus;
-
-static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000;
+using ::android::hardware::sensors::V2_1::Event;
+using ::android::hardware::sensors::V2_1::SensorInfo;
+using ::android::hardware::sensors::V2_1::SensorType;
 
 Sensor::Sensor(ISensorsEventCallback* callback)
     : mIsEnabled(false),
@@ -204,8 +207,8 @@
     mSensorInfo.typeAsString = "";
     mSensorInfo.maxRange = 78.4f;  // +/- 8g
     mSensorInfo.resolution = 1.52e-5;
-    mSensorInfo.power = 0.001f;          // mA
-    mSensorInfo.minDelay = 20 * 1000;    // microseconds
+    mSensorInfo.power = 0.001f;        // mA
+    mSensorInfo.minDelay = 20 * 1000;  // microseconds
     mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
@@ -221,9 +224,9 @@
     mSensorInfo.version = 1;
     mSensorInfo.type = SensorType::PRESSURE;
     mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 1100.0f;   // hPa
-    mSensorInfo.resolution = 0.005f;  // hPa
-    mSensorInfo.power = 0.001f;       // mA
+    mSensorInfo.maxRange = 1100.0f;     // hPa
+    mSensorInfo.resolution = 0.005f;    // hPa
+    mSensorInfo.power = 0.001f;         // mA
     mSensorInfo.minDelay = 100 * 1000;  // microseconds
     mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
@@ -242,7 +245,7 @@
     mSensorInfo.typeAsString = "";
     mSensorInfo.maxRange = 1300.0f;
     mSensorInfo.resolution = 0.01f;
-    mSensorInfo.power = 0.001f;       // mA
+    mSensorInfo.power = 0.001f;        // mA
     mSensorInfo.minDelay = 20 * 1000;  // microseconds
     mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
@@ -261,8 +264,8 @@
     mSensorInfo.typeAsString = "";
     mSensorInfo.maxRange = 43000.0f;
     mSensorInfo.resolution = 10.0f;
-    mSensorInfo.power = 0.001f;           // mA
-    mSensorInfo.minDelay = 200 * 1000;    // microseconds
+    mSensorInfo.power = 0.001f;         // mA
+    mSensorInfo.minDelay = 200 * 1000;  // microseconds
     mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
     mSensorInfo.fifoMaxEventCount = 0;
@@ -280,7 +283,7 @@
     mSensorInfo.typeAsString = "";
     mSensorInfo.maxRange = 5.0f;
     mSensorInfo.resolution = 1.0f;
-    mSensorInfo.power = 0.012f;  // mA
+    mSensorInfo.power = 0.012f;         // mA
     mSensorInfo.minDelay = 200 * 1000;  // microseconds
     mSensorInfo.maxDelay = kDefaultMaxDelayUs;
     mSensorInfo.fifoReservedEventCount = 0;
@@ -367,7 +370,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V2_0
+}  // namespace V2_X
 }  // namespace sensors
 }  // namespace hardware
 }  // namespace android
diff --git a/sensors/2.0/default/Sensor.h b/sensors/common/default/2.X/Sensor.h
similarity index 79%
rename from sensors/2.0/default/Sensor.h
rename to sensors/common/default/2.X/Sensor.h
index 61900fa..2f8a143 100644
--- a/sensors/2.0/default/Sensor.h
+++ b/sensors/common/default/2.X/Sensor.h
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H
-#define ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H
+#ifndef ANDROID_HARDWARE_SENSORS_V2_X_SENSOR_H
+#define ANDROID_HARDWARE_SENSORS_V2_X_SENSOR_H
 
 #include <android/hardware/sensors/1.0/types.h>
+#include <android/hardware/sensors/2.1/types.h>
 
 #include <condition_variable>
 #include <memory>
@@ -25,26 +26,30 @@
 #include <thread>
 #include <vector>
 
-using ::android::hardware::sensors::V1_0::Event;
-using ::android::hardware::sensors::V1_0::OperationMode;
-using ::android::hardware::sensors::V1_0::Result;
-using ::android::hardware::sensors::V1_0::SensorInfo;
-using ::android::hardware::sensors::V1_0::SensorType;
-
 namespace android {
 namespace hardware {
 namespace sensors {
-namespace V2_0 {
+namespace V2_X {
 namespace implementation {
 
+static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000;
+
 class ISensorsEventCallback {
-   public:
+  public:
+    using Event = ::android::hardware::sensors::V2_1::Event;
+
     virtual ~ISensorsEventCallback(){};
     virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
 };
 
 class Sensor {
-   public:
+  public:
+    using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
+    using Result = ::android::hardware::sensors::V1_0::Result;
+    using Event = ::android::hardware::sensors::V2_1::Event;
+    using SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
+    using SensorType = ::android::hardware::sensors::V2_1::SensorType;
+
     Sensor(ISensorsEventCallback* callback);
     virtual ~Sensor();
 
@@ -57,7 +62,7 @@
     bool supportsDataInjection() const;
     Result injectEvent(const Event& event);
 
-   protected:
+  protected:
     void run();
     virtual std::vector<Event> readEvents();
     static void startThread(Sensor* sensor);
@@ -80,68 +85,68 @@
 };
 
 class OnChangeSensor : public Sensor {
-   public:
+  public:
     OnChangeSensor(ISensorsEventCallback* callback);
 
     virtual void activate(bool enable) override;
 
-   protected:
+  protected:
     virtual std::vector<Event> readEvents() override;
 
-   protected:
+  protected:
     Event mPreviousEvent;
     bool mPreviousEventSet;
 };
 
 class AccelSensor : public Sensor {
-   public:
+  public:
     AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
 };
 
 class GyroSensor : public Sensor {
-   public:
+  public:
     GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
 };
 
 class AmbientTempSensor : public OnChangeSensor {
-   public:
+  public:
     AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
 };
 
 class DeviceTempSensor : public OnChangeSensor {
-   public:
+  public:
     DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
 };
 
 class PressureSensor : public Sensor {
-   public:
+  public:
     PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
 };
 
 class MagnetometerSensor : public Sensor {
-   public:
+  public:
     MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
 };
 
 class LightSensor : public OnChangeSensor {
-   public:
+  public:
     LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
 };
 
 class ProximitySensor : public OnChangeSensor {
-   public:
+  public:
     ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
 };
 
 class RelativeHumiditySensor : public OnChangeSensor {
-   public:
+  public:
     RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
 };
 
 }  // namespace implementation
-}  // namespace V2_0
+}  // namespace V2_X
 }  // namespace sensors
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H
+#endif  // ANDROID_HARDWARE_SENSORS_V2_X_SENSOR_H
diff --git a/sensors/common/default/2.X/Sensors.h b/sensors/common/default/2.X/Sensors.h
new file mode 100644
index 0000000..ee8240d
--- /dev/null
+++ b/sensors/common/default/2.X/Sensors.h
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2018 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_SENSORS_V2_X_SENSORS_H
+#define ANDROID_HARDWARE_SENSORS_V2_X_SENSORS_H
+
+#include "EventMessageQueueWrapper.h"
+#include "Sensor.h"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <android/hardware/sensors/2.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hardware_legacy/power.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <log/log.h>
+
+#include <atomic>
+#include <memory>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_X {
+namespace implementation {
+
+template <class ISensorsInterface>
+struct Sensors : public ISensorsInterface, public ISensorsEventCallback {
+    using Event = ::android::hardware::sensors::V1_0::Event;
+    using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
+    using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
+    using Result = ::android::hardware::sensors::V1_0::Result;
+    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+    using EventQueueFlagBits = ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+    using SensorTimeout = ::android::hardware::sensors::V2_0::SensorTimeout;
+    using WakeLockQueueFlagBits = ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+    using ISensorsCallback = ::android::hardware::sensors::V2_0::ISensorsCallback;
+    using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
+    using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+    static constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP";
+
+    Sensors()
+        : mEventQueueFlag(nullptr),
+          mNextHandle(1),
+          mOutstandingWakeUpEvents(0),
+          mReadWakeLockQueueRun(false),
+          mAutoReleaseWakeLockTime(0),
+          mHasWakeLock(false) {
+        AddSensor<AccelSensor>();
+        AddSensor<GyroSensor>();
+        AddSensor<AmbientTempSensor>();
+        AddSensor<DeviceTempSensor>();
+        AddSensor<PressureSensor>();
+        AddSensor<MagnetometerSensor>();
+        AddSensor<LightSensor>();
+        AddSensor<ProximitySensor>();
+        AddSensor<RelativeHumiditySensor>();
+    }
+
+    virtual ~Sensors() {
+        deleteEventFlag();
+        mReadWakeLockQueueRun = false;
+        mWakeLockThread.join();
+    }
+
+    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+    Return<void> getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override {
+        std::vector<V1_0::SensorInfo> sensors;
+        for (const auto& sensor : mSensors) {
+            sensors.push_back(
+                    V2_1::implementation::convertToOldSensorInfo(sensor.second->getSensorInfo()));
+        }
+
+        // Call the HIDL callback with the SensorInfo
+        _hidl_cb(sensors);
+
+        return Void();
+    }
+
+    Return<Result> setOperationMode(OperationMode mode) override {
+        for (auto sensor : mSensors) {
+            sensor.second->setOperationMode(mode);
+        }
+        return Result::OK;
+    }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override {
+        auto sensor = mSensors.find(sensorHandle);
+        if (sensor != mSensors.end()) {
+            sensor->second->activate(enabled);
+            return Result::OK;
+        }
+        return Result::BAD_VALUE;
+    }
+
+    Return<Result> initialize(
+            const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+            const sp<ISensorsCallback>& sensorsCallback) override {
+        auto eventQueue =
+                std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
+        std::unique_ptr<V2_1::implementation::EventMessageQueueWrapperBase> wrapper =
+                std::make_unique<V2_1::implementation::EventMessageQueueWrapperV1_0>(eventQueue);
+        return initializeBase(wrapper, wakeLockDescriptor, sensorsCallback);
+    }
+
+    Return<Result> initializeBase(
+            std::unique_ptr<V2_1::implementation::EventMessageQueueWrapperBase>& eventQueue,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+            const sp<ISensorsCallback>& sensorsCallback) {
+        Result result = Result::OK;
+
+        // Ensure that all sensors are disabled
+        for (auto sensor : mSensors) {
+            sensor.second->activate(false /* enable */);
+        }
+
+        // Stop the Wake Lock thread if it is currently running
+        if (mReadWakeLockQueueRun.load()) {
+            mReadWakeLockQueueRun = false;
+            mWakeLockThread.join();
+        }
+
+        // Save a reference to the callback
+        mCallback = sensorsCallback;
+
+        // Save the event queue.
+        mEventQueue = std::move(eventQueue);
+
+        // Ensure that any existing EventFlag is properly deleted
+        deleteEventFlag();
+
+        // Create the EventFlag that is used to signal to the framework that sensor events have been
+        // written to the Event FMQ
+        if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
+            result = Result::BAD_VALUE;
+        }
+
+        // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
+        // events have been successfully read and handled by the framework.
+        mWakeLockQueue = std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor,
+                                                                true /* resetPointers */);
+
+        if (!mCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
+            result = Result::BAD_VALUE;
+        }
+
+        // Start the thread to read events from the Wake Lock FMQ
+        mReadWakeLockQueueRun = true;
+        mWakeLockThread = std::thread(startReadWakeLockThread, this);
+
+        return result;
+    }
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t /* maxReportLatencyNs */) override {
+        auto sensor = mSensors.find(sensorHandle);
+        if (sensor != mSensors.end()) {
+            sensor->second->batch(samplingPeriodNs);
+            return Result::OK;
+        }
+        return Result::BAD_VALUE;
+    }
+
+    Return<Result> flush(int32_t sensorHandle) override {
+        auto sensor = mSensors.find(sensorHandle);
+        if (sensor != mSensors.end()) {
+            return sensor->second->flush();
+        }
+        return Result::BAD_VALUE;
+    }
+
+    Return<Result> injectSensorData(const Event& event) override {
+        auto sensor = mSensors.find(event.sensorHandle);
+        if (sensor != mSensors.end()) {
+            return sensor->second->injectEvent(V2_1::implementation::convertToNewEvent(event));
+        }
+
+        return Result::BAD_VALUE;
+    }
+
+    Return<void> registerDirectChannel(const SharedMemInfo& /* mem */,
+                                       V2_0::ISensors::registerDirectChannel_cb _hidl_cb) override {
+        _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+        return Return<void>();
+    }
+
+    Return<Result> unregisterDirectChannel(int32_t /* channelHandle */) override {
+        return Result::INVALID_OPERATION;
+    }
+
+    Return<void> configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */,
+                                    RateLevel /* rate */,
+                                    V2_0::ISensors::configDirectReport_cb _hidl_cb) override {
+        _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
+        return Return<void>();
+    }
+
+    void postEvents(const std::vector<V2_1::Event>& events, bool wakeup) override {
+        std::lock_guard<std::mutex> lock(mWriteLock);
+        if (mEventQueue->write(events)) {
+            mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+
+            if (wakeup) {
+                // Keep track of the number of outstanding WAKE_UP events in order to properly hold
+                // a wake lock until the framework has secured a wake lock
+                updateWakeLock(events.size(), 0 /* eventsHandled */);
+            }
+        }
+    }
+
+  protected:
+    /**
+     * Add a new sensor
+     */
+    template <class SensorType>
+    void AddSensor() {
+        std::shared_ptr<SensorType> sensor =
+                std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
+        mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
+    }
+
+    /**
+     * Utility function to delete the Event Flag
+     */
+    void deleteEventFlag() {
+        status_t status = EventFlag::deleteEventFlag(&mEventQueueFlag);
+        if (status != OK) {
+            ALOGI("Failed to delete event flag: %d", status);
+        }
+    }
+
+    static void startReadWakeLockThread(Sensors* sensors) { sensors->readWakeLockFMQ(); }
+
+    /**
+     * Function to read the Wake Lock FMQ and release the wake lock when appropriate
+     */
+    void readWakeLockFMQ() {
+        while (mReadWakeLockQueueRun.load()) {
+            constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000;  // 500 ms
+            uint32_t eventsHandled = 0;
+
+            // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to
+            // ensure that any held wake lock is able to be released if it is held for too long.
+            mWakeLockQueue->readBlocking(&eventsHandled, 1 /* count */, 0 /* readNotification */,
+                                         static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN),
+                                         kReadTimeoutNs);
+            updateWakeLock(0 /* eventsWritten */, eventsHandled);
+        }
+    }
+
+    /**
+     * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events
+     */
+    void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) {
+        std::lock_guard<std::mutex> lock(mWakeLockLock);
+        int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled;
+        if (newVal < 0) {
+            mOutstandingWakeUpEvents = 0;
+        } else {
+            mOutstandingWakeUpEvents = newVal;
+        }
+
+        if (eventsWritten > 0) {
+            // Update the time at which the last WAKE_UP event was sent
+            mAutoReleaseWakeLockTime =
+                    ::android::uptimeMillis() +
+                    static_cast<uint32_t>(SensorTimeout::WAKE_LOCK_SECONDS) * 1000;
+        }
+
+        if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 &&
+            acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) {
+            mHasWakeLock = true;
+        } else if (mHasWakeLock) {
+            // Check if the wake lock should be released automatically if
+            // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written
+            // to the Wake Lock FMQ.
+            if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) {
+                ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock",
+                      SensorTimeout::WAKE_LOCK_SECONDS);
+                mOutstandingWakeUpEvents = 0;
+            }
+
+            if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) {
+                mHasWakeLock = false;
+            }
+        }
+    }
+
+    /**
+     * The Event FMQ where sensor events are written
+     */
+    std::unique_ptr<V2_1::implementation::EventMessageQueueWrapperBase> mEventQueue;
+
+    /**
+     * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
+     */
+    std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
+
+    /**
+     * Event Flag to signal to the framework when sensor events are available to be read
+     */
+    EventFlag* mEventQueueFlag;
+
+    /**
+     * Callback for asynchronous events, such as dynamic sensor connections.
+     */
+    sp<ISensorsCallback> mCallback;
+
+    /**
+     * A map of the available sensors
+     */
+    std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
+
+    /**
+     * The next available sensor handle
+     */
+    int32_t mNextHandle;
+
+    /**
+     * Lock to protect writes to the FMQs
+     */
+    std::mutex mWriteLock;
+
+    /**
+     * Lock to protect acquiring and releasing the wake lock
+     */
+    std::mutex mWakeLockLock;
+
+    /**
+     * Track the number of WAKE_UP events that have not been handled by the framework
+     */
+    uint32_t mOutstandingWakeUpEvents;
+
+    /**
+     * A thread to read the Wake Lock FMQ
+     */
+    std::thread mWakeLockThread;
+
+    /**
+     * Flag to indicate that the Wake Lock Thread should continue to run
+     */
+    std::atomic_bool mReadWakeLockQueueRun;
+
+    /**
+     * Track the time when the wake lock should automatically be released
+     */
+    int64_t mAutoReleaseWakeLockTime;
+
+    /**
+     * Flag to indicate if a wake lock has been acquired
+     */
+    bool mHasWakeLock;
+};
+
+}  // namespace implementation
+}  // namespace V2_X
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_X_SENSORS_H
diff --git a/sensors/common/utils/Android.bp b/sensors/common/utils/Android.bp
new file mode 100644
index 0000000..aec6c4b
--- /dev/null
+++ b/sensors/common/utils/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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.
+
+cc_library_headers {
+    name: "android.hardware.sensors@2.X-shared-utils",
+    vendor_available: true,
+    defaults: ["hidl_defaults"],
+    export_include_dirs: ["."],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libbinder",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+    ],
+}
diff --git a/sensors/common/utils/EventMessageQueueWrapper.h b/sensors/common/utils/EventMessageQueueWrapper.h
new file mode 100644
index 0000000..bf3261f
--- /dev/null
+++ b/sensors/common/utils/EventMessageQueueWrapper.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_1_EVENTMESSAGEQUEUEWRAPPER_H
+#define ANDROID_HARDWARE_SENSORS_V2_1_EVENTMESSAGEQUEUEWRAPPER_H
+
+#include "convertV2_1.h"
+
+#include <android/hardware/sensors/2.1/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <log/log.h>
+
+#include <atomic>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+class EventMessageQueueWrapperBase : public RefBase {
+  public:
+    virtual ~EventMessageQueueWrapperBase() {}
+
+    virtual std::atomic<uint32_t>* getEventFlagWord() = 0;
+    virtual size_t availableToRead() = 0;
+    virtual bool read(V2_1::Event* events, size_t numToRead) = 0;
+    virtual bool write(const std::vector<V2_1::Event>& events) = 0;
+};
+
+class EventMessageQueueWrapperV1_0 : public EventMessageQueueWrapperBase {
+  public:
+    using EventMessageQueue = MessageQueue<V1_0::Event, kSynchronizedReadWrite>;
+
+    EventMessageQueueWrapperV1_0(std::unique_ptr<EventMessageQueue>& queue)
+        : mQueue(std::move(queue)) {}
+
+    const ::android::hardware::MQDescriptorSync<V1_0::Event>* getDesc() {
+        return mQueue->getDesc();
+    }
+
+    virtual std::atomic<uint32_t>* getEventFlagWord() override {
+        return mQueue->getEventFlagWord();
+    }
+
+    virtual size_t availableToRead() override { return mQueue->availableToRead(); }
+
+    virtual bool read(V2_1::Event* events, size_t numToRead) override {
+        return mQueue->read(reinterpret_cast<V1_0::Event*>(events), numToRead);
+    }
+
+    virtual bool write(const std::vector<V2_1::Event>& events) override {
+        const std::vector<V1_0::Event>& oldEvents = convertToOldEvents(events);
+        return mQueue->write(oldEvents.data(), oldEvents.size());
+    }
+
+  private:
+    std::unique_ptr<EventMessageQueue> mQueue;
+};
+
+class EventMessageQueueWrapperV2_1 : public EventMessageQueueWrapperBase {
+  public:
+    using EventMessageQueue = MessageQueue<V2_1::Event, kSynchronizedReadWrite>;
+
+    EventMessageQueueWrapperV2_1(std::unique_ptr<EventMessageQueue>& queue)
+        : mQueue(std::move(queue)) {}
+
+    const ::android::hardware::MQDescriptorSync<V2_1::Event>* getDesc() {
+        return mQueue->getDesc();
+    }
+
+    std::atomic<uint32_t>* getEventFlagWord() override { return mQueue->getEventFlagWord(); }
+
+    virtual size_t availableToRead() override { return mQueue->availableToRead(); }
+
+    virtual bool read(V2_1::Event* events, size_t numToRead) override {
+        return mQueue->read(events, numToRead);
+    }
+
+    bool write(const std::vector<V2_1::Event>& events) override {
+        return mQueue->write(events.data(), events.size());
+    }
+
+  private:
+    std::unique_ptr<EventMessageQueue> mQueue;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_1_EVENTMESSAGEQUEUEWRAPPER_H
\ No newline at end of file
diff --git a/sensors/common/utils/ISensorsWrapper.h b/sensors/common/utils/ISensorsWrapper.h
new file mode 100644
index 0000000..e9c22b1
--- /dev/null
+++ b/sensors/common/utils/ISensorsWrapper.h
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H
+#define ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H
+
+#include "EventMessageQueueWrapper.h"
+#include "ISensorsWrapper.h"
+
+#include "android/hardware/sensors/1.0/ISensors.h"
+#include "android/hardware/sensors/1.0/types.h"
+#include "android/hardware/sensors/2.0/ISensors.h"
+#include "android/hardware/sensors/2.0/ISensorsCallback.h"
+#include "android/hardware/sensors/2.1/ISensors.h"
+#include "android/hardware/sensors/2.1/ISensorsCallback.h"
+#include "android/hardware/sensors/2.1/types.h"
+
+#include <utils/LightRefBase.h>
+
+#include <cassert>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::sensors::V1_0::ISensors;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::RateLevel;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V2_1::Event;
+using ::android::hardware::sensors::V2_1::ISensorsCallback;
+
+// TODO: Look into providing this as a param if it needs to be a different value
+// than the framework.
+static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 256;
+
+/*
+ * The ISensorsWrapper interface includes all function from supported Sensors HAL versions. This
+ * allows for the SensorDevice to use the ISensorsWrapper interface to interact with the Sensors
+ * HAL regardless of the current version of the Sensors HAL that is loaded. Each concrete
+ * instantiation of ISensorsWrapper must correspond to a specific Sensors HAL version. This design
+ * is beneficial because only the functions that change between Sensors HAL versions must be newly
+ * implemented, any previously implemented function that does not change may remain the same.
+ *
+ * Functions that exist across all versions of the Sensors HAL should be implemented as pure
+ * virtual functions which forces the concrete instantiations to implement the functions.
+ *
+ * Functions that do not exist across all versions of the Sensors HAL should include a default
+ * implementation that generates an error if called. The default implementation should never
+ * be called and must be overridden by Sensors HAL versions that support the function.
+ */
+class ISensorsWrapperBase : public VirtualLightRefBase {
+  public:
+    virtual bool supportsPolling() const = 0;
+
+    virtual bool supportsMessageQueues() const = 0;
+
+    virtual void linkToDeath(android::sp<android::hardware::hidl_death_recipient> deathRecipient,
+                             uint64_t cookie) = 0;
+
+    virtual Return<void> getSensorsList(
+            ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) = 0;
+
+    virtual Return<Result> setOperationMode(OperationMode mode) = 0;
+
+    virtual Return<Result> activate(int32_t sensorHandle, bool enabled) = 0;
+
+    virtual Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                                 int64_t maxReportLatencyNs) = 0;
+
+    virtual Return<Result> flush(int32_t sensorHandle) = 0;
+
+    virtual Return<Result> injectSensorData(const Event& event) = 0;
+
+    virtual Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                               ISensors::registerDirectChannel_cb _hidl_cb) = 0;
+
+    virtual Return<Result> unregisterDirectChannel(int32_t channelHandle) = 0;
+
+    virtual Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle,
+                                            RateLevel rate,
+                                            ISensors::configDirectReport_cb _hidl_cb) = 0;
+
+    virtual Return<void> poll(int32_t /* maxCount */, ISensors::poll_cb /* _hidl_cb */) {
+        // Enforce this method is never invoked as it should be overridden if it's meant to be used.
+        assert(false);
+        return Return<void>();
+    }
+
+    virtual EventMessageQueueWrapperBase* getEventQueue() { return nullptr; }
+
+    virtual Return<Result> initialize(const MQDescriptorSync<uint32_t>& /* wakeLockDesc */,
+                                      const ::android::sp<ISensorsCallback>& /* callback */) {
+        // Enforce this method is never invoked as it should be overridden if it's meant to be used.
+        assert(false);
+        return Result::INVALID_OPERATION;
+    }
+};
+
+template <typename T>
+class SensorsWrapperBase : public ISensorsWrapperBase {
+  public:
+    SensorsWrapperBase(sp<T> sensors) : mSensors(sensors){};
+
+    void linkToDeath(android::sp<android::hardware::hidl_death_recipient> deathRecipient,
+                     uint64_t cookie) override {
+        mSensors->linkToDeath(deathRecipient, cookie);
+    }
+
+    virtual Return<void> getSensorsList(
+            ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override {
+        return mSensors->getSensorsList(
+                [&](const auto& list) { _hidl_cb(convertToNewSensorInfos(list)); });
+    }
+
+    Return<Result> setOperationMode(OperationMode mode) override {
+        return mSensors->setOperationMode(mode);
+    }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override {
+        return mSensors->activate(sensorHandle, enabled);
+    }
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override {
+        return mSensors->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+    }
+
+    Return<Result> flush(int32_t sensorHandle) override { return mSensors->flush(sensorHandle); }
+
+    virtual Return<Result> injectSensorData(const Event& event) override {
+        return mSensors->injectSensorData(convertToOldEvent(event));
+    }
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       ISensors::registerDirectChannel_cb _hidl_cb) override {
+        return mSensors->registerDirectChannel(mem, _hidl_cb);
+    }
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+        return mSensors->unregisterDirectChannel(channelHandle);
+    }
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    ISensors::configDirectReport_cb _hidl_cb) override {
+        return mSensors->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+    }
+
+  protected:
+    sp<T> mSensors;
+};
+
+class ISensorsWrapperV1_0 : public SensorsWrapperBase<hardware::sensors::V1_0::ISensors> {
+  public:
+    ISensorsWrapperV1_0(sp<hardware::sensors::V1_0::ISensors> sensors)
+        : SensorsWrapperBase(sensors){};
+
+    bool supportsPolling() const override { return true; }
+
+    bool supportsMessageQueues() const override { return false; }
+
+    Return<void> poll(int32_t maxCount,
+                      hardware::sensors::V1_0::ISensors::poll_cb _hidl_cb) override {
+        return mSensors->poll(maxCount, _hidl_cb);
+    }
+};
+
+class ISensorsWrapperV2_0 : public SensorsWrapperBase<hardware::sensors::V2_0::ISensors> {
+  public:
+    typedef MessageQueue<::android::hardware::sensors::V1_0::Event,
+                         ::android::hardware::kSynchronizedReadWrite>
+            EventMessageQueue;
+
+    ISensorsWrapperV2_0(sp<hardware::sensors::V2_0::ISensors> sensors)
+        : SensorsWrapperBase(sensors) {
+        auto eventQueue = std::make_unique<EventMessageQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+                                                              true /* configureEventFlagWord */);
+        mEventQueue = std::make_unique<EventMessageQueueWrapperV1_0>(eventQueue);
+    };
+
+    bool supportsPolling() const override { return false; }
+
+    bool supportsMessageQueues() const override { return true; }
+
+    EventMessageQueueWrapperBase* getEventQueue() override { return mEventQueue.get(); }
+
+    Return<Result> initialize(const MQDescriptorSync<uint32_t>& wakeLockDesc,
+                              const ::android::sp<ISensorsCallback>& callback) override {
+        return mSensors->initialize(*mEventQueue->getDesc(), wakeLockDesc, callback);
+    }
+
+  private:
+    std::unique_ptr<EventMessageQueueWrapperV1_0> mEventQueue;
+};
+
+class ISensorsWrapperV2_1 : public SensorsWrapperBase<hardware::sensors::V2_1::ISensors> {
+  public:
+    typedef MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite> EventMessageQueueV2_1;
+
+    ISensorsWrapperV2_1(sp<hardware::sensors::V2_1::ISensors> sensors)
+        : SensorsWrapperBase(sensors) {
+        auto eventQueue = std::make_unique<EventMessageQueueV2_1>(
+                MAX_RECEIVE_BUFFER_EVENT_COUNT, true /* configureEventFlagWord */);
+        mEventQueue = std::make_unique<EventMessageQueueWrapperV2_1>(eventQueue);
+    };
+
+    bool supportsPolling() const override { return false; }
+
+    bool supportsMessageQueues() const override { return true; }
+
+    EventMessageQueueWrapperBase* getEventQueue() override { return mEventQueue.get(); }
+
+    Return<void> getSensorsList(
+            ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override {
+        return mSensors->getSensorsList_2_1(_hidl_cb);
+    }
+
+    Return<Result> injectSensorData(const Event& event) override {
+        return mSensors->injectSensorData_2_1(event);
+    }
+
+    Return<Result> initialize(const MQDescriptorSync<uint32_t>& wakeLockDesc,
+                              const ::android::sp<ISensorsCallback>& callback) override {
+        return mSensors->initialize_2_1(*mEventQueue->getDesc(), wakeLockDesc, callback);
+    }
+
+  private:
+    std::unique_ptr<EventMessageQueueWrapperV2_1> mEventQueue;
+};
+
+inline sp<ISensorsWrapperV2_0> wrapISensors(sp<V2_0::ISensors> sensors) {
+    return new ISensorsWrapperV2_0(sensors);
+}
+
+inline sp<ISensorsWrapperV2_1> wrapISensors(sp<V2_1::ISensors> sensors) {
+    return new ISensorsWrapperV2_1(sensors);
+}
+
+class NoOpSensorsCallback : public ISensorsCallback {
+  public:
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<V1_0::SensorInfo>& /* sensorInfos */) override {
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& /* sensorHandles */) override {
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsConnected_2_1(
+            const hidl_vec<SensorInfo>& /* sensorInfos */) override {
+        return Return<void>();
+    }
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H
\ No newline at end of file
diff --git a/sensors/common/utils/OWNERS b/sensors/common/utils/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/sensors/common/utils/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/sensors/common/utils/convertV2_1.h b/sensors/common/utils/convertV2_1.h
new file mode 100644
index 0000000..9231011
--- /dev/null
+++ b/sensors/common/utils/convertV2_1.h
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_1_CONVERT_H
+#define ANDROID_HARDWARE_SENSORS_V2_1_CONVERT_H
+
+#include <android/hardware/sensors/2.1/types.h>
+#include <hardware/sensors.h>
+#include <sensors/convert.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+static_assert(sizeof(V1_0::Event) == sizeof(V2_1::Event),
+              "New and old Event types must have the same size");
+static_assert(sizeof(V1_0::SensorInfo) == sizeof(V2_1::SensorInfo),
+              "New and old SensorInfo types must have the same size");
+
+// The following conversion methods are safe as the only difference between
+// V1_0 and V2_1 for these types is an added enum value to SensorType which doesn't
+// change the memory layout of the types.
+inline const V1_0::Event& convertToOldEvent(const V2_1::Event& event) {
+    return reinterpret_cast<const V1_0::Event&>(event);
+}
+
+inline const std::vector<V1_0::Event>& convertToOldEvents(const std::vector<V2_1::Event>& events) {
+    return reinterpret_cast<const std::vector<V1_0::Event>&>(events);
+}
+
+inline V1_0::Event* convertToOldEvent(V2_1::Event* event) {
+    return reinterpret_cast<V1_0::Event*>(event);
+}
+
+inline const V2_1::SensorInfo& convertToNewSensorInfo(const V1_0::SensorInfo& info) {
+    return reinterpret_cast<const V2_1::SensorInfo&>(info);
+}
+
+inline const V1_0::SensorInfo& convertToOldSensorInfo(const V2_1::SensorInfo& info) {
+    return reinterpret_cast<const V1_0::SensorInfo&>(info);
+}
+
+inline const V2_1::Event& convertToNewEvent(const V1_0::Event& event) {
+    return reinterpret_cast<const V2_1::Event&>(event);
+}
+
+inline const std::vector<V2_1::Event>& convertToNewEvents(const std::vector<V1_0::Event>& events) {
+    return reinterpret_cast<const std::vector<V2_1::Event>&>(events);
+}
+
+inline const hidl_vec<V2_1::Event>& convertToNewEvents(const hidl_vec<V1_0::Event>& events) {
+    return reinterpret_cast<const hidl_vec<V2_1::Event>&>(events);
+}
+
+inline const hidl_vec<V2_1::SensorInfo>& convertToNewSensorInfos(
+        const hidl_vec<V1_0::SensorInfo>& infos) {
+    return reinterpret_cast<const hidl_vec<V2_1::SensorInfo>&>(infos);
+}
+
+inline const hidl_vec<V1_0::SensorInfo>& convertToOldSensorInfos(
+        const hidl_vec<V2_1::SensorInfo>& infos) {
+    return reinterpret_cast<const hidl_vec<V1_0::SensorInfo>&>(infos);
+}
+
+inline void convertFromSensorEvent(const sensors_event_t& src, V2_1::Event* dst) {
+    switch ((SensorType)src.type) {
+        case SensorType::HINGE_ANGLE:
+            // Only fill in values for hinge angle as other sensors
+            // will have it filled in by legacy code.
+            *dst = {
+                    .timestamp = src.timestamp,
+                    .sensorHandle = src.sensor,
+                    .sensorType = (SensorType)src.type,
+            };
+            dst->u.scalar = src.data[0];
+            break;
+        default:
+            V1_0::implementation::convertFromSensorEvent(src, convertToOldEvent(dst));
+            break;
+    }
+}
+
+inline void convertToSensorEvent(const V2_1::Event& src, sensors_event_t* dst) {
+    switch (src.sensorType) {
+        case SensorType::HINGE_ANGLE:
+            // Only fill in values for hinge angle as other sensors
+            // will have it filled in by legacy code.
+            *dst = {.version = sizeof(sensors_event_t),
+                    .sensor = src.sensorHandle,
+                    .type = (int32_t)src.sensorType,
+                    .reserved0 = 0,
+                    .timestamp = src.timestamp};
+            dst->data[0] = src.u.scalar;
+            break;
+        default:
+            V1_0::implementation::convertToSensorEvent(convertToOldEvent(src), dst);
+            break;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_1_CONVERT_H
diff --git a/sensors/common/vts/2_X/Android.bp b/sensors/common/vts/2_X/Android.bp
new file mode 100644
index 0000000..8cdb5d1
--- /dev/null
+++ b/sensors/common/vts/2_X/Android.bp
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_defaults {
+    name: "VtsHalSensorsV2_XTargetTest-defaults",
+    cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "SensorsHidlEnvironmentV2_X.cpp",
+    ],
+    export_include_dirs: ["."],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    shared_libs: [
+        "libbinder",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libfmq",
+        "VtsHalSensorsTargetTestUtils",
+    ],
+}
+
+cc_test_library {
+    name: "VtsHalSensorsV2_0TargetTest-lib",
+    defaults: ["VtsHalSensorsV2_XTargetTest-defaults"],
+}
+
+cc_test_library {
+    name: "VtsHalSensorsV2_1TargetTest-lib",
+    cflags: ["-DSENSORS_HAL_2_1"],
+    defaults: ["VtsHalSensorsV2_XTargetTest-defaults"],
+}
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp
similarity index 69%
rename from sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
rename to sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp
index 81db5a0..a8c2513 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
+++ b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
-#include "SensorsHidlEnvironmentV2_0.h"
+#include "SensorsHidlEnvironmentV2_X.h"
 
 #include <android/hardware/sensors/2.0/types.h>
+#include <android/hardware/sensors/2.1/types.h>
+
 #include <log/log.h>
 
 #include <algorithm>
@@ -26,18 +28,20 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::sensors::V1_0::Result;
-using ::android::hardware::sensors::V1_0::SensorInfo;
 using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_1::SensorInfo;
+#ifdef SENSORS_HAL_2_1
+using ::android::hardware::sensors::V2_1::ISensors;
+#else
 using ::android::hardware::sensors::V2_0::ISensors;
-using ::android::hardware::sensors::V2_0::ISensorsCallback;
+#endif
+using ::android::hardware::sensors::V2_1::ISensorsCallback;
 
 template <typename EnumType>
 constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
     return static_cast<typename std::underlying_type<EnumType>::type>(value);
 }
 
-constexpr size_t SensorsHidlEnvironmentV2_0::MAX_RECEIVE_BUFFER_EVENT_COUNT;
-
 void SensorsHalDeathRecipient::serviceDied(
         uint64_t /* cookie */,
         const ::android::wp<::android::hidl::base::V1_0::IBase>& /* service */) {
@@ -45,48 +49,34 @@
     FAIL() << "Sensors HAL died during test";
 }
 
-struct SensorsCallback : ISensorsCallback {
-    Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& /* sensorInfos */) {
-        return Return<void>();
-    }
-
-    Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& /* sensorHandles */) {
-        return Return<void>();
-    }
-};
-
-bool SensorsHidlEnvironmentV2_0::resetHal() {
+bool SensorsHidlEnvironmentV2_X::resetHal() {
     bool succeed = false;
     do {
-        mSensors = ISensors::getService(mServiceName);
+        mSensors = wrapISensors(ISensors::getService(mServiceName));
         if (mSensors == nullptr) {
             break;
         }
         mSensors->linkToDeath(mDeathRecipient, 0 /* cookie */);
 
         // Initialize FMQs
-        mEventQueue = std::make_unique<EventMessageQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
-                                                          true /* configureEventFlagWord */);
-
         mWakeLockQueue = std::make_unique<WakeLockQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
                                                          true /* configureEventFlagWord */);
 
-        if (mEventQueue == nullptr || mWakeLockQueue == nullptr) {
+        if (mWakeLockQueue == nullptr) {
             break;
         }
 
         EventFlag::deleteEventFlag(&mEventQueueFlag);
-        EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
+        EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(), &mEventQueueFlag);
         if (mEventQueueFlag == nullptr) {
             break;
         }
 
-        mSensors->initialize(*mEventQueue->getDesc(), *mWakeLockQueue->getDesc(),
-                             new SensorsCallback());
+        mSensors->initialize(*mWakeLockQueue->getDesc(), new NoOpSensorsCallback());
 
         std::vector<SensorInfo> sensorList;
         if (!mSensors->getSensorsList([&](const hidl_vec<SensorInfo>& list) { sensorList = list; })
-                 .isOk()) {
+                     .isOk()) {
             break;
         }
 
@@ -113,7 +103,7 @@
     return succeed;
 }
 
-void SensorsHidlEnvironmentV2_0::HidlTearDown() {
+void SensorsHidlEnvironmentV2_X::HidlTearDown() {
     mStopThread = true;
 
     if (mEventQueueFlag != nullptr) {
@@ -127,25 +117,25 @@
     }
 }
 
-void SensorsHidlEnvironmentV2_0::startPollingThread() {
+void SensorsHidlEnvironmentV2_X::startPollingThread() {
     mStopThread = false;
     mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
     mPollThread = std::thread(pollingThread, this);
 }
 
-void SensorsHidlEnvironmentV2_0::readEvents() {
-    size_t availableEvents = mEventQueue->availableToRead();
+void SensorsHidlEnvironmentV2_X::readEvents() {
+    size_t availableEvents = mSensors->getEventQueue()->availableToRead();
 
     if (availableEvents == 0) {
         uint32_t eventFlagState = 0;
 
         mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS), &eventFlagState);
-        availableEvents = mEventQueue->availableToRead();
+        availableEvents = mSensors->getEventQueue()->availableToRead();
     }
 
     size_t eventsToRead = std::min(availableEvents, mEventBuffer.size());
     if (eventsToRead > 0) {
-        if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) {
+        if (mSensors->getEventQueue()->read(mEventBuffer.data(), eventsToRead)) {
             mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::EVENTS_READ));
             for (size_t i = 0; i < eventsToRead; i++) {
                 addEvent(mEventBuffer[i]);
@@ -154,7 +144,7 @@
     }
 }
 
-void SensorsHidlEnvironmentV2_0::pollingThread(SensorsHidlEnvironmentV2_0* env) {
+void SensorsHidlEnvironmentV2_X::pollingThread(SensorsHidlEnvironmentV2_X* env) {
     ALOGD("polling thread start");
 
     while (!env->mStopThread.load()) {
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.h
similarity index 68%
rename from sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
rename to sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.h
index 819cdd4..01f451f 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
+++ b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.h
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
-#define ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
+#ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_X_H
+#define ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_X_H
 
+#include "ISensorsWrapper.h"
 #include "sensors-vts-utils/SensorsHidlEnvironmentBase.h"
 
-#include <android/hardware/sensors/1.0/types.h>
-#include <android/hardware/sensors/2.0/ISensors.h>
+#include <android/hardware/sensors/2.1/ISensors.h>
+#include <android/hardware/sensors/2.1/types.h>
+
 #include <fmq/MessageQueue.h>
 #include <utils/StrongPointer.h>
 
@@ -30,6 +32,10 @@
 
 using ::android::sp;
 using ::android::hardware::MessageQueue;
+using ::android::hardware::sensors::V2_1::implementation::ISensorsWrapperBase;
+using ::android::hardware::sensors::V2_1::implementation::MAX_RECEIVE_BUFFER_EVENT_COUNT;
+using ::android::hardware::sensors::V2_1::implementation::NoOpSensorsCallback;
+using ::android::hardware::sensors::V2_1::implementation::wrapISensors;
 
 class SensorsHidlTest;
 
@@ -39,14 +45,14 @@
             const ::android::wp<::android::hidl::base::V1_0::IBase>& service) override;
 };
 
-class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase {
-   public:
-    using Event = ::android::hardware::sensors::V1_0::Event;
+class SensorsHidlEnvironmentV2_X
+    : public SensorsHidlEnvironmentBase<::android::hardware::sensors::V2_1::Event> {
+  public:
     virtual void HidlTearDown() override;
 
-   protected:
+  protected:
     friend SensorsHidlTest;
-    SensorsHidlEnvironmentV2_0(const std::string& service_name)
+    SensorsHidlEnvironmentV2_X(const std::string& service_name)
         : SensorsHidlEnvironmentBase(service_name), mEventQueueFlag(nullptr) {}
 
     /**
@@ -66,19 +72,19 @@
      *
      * @param env SensorEnvironment to being polling for events on
      */
-    static void pollingThread(SensorsHidlEnvironmentV2_0* env);
+    static void pollingThread(SensorsHidlEnvironmentV2_X* env);
 
     /**
      * Reads and saves sensor events from the Event FMQ
      */
     void readEvents();
 
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV2_0);
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV2_X);
 
     /**
      * Pointer to the Sensors HAL Interface that allows the test to call HAL functions.
      */
-    sp<android::hardware::sensors::V2_0::ISensors> mSensors;
+    sp<ISensorsWrapperBase> mSensors;
 
     /**
      * Monitors the HAL for crashes, triggering test failure if seen
@@ -86,22 +92,11 @@
     sp<SensorsHalDeathRecipient> mDeathRecipient = new SensorsHalDeathRecipient();
 
     /**
-     * Type used to simplify the creation of the Event FMQ
-     */
-    typedef MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite> EventMessageQueue;
-
-    /**
      * Type used to simplify the creation of the Wake Lock FMQ
      */
     typedef MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite> WakeLockQueue;
 
     /**
-     * The Event FMQ where the test framework is able to read sensor events that the Sensors HAL
-     * has written.
-     */
-    std::unique_ptr<EventMessageQueue> mEventQueue;
-
-    /**
      * The Wake Lock FMQ is used by the test to notify the Sensors HAL whenever it has processed
      * WAKE_UP sensor events.
      */
@@ -114,14 +109,10 @@
     ::android::hardware::EventFlag* mEventQueueFlag;
 
     /**
-     * The maximum number of sensor events that can be read from the Event FMQ at one time.
-     */
-    static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 128;
-
-    /**
      * An array that is used to store sensor events read from the Event FMQ
      */
-    std::array<Event, MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
+    std::array<::android::hardware::sensors::V2_1::Event, MAX_RECEIVE_BUFFER_EVENT_COUNT>
+            mEventBuffer;
 };
 
-#endif  // ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
+#endif  // ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_X_H
diff --git a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
new file mode 100644
index 0000000..53ed259
--- /dev/null
+++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
@@ -0,0 +1,1186 @@
+/*
+ * Copyright (C) 2018 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 "SensorsHidlEnvironmentV2_X.h"
+#include "convertV2_1.h"
+#include "sensors-vts-utils/SensorsHidlTestBase.h"
+#include "sensors-vts-utils/SensorsTestSharedMemory.h"
+
+#include <android/hardware/sensors/2.1/ISensors.h>
+#include <android/hardware/sensors/2.1/types.h>
+
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include <cinttypes>
+#include <condition_variable>
+#include <cstring>
+#include <map>
+#include <vector>
+
+/**
+ * This file contains the core tests and test logic for both sensors HAL 2.0
+ * and 2.1. To make it easier to share the code between both VTS test suites,
+ * this is defined as a header so they can both include and use all pieces of
+ * code.
+ */
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::MetaDataEventType;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
+using ::android::hardware::sensors::V1_0::SensorStatus;
+using ::android::hardware::sensors::V1_0::SharedMemType;
+using ::android::hardware::sensors::V1_0::Vec3;
+using ::android::hardware::sensors::V2_1::implementation::convertToOldSensorInfos;
+using std::chrono::duration_cast;
+using std::chrono::microseconds;
+using std::chrono::milliseconds;
+using std::chrono::nanoseconds;
+
+using EventV1_0 = ::android::hardware::sensors::V1_0::Event;
+using ISensorsType = ::android::hardware::sensors::V2_1::ISensors;
+using SensorTypeVersion = ::android::hardware::sensors::V2_1::SensorType;
+using EventType = ::android::hardware::sensors::V2_1::Event;
+using SensorInfoType = ::android::hardware::sensors::V2_1::SensorInfo;
+using SensorsHidlTestBaseV2_X = SensorsHidlTestBase<SensorTypeVersion, EventType, SensorInfoType>;
+
+constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+
+class EventCallback : public IEventCallback<EventType> {
+  public:
+    void reset() {
+        mFlushMap.clear();
+        mEventMap.clear();
+    }
+
+    void onEvent(const EventType& event) override {
+        if (event.sensorType == SensorTypeVersion::META_DATA &&
+            event.u.meta.what == MetaDataEventType::META_DATA_FLUSH_COMPLETE) {
+            std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+            mFlushMap[event.sensorHandle]++;
+            mFlushCV.notify_all();
+        } else if (event.sensorType != SensorTypeVersion::ADDITIONAL_INFO) {
+            std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+            mEventMap[event.sensorHandle].push_back(event);
+            mEventCV.notify_all();
+        }
+    }
+
+    int32_t getFlushCount(int32_t sensorHandle) {
+        std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+        return mFlushMap[sensorHandle];
+    }
+
+    void waitForFlushEvents(const std::vector<SensorInfoType>& sensorsToWaitFor,
+                            int32_t numCallsToFlush, milliseconds timeout) {
+        std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+        mFlushCV.wait_for(lock, timeout,
+                          [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); });
+    }
+
+    const std::vector<EventType> getEvents(int32_t sensorHandle) {
+        std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+        return mEventMap[sensorHandle];
+    }
+
+    void waitForEvents(const std::vector<SensorInfoType>& sensorsToWaitFor, milliseconds timeout) {
+        std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+        mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); });
+    }
+
+  protected:
+    bool flushesReceived(const std::vector<SensorInfoType>& sensorsToWaitFor,
+                         int32_t numCallsToFlush) {
+        for (const SensorInfoType& sensor : sensorsToWaitFor) {
+            if (getFlushCount(sensor.sensorHandle) < numCallsToFlush) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    bool eventsReceived(const std::vector<SensorInfoType>& sensorsToWaitFor) {
+        for (const SensorInfoType& sensor : sensorsToWaitFor) {
+            if (getEvents(sensor.sensorHandle).size() == 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    std::map<int32_t, int32_t> mFlushMap;
+    std::recursive_mutex mFlushMutex;
+    std::condition_variable_any mFlushCV;
+
+    std::map<int32_t, std::vector<EventType>> mEventMap;
+    std::recursive_mutex mEventMutex;
+    std::condition_variable_any mEventCV;
+};
+
+/**
+ * Define the template specific versions of the static helper methods in
+ * SensorsHidlTestBase used to test that hinge angle is exposed properly.
+ */
+template <>
+SensorFlagBits expectedReportModeForType(::android::hardware::sensors::V2_1::SensorType type) {
+    switch (type) {
+        case ::android::hardware::sensors::V2_1::SensorType::HINGE_ANGLE:
+            return SensorFlagBits::ON_CHANGE_MODE;
+        default:
+            return expectedReportModeForType(
+                    static_cast<::android::hardware::sensors::V1_0::SensorType>(type));
+    }
+}
+
+template <>
+void assertTypeMatchStringType(::android::hardware::sensors::V2_1::SensorType type,
+                               const hidl_string& stringType) {
+    switch (type) {
+        case (::android::hardware::sensors::V2_1::SensorType::HINGE_ANGLE):
+            ASSERT_STREQ(SENSOR_STRING_TYPE_HINGE_ANGLE, stringType.c_str());
+            break;
+        default:
+            assertTypeMatchStringType(
+                    static_cast<::android::hardware::sensors::V1_0::SensorType>(type), stringType);
+            break;
+    }
+}
+
+// The main test class for SENSORS HIDL HAL.
+class SensorsHidlTest : public SensorsHidlTestBaseV2_X {
+  public:
+    virtual void SetUp() override {
+        mEnvironment = new SensorsHidlEnvironmentV2_X(GetParam());
+        mEnvironment->HidlSetUp();
+        // Ensure that we have a valid environment before performing tests
+        ASSERT_NE(getSensors(), nullptr);
+    }
+
+    virtual void TearDown() override { mEnvironment->HidlTearDown(); }
+
+  protected:
+    SensorInfoType defaultSensorByType(SensorTypeVersion type) override;
+    std::vector<SensorInfoType> getSensorsList();
+    // implementation wrapper
+
+    Return<void> getSensorsList(ISensorsType::getSensorsList_cb _hidl_cb) override {
+        return getSensors()->getSensorsList(
+                [&](const auto& list) { _hidl_cb(convertToOldSensorInfos(list)); });
+    }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override {
+        return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+    }
+
+    Return<Result> flush(int32_t sensorHandle) override {
+        return getSensors()->flush(sensorHandle);
+    }
+
+    Return<Result> injectSensorData(const EventType& event) override {
+        return getSensors()->injectSensorData(event);
+    }
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       ISensorsType::registerDirectChannel_cb _hidl_cb) override;
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+        return getSensors()->unregisterDirectChannel(channelHandle);
+    }
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    ISensorsType::configDirectReport_cb _hidl_cb) override {
+        return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+    }
+
+    inline sp<ISensorsWrapperBase>& getSensors() { return mEnvironment->mSensors; }
+
+    SensorsHidlEnvironmentBase<EventType>* getEnvironment() override { return mEnvironment; }
+
+    // Test helpers
+    void runSingleFlushTest(const std::vector<SensorInfoType>& sensors, bool activateSensor,
+                            int32_t expectedFlushCount, Result expectedResponse);
+    void runFlushTest(const std::vector<SensorInfoType>& sensors, bool activateSensor,
+                      int32_t flushCalls, int32_t expectedFlushCount, Result expectedResponse);
+
+    // Helper functions
+    void activateAllSensors(bool enable);
+    std::vector<SensorInfoType> getNonOneShotSensors();
+    std::vector<SensorInfoType> getNonOneShotAndNonSpecialSensors();
+    std::vector<SensorInfoType> getOneShotSensors();
+    std::vector<SensorInfoType> getInjectEventSensors();
+    int32_t getInvalidSensorHandle();
+    bool getDirectChannelSensor(SensorInfoType* sensor, SharedMemType* memType, RateLevel* rate);
+    void verifyDirectChannel(SharedMemType memType);
+    void verifyRegisterDirectChannel(
+            std::shared_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem,
+            int32_t* directChannelHandle, bool supportsSharedMemType,
+            bool supportsAnyDirectChannel);
+    void verifyConfigure(const SensorInfoType& sensor, SharedMemType memType,
+                         int32_t directChannelHandle, bool directChannelSupported);
+    void verifyUnregisterDirectChannel(int32_t directChannelHandle, bool directChannelSupported);
+    void checkRateLevel(const SensorInfoType& sensor, int32_t directChannelHandle,
+                        RateLevel rateLevel);
+    void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
+                                   bool* supportsAnyDirectChannel);
+
+  private:
+    // Test environment for sensors HAL.
+    SensorsHidlEnvironmentV2_X* mEnvironment;
+};
+
+Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
+    // If activating a sensor, add the handle in a set so that when test fails it can be turned off.
+    // The handle is not removed when it is deactivating on purpose so that it is not necessary to
+    // check the return value of deactivation. Deactivating a sensor more than once does not have
+    // negative effect.
+    if (enabled) {
+        mSensorHandles.insert(sensorHandle);
+    }
+    return getSensors()->activate(sensorHandle, enabled);
+}
+
+Return<void> SensorsHidlTest::registerDirectChannel(const SharedMemInfo& mem,
+                                                    ISensors::registerDirectChannel_cb cb) {
+    // If registeration of a channel succeeds, add the handle of channel to a set so that it can be
+    // unregistered when test fails. Unregister a channel does not remove the handle on purpose.
+    // Unregistering a channel more than once should not have negative effect.
+    getSensors()->registerDirectChannel(mem, [&](auto result, auto channelHandle) {
+        if (result == Result::OK) {
+            mDirectChannelHandles.insert(channelHandle);
+        }
+        cb(result, channelHandle);
+    });
+    return Void();
+}
+
+SensorInfoType SensorsHidlTest::defaultSensorByType(SensorTypeVersion type) {
+    SensorInfoType ret;
+
+    ret.type = (SensorTypeVersion)-1;
+    getSensors()->getSensorsList([&](const auto& list) {
+        const size_t count = list.size();
+        for (size_t i = 0; i < count; ++i) {
+            if (list[i].type == type) {
+                ret = list[i];
+                return;
+            }
+        }
+    });
+
+    return ret;
+}
+
+std::vector<SensorInfoType> SensorsHidlTest::getSensorsList() {
+    std::vector<SensorInfoType> ret;
+
+    getSensors()->getSensorsList([&](const auto& list) {
+        const size_t count = list.size();
+        ret.reserve(list.size());
+        for (size_t i = 0; i < count; ++i) {
+            ret.push_back(list[i]);
+        }
+    });
+
+    return ret;
+}
+
+std::vector<SensorInfoType> SensorsHidlTest::getNonOneShotSensors() {
+    std::vector<SensorInfoType> sensors;
+    for (const SensorInfoType& info : getSensorsList()) {
+        if (extractReportMode(info.flags) != SensorFlagBits::ONE_SHOT_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+std::vector<SensorInfoType> SensorsHidlTest::getNonOneShotAndNonSpecialSensors() {
+    std::vector<SensorInfoType> sensors;
+    for (const SensorInfoType& info : getSensorsList()) {
+        SensorFlagBits reportMode = extractReportMode(info.flags);
+        if (reportMode != SensorFlagBits::ONE_SHOT_MODE &&
+            reportMode != SensorFlagBits::SPECIAL_REPORTING_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+std::vector<SensorInfoType> SensorsHidlTest::getOneShotSensors() {
+    std::vector<SensorInfoType> sensors;
+    for (const SensorInfoType& info : getSensorsList()) {
+        if (extractReportMode(info.flags) == SensorFlagBits::ONE_SHOT_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+std::vector<SensorInfoType> SensorsHidlTest::getInjectEventSensors() {
+    std::vector<SensorInfoType> sensors;
+    for (const SensorInfoType& info : getSensorsList()) {
+        if (info.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION)) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+int32_t SensorsHidlTest::getInvalidSensorHandle() {
+    // Find a sensor handle that does not exist in the sensor list
+    int32_t maxHandle = 0;
+    for (const SensorInfoType& sensor : getSensorsList()) {
+        maxHandle = std::max(maxHandle, sensor.sensorHandle);
+    }
+    return maxHandle + 1;
+}
+
+// Test if sensor list returned is valid
+TEST_P(SensorsHidlTest, SensorListValid) {
+    getSensors()->getSensorsList([&](const auto& list) {
+        const size_t count = list.size();
+        for (size_t i = 0; i < count; ++i) {
+            const auto& s = list[i];
+            SCOPED_TRACE(::testing::Message()
+                         << i << "/" << count << ": "
+                         << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                         << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
+                         << " name=" << s.name);
+
+            // Test non-empty type string
+            EXPECT_FALSE(s.typeAsString.empty());
+
+            // Test defined type matches defined string type
+            EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
+
+            // Test if all sensor has name and vendor
+            EXPECT_FALSE(s.name.empty());
+            EXPECT_FALSE(s.vendor.empty());
+
+            // Test power > 0, maxRange > 0
+            EXPECT_LE(0, s.power);
+            EXPECT_LT(0, s.maxRange);
+
+            // Info type, should have no sensor
+            EXPECT_FALSE(s.type == SensorTypeVersion::ADDITIONAL_INFO ||
+                         s.type == SensorTypeVersion::META_DATA);
+
+            // Test fifoMax >= fifoReserved
+            EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
+                    << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
+
+            // Test Reporting mode valid
+            EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
+
+            // Test min max are in the right order
+            EXPECT_LE(s.minDelay, s.maxDelay);
+            // Test min/max delay matches reporting mode
+            EXPECT_NO_FATAL_FAILURE(
+                    assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
+        }
+    });
+}
+
+// Test that SetOperationMode returns the expected value
+TEST_P(SensorsHidlTest, SetOperationMode) {
+    std::vector<SensorInfoType> sensors = getInjectEventSensors();
+    if (getInjectEventSensors().size() > 0) {
+        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+    } else {
+        ASSERT_EQ(Result::BAD_VALUE, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+    }
+}
+
+// Test that an injected event is written back to the Event FMQ
+TEST_P(SensorsHidlTest, InjectSensorEventData) {
+    std::vector<SensorInfoType> sensors = getInjectEventSensors();
+    if (sensors.size() == 0) {
+        return;
+    }
+
+    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+
+    EventCallback callback;
+    getEnvironment()->registerCallback(&callback);
+
+    // AdditionalInfo event should not be sent to Event FMQ
+    EventType additionalInfoEvent;
+    additionalInfoEvent.sensorType = SensorTypeVersion::ADDITIONAL_INFO;
+    additionalInfoEvent.timestamp = android::elapsedRealtimeNano();
+
+    EventType injectedEvent;
+    injectedEvent.timestamp = android::elapsedRealtimeNano();
+    Vec3 data = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
+    injectedEvent.u.vec3 = data;
+
+    for (const auto& s : sensors) {
+        additionalInfoEvent.sensorHandle = s.sensorHandle;
+        EXPECT_EQ(Result::OK, getSensors()->injectSensorData(additionalInfoEvent));
+
+        injectedEvent.sensorType = s.type;
+        injectedEvent.sensorHandle = s.sensorHandle;
+        EXPECT_EQ(Result::OK, getSensors()->injectSensorData(injectedEvent));
+    }
+
+    // Wait for events to be written back to the Event FMQ
+    callback.waitForEvents(sensors, milliseconds(1000) /* timeout */);
+
+    for (const auto& s : sensors) {
+        auto events = callback.getEvents(s.sensorHandle);
+        auto lastEvent = events.back();
+
+        // Verify that only a single event has been received
+        ASSERT_EQ(events.size(), 1);
+
+        // Verify that the event received matches the event injected and is not the additional
+        // info event
+        ASSERT_EQ(lastEvent.sensorType, s.type);
+        ASSERT_EQ(lastEvent.sensorType, s.type);
+        ASSERT_EQ(lastEvent.timestamp, injectedEvent.timestamp);
+        ASSERT_EQ(lastEvent.u.vec3.x, injectedEvent.u.vec3.x);
+        ASSERT_EQ(lastEvent.u.vec3.y, injectedEvent.u.vec3.y);
+        ASSERT_EQ(lastEvent.u.vec3.z, injectedEvent.u.vec3.z);
+        ASSERT_EQ(lastEvent.u.vec3.status, injectedEvent.u.vec3.status);
+    }
+
+    getEnvironment()->unregisterCallback();
+    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+}
+
+// Test if sensor hal can do UI speed accelerometer streaming properly
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
+    testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(200),
+                           std::chrono::seconds(5), mAccelNormChecker);
+}
+
+// Test if sensor hal can do normal speed accelerometer streaming properly
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
+    testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(20),
+                           std::chrono::seconds(5), mAccelNormChecker);
+}
+
+// Test if sensor hal can do game speed accelerometer streaming properly
+TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) {
+    testStreamingOperation(SensorTypeVersion::ACCELEROMETER, std::chrono::milliseconds(5),
+                           std::chrono::seconds(5), mAccelNormChecker);
+}
+
+// Test if sensor hal can do UI speed gyroscope streaming properly
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
+    testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(200),
+                           std::chrono::seconds(5), mGyroNormChecker);
+}
+
+// Test if sensor hal can do normal speed gyroscope streaming properly
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
+    testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(20),
+                           std::chrono::seconds(5), mGyroNormChecker);
+}
+
+// Test if sensor hal can do game speed gyroscope streaming properly
+TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) {
+    testStreamingOperation(SensorTypeVersion::GYROSCOPE, std::chrono::milliseconds(5),
+                           std::chrono::seconds(5), mGyroNormChecker);
+}
+
+// Test if sensor hal can do UI speed magnetometer streaming properly
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
+    testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(200),
+                           std::chrono::seconds(5), NullChecker<EventType>());
+}
+
+// Test if sensor hal can do normal speed magnetometer streaming properly
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
+    testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(20),
+                           std::chrono::seconds(5), NullChecker<EventType>());
+}
+
+// Test if sensor hal can do game speed magnetometer streaming properly
+TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) {
+    testStreamingOperation(SensorTypeVersion::MAGNETIC_FIELD, std::chrono::milliseconds(5),
+                           std::chrono::seconds(5), NullChecker<EventType>());
+}
+
+// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
+TEST_P(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+    testSamplingRateHotSwitchOperation(SensorTypeVersion::ACCELEROMETER);
+    testSamplingRateHotSwitchOperation(SensorTypeVersion::ACCELEROMETER, false /*fastToSlow*/);
+}
+
+// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
+TEST_P(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
+    testSamplingRateHotSwitchOperation(SensorTypeVersion::GYROSCOPE);
+    testSamplingRateHotSwitchOperation(SensorTypeVersion::GYROSCOPE, false /*fastToSlow*/);
+}
+
+// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
+TEST_P(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
+    testSamplingRateHotSwitchOperation(SensorTypeVersion::MAGNETIC_FIELD);
+    testSamplingRateHotSwitchOperation(SensorTypeVersion::MAGNETIC_FIELD, false /*fastToSlow*/);
+}
+
+// Test if sensor hal can do accelerometer batching properly
+TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) {
+    testBatchingOperation(SensorTypeVersion::ACCELEROMETER);
+}
+
+// Test if sensor hal can do gyroscope batching properly
+TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) {
+    testBatchingOperation(SensorTypeVersion::GYROSCOPE);
+}
+
+// Test if sensor hal can do magnetometer batching properly
+TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) {
+    testBatchingOperation(SensorTypeVersion::MAGNETIC_FIELD);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at normal rate
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
+    testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM,
+                              RateLevel::NORMAL, mAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at fast rate
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
+    testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM,
+                              RateLevel::FAST, mAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at very fast rate
+TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::ASHMEM,
+                              RateLevel::VERY_FAST, mAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at normal rate
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
+    testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM,
+                              RateLevel::NORMAL, mGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at fast rate
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
+    testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
+                              mGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at very fast rate
+TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::ASHMEM,
+                              RateLevel::VERY_FAST, mGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for mag sensor at normal rate
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
+    testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM,
+                              RateLevel::NORMAL, NullChecker<EventType>());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at fast rate
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
+    testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM,
+                              RateLevel::FAST, NullChecker<EventType>());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at very fast rate
+TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::ASHMEM,
+                              RateLevel::VERY_FAST, NullChecker<EventType>());
+}
+
+// Test sensor event direct report with gralloc for accel sensor at normal rate
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
+    testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC,
+                              RateLevel::NORMAL, mAccelNormChecker);
+}
+
+// Test sensor event direct report with gralloc for accel sensor at fast rate
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
+    testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC,
+                              RateLevel::FAST, mAccelNormChecker);
+}
+
+// Test sensor event direct report with gralloc for accel sensor at very fast rate
+TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorTypeVersion::ACCELEROMETER, SharedMemType::GRALLOC,
+                              RateLevel::VERY_FAST, mAccelNormChecker);
+}
+
+// Test sensor event direct report with gralloc for gyro sensor at normal rate
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
+    testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC,
+                              RateLevel::NORMAL, mGyroNormChecker);
+}
+
+// Test sensor event direct report with gralloc for gyro sensor at fast rate
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
+    testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
+                              mGyroNormChecker);
+}
+
+// Test sensor event direct report with gralloc for gyro sensor at very fast rate
+TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorTypeVersion::GYROSCOPE, SharedMemType::GRALLOC,
+                              RateLevel::VERY_FAST, mGyroNormChecker);
+}
+
+// Test sensor event direct report with gralloc for mag sensor at normal rate
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
+    testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC,
+                              RateLevel::NORMAL, NullChecker<EventType>());
+}
+
+// Test sensor event direct report with gralloc for mag sensor at fast rate
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
+    testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC,
+                              RateLevel::FAST, NullChecker<EventType>());
+}
+
+// Test sensor event direct report with gralloc for mag sensor at very fast rate
+TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC,
+                              RateLevel::VERY_FAST, NullChecker<EventType>());
+}
+
+void SensorsHidlTest::activateAllSensors(bool enable) {
+    for (const SensorInfoType& sensorInfo : getSensorsList()) {
+        if (isValidType(sensorInfo.type)) {
+            batch(sensorInfo.sensorHandle, sensorInfo.minDelay, 0 /* maxReportLatencyNs */);
+            activate(sensorInfo.sensorHandle, enable);
+        }
+    }
+}
+
+// Test that if initialize is called twice, then the HAL writes events to the FMQs from the second
+// call to the function.
+TEST_P(SensorsHidlTest, CallInitializeTwice) {
+    // Create a helper class so that a second environment is able to be instantiated
+    class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_X {
+      public:
+        SensorsHidlEnvironmentTest(const std::string& service_name)
+            : SensorsHidlEnvironmentV2_X(service_name) {}
+    };
+
+    if (getSensorsList().size() == 0) {
+        // No sensors
+        return;
+    }
+
+    constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000;  // 1s
+    constexpr int32_t kNumEvents = 1;
+
+    // Create a new environment that calls initialize()
+    std::unique_ptr<SensorsHidlEnvironmentTest> newEnv =
+            std::make_unique<SensorsHidlEnvironmentTest>(GetParam());
+    newEnv->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if setting up the new environment failed
+    }
+
+    activateAllSensors(true);
+    // Verify that the old environment does not receive any events
+    EXPECT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0);
+    // Verify that the new event queue receives sensor events
+    EXPECT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, newEnv.get(), newEnv.get()).size(),
+              kNumEvents);
+    activateAllSensors(false);
+
+    // Cleanup the test environment
+    newEnv->HidlTearDown();
+
+    // Restore the test environment for future tests
+    getEnvironment()->HidlTearDown();
+    getEnvironment()->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if resetting the environment failed
+    }
+
+    // Ensure that the original environment is receiving events
+    activateAllSensors(true);
+    EXPECT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    activateAllSensors(false);
+}
+
+TEST_P(SensorsHidlTest, CleanupConnectionsOnInitialize) {
+    activateAllSensors(true);
+
+    // Verify that events are received
+    constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000;  // 1s
+    constexpr int32_t kNumEvents = 1;
+    ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents);
+
+    // Clear the active sensor handles so they are not disabled during TearDown
+    auto handles = mSensorHandles;
+    mSensorHandles.clear();
+    getEnvironment()->HidlTearDown();
+    getEnvironment()->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if resetting the environment failed
+    }
+
+    // Verify no events are received until sensors are re-activated
+    ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0);
+    activateAllSensors(true);
+    ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents);
+
+    // Disable sensors
+    activateAllSensors(false);
+
+    // Restore active sensors prior to clearing the environment
+    mSensorHandles = handles;
+}
+
+void SensorsHidlTest::runSingleFlushTest(const std::vector<SensorInfoType>& sensors,
+                                         bool activateSensor, int32_t expectedFlushCount,
+                                         Result expectedResponse) {
+    runFlushTest(sensors, activateSensor, 1 /* flushCalls */, expectedFlushCount, expectedResponse);
+}
+
+void SensorsHidlTest::runFlushTest(const std::vector<SensorInfoType>& sensors, bool activateSensor,
+                                   int32_t flushCalls, int32_t expectedFlushCount,
+                                   Result expectedResponse) {
+    EventCallback callback;
+    getEnvironment()->registerCallback(&callback);
+
+    for (const SensorInfoType& sensor : sensors) {
+        // Configure and activate the sensor
+        batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */);
+        activate(sensor.sensorHandle, activateSensor);
+
+        // Flush the sensor
+        for (int32_t i = 0; i < flushCalls; i++) {
+            Result flushResult = flush(sensor.sensorHandle);
+            ASSERT_EQ(flushResult, expectedResponse);
+        }
+    }
+
+    // Wait up to one second for the flush events
+    callback.waitForFlushEvents(sensors, flushCalls, milliseconds(1000) /* timeout */);
+
+    // Deactivate all sensors after waiting for flush events so pending flush events are not
+    // abandoned by the HAL.
+    for (const SensorInfoType& sensor : sensors) {
+        activate(sensor.sensorHandle, false);
+    }
+    getEnvironment()->unregisterCallback();
+
+    // Check that the correct number of flushes are present for each sensor
+    for (const SensorInfoType& sensor : sensors) {
+        ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount);
+    }
+}
+
+TEST_P(SensorsHidlTest, FlushSensor) {
+    // Find a sensor that is not a one-shot sensor
+    std::vector<SensorInfoType> sensors = getNonOneShotSensors();
+    if (sensors.size() == 0) {
+        return;
+    }
+
+    constexpr int32_t kFlushes = 5;
+    runSingleFlushTest(sensors, true /* activateSensor */, 1 /* expectedFlushCount */, Result::OK);
+    runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, Result::OK);
+}
+
+TEST_P(SensorsHidlTest, FlushOneShotSensor) {
+    // Find a sensor that is a one-shot sensor
+    std::vector<SensorInfoType> sensors = getOneShotSensors();
+    if (sensors.size() == 0) {
+        return;
+    }
+
+    runSingleFlushTest(sensors, true /* activateSensor */, 0 /* expectedFlushCount */,
+                       Result::BAD_VALUE);
+}
+
+TEST_P(SensorsHidlTest, FlushInactiveSensor) {
+    // Attempt to find a non-one shot sensor, then a one-shot sensor if necessary
+    std::vector<SensorInfoType> sensors = getNonOneShotSensors();
+    if (sensors.size() == 0) {
+        sensors = getOneShotSensors();
+        if (sensors.size() == 0) {
+            return;
+        }
+    }
+
+    runSingleFlushTest(sensors, false /* activateSensor */, 0 /* expectedFlushCount */,
+                       Result::BAD_VALUE);
+}
+
+TEST_P(SensorsHidlTest, FlushNonexistentSensor) {
+    SensorInfoType sensor;
+    std::vector<SensorInfoType> sensors = getNonOneShotSensors();
+    if (sensors.size() == 0) {
+        sensors = getOneShotSensors();
+        if (sensors.size() == 0) {
+            return;
+        }
+    }
+    sensor = sensors.front();
+    sensor.sensorHandle = getInvalidSensorHandle();
+    runSingleFlushTest(std::vector<SensorInfoType>{sensor}, false /* activateSensor */,
+                       0 /* expectedFlushCount */, Result::BAD_VALUE);
+}
+
+TEST_P(SensorsHidlTest, Batch) {
+    if (getSensorsList().size() == 0) {
+        return;
+    }
+
+    activateAllSensors(false /* enable */);
+    for (const SensorInfoType& sensor : getSensorsList()) {
+        // Call batch on inactive sensor
+        // One shot sensors have minDelay set to -1 which is an invalid
+        // parameter. Use 0 instead to avoid errors.
+        int64_t samplingPeriodNs = extractReportMode(sensor.flags) == SensorFlagBits::ONE_SHOT_MODE
+                                           ? 0
+                                           : sensor.minDelay;
+        ASSERT_EQ(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */),
+                  Result::OK);
+
+        // Activate the sensor
+        activate(sensor.sensorHandle, true /* enabled */);
+
+        // Call batch on an active sensor
+        ASSERT_EQ(batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */),
+                  Result::OK);
+    }
+    activateAllSensors(false /* enable */);
+
+    // Call batch on an invalid sensor
+    SensorInfoType sensor = getSensorsList().front();
+    sensor.sensorHandle = getInvalidSensorHandle();
+    ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
+              Result::BAD_VALUE);
+}
+
+TEST_P(SensorsHidlTest, Activate) {
+    if (getSensorsList().size() == 0) {
+        return;
+    }
+
+    // Verify that sensor events are generated when activate is called
+    for (const SensorInfoType& sensor : getSensorsList()) {
+        batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */);
+        ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);
+
+        // Call activate on a sensor that is already activated
+        ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);
+
+        // Deactivate the sensor
+        ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK);
+
+        // Call deactivate on a sensor that is already deactivated
+        ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK);
+    }
+
+    // Attempt to activate an invalid sensor
+    int32_t invalidHandle = getInvalidSensorHandle();
+    ASSERT_EQ(activate(invalidHandle, true), Result::BAD_VALUE);
+    ASSERT_EQ(activate(invalidHandle, false), Result::BAD_VALUE);
+}
+
+TEST_P(SensorsHidlTest, NoStaleEvents) {
+    constexpr milliseconds kFiveHundredMs(500);
+    constexpr milliseconds kOneSecond(1000);
+
+    // Register the callback to receive sensor events
+    EventCallback callback;
+    getEnvironment()->registerCallback(&callback);
+
+    // This test is not valid for one-shot or special-report-mode sensors
+    const std::vector<SensorInfoType> sensors = getNonOneShotAndNonSpecialSensors();
+    milliseconds maxMinDelay(0);
+    for (const SensorInfoType& sensor : sensors) {
+        milliseconds minDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
+        maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
+    }
+
+    // Activate the sensors so that they start generating events
+    activateAllSensors(true);
+
+    // According to the CDD, the first sample must be generated within 400ms + 2 * sample_time
+    // and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount
+    // of time to guarantee that a sample has arrived.
+    callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
+    activateAllSensors(false);
+
+    // Save the last received event for each sensor
+    std::map<int32_t, int64_t> lastEventTimestampMap;
+    for (const SensorInfoType& sensor : sensors) {
+        // Some on-change sensors may not report an event without stimulus
+        if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) {
+            ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
+        }
+        if (callback.getEvents(sensor.sensorHandle).size() >= 1) {
+            lastEventTimestampMap[sensor.sensorHandle] =
+                    callback.getEvents(sensor.sensorHandle).back().timestamp;
+        }
+    }
+
+    // Allow some time to pass, reset the callback, then reactivate the sensors
+    usleep(duration_cast<microseconds>(kOneSecond + (5 * maxMinDelay)).count());
+    callback.reset();
+    activateAllSensors(true);
+    callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
+    activateAllSensors(false);
+
+    for (const SensorInfoType& sensor : sensors) {
+        // Skip sensors that did not previously report an event
+        if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
+            continue;
+        }
+        // Skip on-change sensors that do not consistently report an initial event
+        if (callback.getEvents(sensor.sensorHandle).size() < 1) {
+            continue;
+        }
+        // Ensure that the first event received is not stale by ensuring that its timestamp is
+        // sufficiently different from the previous event
+        const EventType newEvent = callback.getEvents(sensor.sensorHandle).front();
+        milliseconds delta = duration_cast<milliseconds>(
+                nanoseconds(newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]));
+        milliseconds sensorMinDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
+        ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay));
+    }
+}
+
+void SensorsHidlTest::checkRateLevel(const SensorInfoType& sensor, int32_t directChannelHandle,
+                                     RateLevel rateLevel) {
+    configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel,
+                       [&](Result result, int32_t reportToken) {
+                           if (isDirectReportRateSupported(sensor, rateLevel)) {
+                               ASSERT_EQ(result, Result::OK);
+                               if (rateLevel != RateLevel::STOP) {
+                                   ASSERT_GT(reportToken, 0);
+                               }
+                           } else {
+                               ASSERT_EQ(result, Result::BAD_VALUE);
+                           }
+                       });
+}
+
+void SensorsHidlTest::queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
+                                                bool* supportsAnyDirectChannel) {
+    *supportsSharedMemType = false;
+    *supportsAnyDirectChannel = false;
+    for (const SensorInfoType& curSensor : getSensorsList()) {
+        if (isDirectChannelTypeSupported(curSensor, memType)) {
+            *supportsSharedMemType = true;
+        }
+        if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM) ||
+            isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) {
+            *supportsAnyDirectChannel = true;
+        }
+
+        if (*supportsSharedMemType && *supportsAnyDirectChannel) {
+            break;
+        }
+    }
+}
+
+void SensorsHidlTest::verifyRegisterDirectChannel(
+        std::shared_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem,
+        int32_t* directChannelHandle, bool supportsSharedMemType, bool supportsAnyDirectChannel) {
+    char* buffer = mem->getBuffer();
+    memset(buffer, 0xff, mem->getSize());
+
+    registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
+        if (supportsSharedMemType) {
+            ASSERT_EQ(result, Result::OK);
+            ASSERT_GT(channelHandle, 0);
+
+            // Verify that the memory has been zeroed
+            for (size_t i = 0; i < mem->getSize(); i++) {
+                ASSERT_EQ(buffer[i], 0x00);
+            }
+        } else {
+            Result expectedResult =
+                    supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
+            ASSERT_EQ(result, expectedResult);
+            ASSERT_EQ(channelHandle, -1);
+        }
+        *directChannelHandle = channelHandle;
+    });
+}
+
+void SensorsHidlTest::verifyConfigure(const SensorInfoType& sensor, SharedMemType memType,
+                                      int32_t directChannelHandle, bool supportsAnyDirectChannel) {
+    if (isDirectChannelTypeSupported(sensor, memType)) {
+        // Verify that each rate level is properly supported
+        checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL);
+        checkRateLevel(sensor, directChannelHandle, RateLevel::FAST);
+        checkRateLevel(sensor, directChannelHandle, RateLevel::VERY_FAST);
+        checkRateLevel(sensor, directChannelHandle, RateLevel::STOP);
+
+        // Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP
+        configDirectReport(-1 /* sensorHandle */, directChannelHandle, RateLevel::NORMAL,
+                           [](Result result, int32_t /* reportToken */) {
+                               ASSERT_EQ(result, Result::BAD_VALUE);
+                           });
+        configDirectReport(
+                -1 /* sensorHandle */, directChannelHandle, RateLevel::STOP,
+                [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
+    } else {
+        // directChannelHandle will be -1 here, HAL should either reject it as a bad value if there
+        // is some level of direct channel report, otherwise return INVALID_OPERATION if direct
+        // channel is not supported at all
+        Result expectedResult =
+                supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
+        configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL,
+                           [expectedResult](Result result, int32_t /* reportToken */) {
+                               ASSERT_EQ(result, expectedResult);
+                           });
+    }
+}
+
+void SensorsHidlTest::verifyUnregisterDirectChannel(int32_t directChannelHandle,
+                                                    bool supportsAnyDirectChannel) {
+    Result expectedResult = supportsAnyDirectChannel ? Result::OK : Result::INVALID_OPERATION;
+    ASSERT_EQ(unregisterDirectChannel(directChannelHandle), expectedResult);
+}
+
+void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) {
+    constexpr size_t kNumEvents = 1;
+    constexpr size_t kMemSize = kNumEvents * kEventSize;
+
+    std::shared_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem(
+            SensorsTestSharedMemory<SensorTypeVersion, EventType>::create(memType, kMemSize));
+    ASSERT_NE(mem, nullptr);
+
+    bool supportsSharedMemType;
+    bool supportsAnyDirectChannel;
+    queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel);
+
+    for (const SensorInfoType& sensor : getSensorsList()) {
+        int32_t directChannelHandle = 0;
+        verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType,
+                                    supportsAnyDirectChannel);
+        verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel);
+        verifyUnregisterDirectChannel(directChannelHandle, supportsAnyDirectChannel);
+    }
+}
+
+TEST_P(SensorsHidlTest, DirectChannelAshmem) {
+    verifyDirectChannel(SharedMemType::ASHMEM);
+}
+
+TEST_P(SensorsHidlTest, DirectChannelGralloc) {
+    verifyDirectChannel(SharedMemType::GRALLOC);
+}
+
+bool SensorsHidlTest::getDirectChannelSensor(SensorInfoType* sensor, SharedMemType* memType,
+                                             RateLevel* rate) {
+    bool found = false;
+    for (const SensorInfoType& curSensor : getSensorsList()) {
+        if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM)) {
+            *memType = SharedMemType::ASHMEM;
+            *sensor = curSensor;
+            found = true;
+            break;
+        } else if (isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) {
+            *memType = SharedMemType::GRALLOC;
+            *sensor = curSensor;
+            found = true;
+            break;
+        }
+    }
+
+    if (found) {
+        // Find a supported rate level
+        constexpr int kNumRateLevels = 3;
+        RateLevel rates[kNumRateLevels] = {RateLevel::NORMAL, RateLevel::FAST,
+                                           RateLevel::VERY_FAST};
+        *rate = RateLevel::STOP;
+        for (int i = 0; i < kNumRateLevels; i++) {
+            if (isDirectReportRateSupported(*sensor, rates[i])) {
+                *rate = rates[i];
+            }
+        }
+
+        // At least one rate level must be supported
+        EXPECT_NE(*rate, RateLevel::STOP);
+    }
+    return found;
+}
+
+TEST_P(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) {
+    SensorInfoType sensor;
+    SharedMemType memType;
+    RateLevel rate;
+    if (!getDirectChannelSensor(&sensor, &memType, &rate)) {
+        return;
+    }
+
+    // Verify that an invalid channel handle produces a BAD_VALUE result
+    configDirectReport(sensor.sensorHandle, -1, rate, [](Result result, int32_t /* reportToken */) {
+        ASSERT_EQ(result, Result::BAD_VALUE);
+    });
+}
+
+TEST_P(SensorsHidlTest, CleanupDirectConnectionOnInitialize) {
+    constexpr size_t kNumEvents = 1;
+    constexpr size_t kMemSize = kNumEvents * kEventSize;
+
+    SensorInfoType sensor;
+    SharedMemType memType;
+    RateLevel rate;
+
+    if (!getDirectChannelSensor(&sensor, &memType, &rate)) {
+        return;
+    }
+
+    std::shared_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem(
+            SensorsTestSharedMemory<SensorTypeVersion, EventType>::create(memType, kMemSize));
+    ASSERT_NE(mem, nullptr);
+
+    int32_t directChannelHandle = 0;
+    registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
+        ASSERT_EQ(result, Result::OK);
+        directChannelHandle = channelHandle;
+    });
+
+    // Configure the channel and expect success
+    configDirectReport(
+            sensor.sensorHandle, directChannelHandle, rate,
+            [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
+
+    // Call initialize() via the environment setup to cause the HAL to re-initialize
+    // Clear the active direct connections so they are not stopped during TearDown
+    auto handles = mDirectChannelHandles;
+    mDirectChannelHandles.clear();
+    getEnvironment()->HidlTearDown();
+    getEnvironment()->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if resetting the environment failed
+    }
+
+    // Attempt to configure the direct channel and expect it to fail
+    configDirectReport(
+            sensor.sensorHandle, directChannelHandle, rate,
+            [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::BAD_VALUE); });
+
+    // Restore original handles, though they should already be deactivated
+    mDirectChannelHandles = handles;
+}
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index bb4d329..ca4346a 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -20,9 +20,6 @@
     cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
     srcs: [
         "GrallocWrapper.cpp",
-        "SensorsHidlEnvironmentBase.cpp",
-        "SensorsHidlTestBase.cpp",
-        "SensorsTestSharedMemory.cpp",
     ],
     export_include_dirs: [
         "include",
@@ -30,6 +27,9 @@
     local_include_dirs: [
         "include/sensors-vts-utils",
     ],
+    shared_libs: [
+        "libutils",
+    ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
@@ -37,5 +37,7 @@
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
     ],
 }
diff --git a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
deleted file mode 100644
index fa0e2e9..0000000
--- a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2018 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 "SensorsHidlEnvironmentBase.h"
-
-void SensorsHidlEnvironmentBase::HidlSetUp() {
-    ASSERT_TRUE(resetHal()) << "could not get hidl service";
-
-    mCollectionEnabled = false;
-    startPollingThread();
-
-    // In case framework just stopped for test and there is sensor events in the pipe,
-    // wait some time for those events to be cleared to avoid them messing up the test.
-    std::this_thread::sleep_for(std::chrono::seconds(3));
-}
-
-void SensorsHidlEnvironmentBase::HidlTearDown() {
-    mStopThread = true;
-    if (mPollThread.joinable()) {
-        mPollThread.detach();
-    }
-}
-
-void SensorsHidlEnvironmentBase::catEvents(std::vector<Event>* output) {
-    std::lock_guard<std::mutex> lock(mEventsMutex);
-    if (output) {
-        output->insert(output->end(), mEvents.begin(), mEvents.end());
-    }
-    mEvents.clear();
-}
-
-void SensorsHidlEnvironmentBase::setCollection(bool enable) {
-    std::lock_guard<std::mutex> lock(mEventsMutex);
-    mCollectionEnabled = enable;
-}
-
-void SensorsHidlEnvironmentBase::addEvent(const Event& ev) {
-    std::lock_guard<std::mutex> lock(mEventsMutex);
-    if (mCollectionEnabled) {
-        mEvents.push_back(ev);
-    }
-
-    if (mCallback != nullptr) {
-        mCallback->onEvent(ev);
-    }
-}
-
-void SensorsHidlEnvironmentBase::registerCallback(IEventCallback* callback) {
-    std::lock_guard<std::mutex> lock(mEventsMutex);
-    mCallback = callback;
-}
-
-void SensorsHidlEnvironmentBase::unregisterCallback() {
-    std::lock_guard<std::mutex> lock(mEventsMutex);
-    mCallback = nullptr;
-}
\ No newline at end of file
diff --git a/sensors/common/vts/utils/SensorsHidlTestBase.cpp b/sensors/common/vts/utils/SensorsHidlTestBase.cpp
deleted file mode 100644
index 18549df..0000000
--- a/sensors/common/vts/utils/SensorsHidlTestBase.cpp
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * Copyright (C) 2018 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 "SensorsHidlTestBase.h"
-
-#include "sensors-vts-utils/GrallocWrapper.h"
-#include "sensors-vts-utils/SensorsTestSharedMemory.h"
-
-#include <hardware/sensors.h>  // for sensor type strings
-#include <log/log.h>
-#include <utils/SystemClock.h>
-
-#include <cinttypes>
-
-using ::android::sp;
-using ::android::hardware::hidl_string;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::sensors::V1_0::SensorFlagShift;
-using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
-
-const Vec3NormChecker SensorsHidlTestBase::sAccelNormChecker(
-    Vec3NormChecker::byNominal(GRAVITY_EARTH, 1.0f /*m/s^2*/));
-const Vec3NormChecker SensorsHidlTestBase::sGyroNormChecker(
-    Vec3NormChecker::byNominal(0.f, 0.1f /*rad/s*/));
-
-std::vector<Event> SensorsHidlTestBase::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
-                                                      bool clearBeforeStart,
-                                                      bool changeCollection) {
-    return collectEvents(timeLimitUs, nEventLimit, getEnvironment(), clearBeforeStart,
-                         changeCollection);
-}
-
-std::vector<Event> SensorsHidlTestBase::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
-                                                      SensorsHidlEnvironmentBase* environment,
-                                                      bool clearBeforeStart,
-                                                      bool changeCollection) {
-    std::vector<Event> events;
-    constexpr useconds_t SLEEP_GRANULARITY = 100 * 1000;  // granularity 100 ms
-
-    ALOGI("collect max of %zu events for %d us, clearBeforeStart %d", nEventLimit, timeLimitUs,
-          clearBeforeStart);
-
-    if (changeCollection) {
-        environment->setCollection(true);
-    }
-    if (clearBeforeStart) {
-        environment->catEvents(nullptr);
-    }
-
-    while (timeLimitUs > 0) {
-        useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
-        usleep(duration);
-        timeLimitUs -= duration;
-
-        environment->catEvents(&events);
-        if (events.size() >= nEventLimit) {
-            break;
-        }
-        ALOGV("time to go = %d, events to go = %d", (int)timeLimitUs,
-              (int)(nEventLimit - events.size()));
-    }
-
-    if (changeCollection) {
-        environment->setCollection(false);
-    }
-    return events;
-}
-
-void SensorsHidlTestBase::assertTypeMatchStringType(SensorType type,
-                                                    const hidl_string& stringType) {
-    if (type >= SensorType::DEVICE_PRIVATE_BASE) {
-        return;
-    }
-
-    switch (type) {
-#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type)                      \
-    case SensorType::type:                                           \
-        ASSERT_STREQ(SENSOR_STRING_TYPE_##type, stringType.c_str()); \
-        break;
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
-        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
-        default:
-            FAIL() << "Type " << static_cast<int>(type)
-                   << " in android defined range is not checked, "
-                   << "stringType = " << stringType;
-#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
-    }
-}
-
-void SensorsHidlTestBase::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) {
-    if (type >= SensorType::DEVICE_PRIVATE_BASE) {
-        return;
-    }
-
-    SensorFlagBits expected = expectedReportModeForType(type);
-
-    ASSERT_TRUE(expected == (SensorFlagBits)-1 || expected == reportMode)
-        << "reportMode=" << static_cast<int>(reportMode)
-        << "expected=" << static_cast<int>(expected);
-}
-
-void SensorsHidlTestBase::assertDelayMatchReportMode(int32_t minDelay, int32_t maxDelay,
-                                                     SensorFlagBits reportMode) {
-    switch (reportMode) {
-        case SensorFlagBits::CONTINUOUS_MODE:
-            ASSERT_LT(0, minDelay);
-            ASSERT_LE(0, maxDelay);
-            break;
-        case SensorFlagBits::ON_CHANGE_MODE:
-            ASSERT_LE(0, minDelay);
-            ASSERT_LE(0, maxDelay);
-            break;
-        case SensorFlagBits::ONE_SHOT_MODE:
-            ASSERT_EQ(-1, minDelay);
-            ASSERT_EQ(0, maxDelay);
-            break;
-        case SensorFlagBits::SPECIAL_REPORTING_MODE:
-            // do not enforce anything for special reporting mode
-            break;
-        default:
-            FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
-    }
-}
-
-// return -1 means no expectation for this type
-SensorFlagBits SensorsHidlTestBase::expectedReportModeForType(SensorType type) {
-    switch (type) {
-        case SensorType::ACCELEROMETER:
-        case SensorType::ACCELEROMETER_UNCALIBRATED:
-        case SensorType::GYROSCOPE:
-        case SensorType::MAGNETIC_FIELD:
-        case SensorType::ORIENTATION:
-        case SensorType::PRESSURE:
-        case SensorType::TEMPERATURE:
-        case SensorType::GRAVITY:
-        case SensorType::LINEAR_ACCELERATION:
-        case SensorType::ROTATION_VECTOR:
-        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
-        case SensorType::GAME_ROTATION_VECTOR:
-        case SensorType::GYROSCOPE_UNCALIBRATED:
-        case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
-        case SensorType::POSE_6DOF:
-        case SensorType::HEART_BEAT:
-            return SensorFlagBits::CONTINUOUS_MODE;
-
-        case SensorType::LIGHT:
-        case SensorType::PROXIMITY:
-        case SensorType::RELATIVE_HUMIDITY:
-        case SensorType::AMBIENT_TEMPERATURE:
-        case SensorType::HEART_RATE:
-        case SensorType::DEVICE_ORIENTATION:
-        case SensorType::STEP_COUNTER:
-        case SensorType::LOW_LATENCY_OFFBODY_DETECT:
-            return SensorFlagBits::ON_CHANGE_MODE;
-
-        case SensorType::SIGNIFICANT_MOTION:
-        case SensorType::WAKE_GESTURE:
-        case SensorType::GLANCE_GESTURE:
-        case SensorType::PICK_UP_GESTURE:
-        case SensorType::MOTION_DETECT:
-        case SensorType::STATIONARY_DETECT:
-            return SensorFlagBits::ONE_SHOT_MODE;
-
-        case SensorType::STEP_DETECTOR:
-        case SensorType::TILT_DETECTOR:
-        case SensorType::WRIST_TILT_GESTURE:
-        case SensorType::DYNAMIC_SENSOR_META:
-            return SensorFlagBits::SPECIAL_REPORTING_MODE;
-
-        default:
-            ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
-            return (SensorFlagBits)-1;
-    }
-}
-
-bool SensorsHidlTestBase::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) {
-    unsigned int r = static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT) >>
-                     static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT);
-    return r >= static_cast<unsigned int>(rate);
-}
-
-bool SensorsHidlTestBase::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) {
-    switch (type) {
-        case SharedMemType::ASHMEM:
-            return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0;
-        case SharedMemType::GRALLOC:
-            return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0;
-        default:
-            return false;
-    }
-}
-
-void SensorsHidlTestBase::testDirectReportOperation(SensorType type, SharedMemType memType,
-                                                    RateLevel rate,
-                                                    const SensorEventsChecker& checker) {
-    constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
-    constexpr size_t kNEvent = 4096;
-    constexpr size_t kMemSize = kEventSize * kNEvent;
-
-    constexpr float kNormalNominal = 50;
-    constexpr float kFastNominal = 200;
-    constexpr float kVeryFastNominal = 800;
-
-    constexpr float kNominalTestTimeSec = 1.f;
-    constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f;  // 0.5 second for initialization
-
-    SensorInfo sensor = defaultSensorByType(type);
-
-    if (!isValidType(sensor.type)) {
-        // no default sensor of this type
-        return;
-    }
-
-    if (!isDirectReportRateSupported(sensor, rate)) {
-        return;
-    }
-
-    if (!isDirectChannelTypeSupported(sensor, memType)) {
-        return;
-    }
-
-    std::unique_ptr<SensorsTestSharedMemory> mem(
-        SensorsTestSharedMemory::create(memType, kMemSize));
-    ASSERT_NE(mem, nullptr);
-
-    char* buffer = mem->getBuffer();
-    // fill memory with data
-    for (size_t i = 0; i < kMemSize; ++i) {
-        buffer[i] = '\xcc';
-    }
-
-    int32_t channelHandle;
-    registerDirectChannel(mem->getSharedMemInfo(),
-                          [&channelHandle](auto result, auto channelHandle_) {
-                              ASSERT_EQ(result, Result::OK);
-                              channelHandle = channelHandle_;
-                          });
-
-    // check memory is zeroed
-    for (size_t i = 0; i < kMemSize; ++i) {
-        ASSERT_EQ(buffer[i], '\0');
-    }
-
-    int32_t eventToken;
-    configDirectReport(sensor.sensorHandle, channelHandle, rate,
-                       [&eventToken](auto result, auto token) {
-                           ASSERT_EQ(result, Result::OK);
-                           eventToken = token;
-                       });
-
-    usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f));
-    auto events = mem->parseEvents();
-
-    // find norminal rate
-    float nominalFreq = 0.f;
-    switch (rate) {
-        case RateLevel::NORMAL:
-            nominalFreq = kNormalNominal;
-            break;
-        case RateLevel::FAST:
-            nominalFreq = kFastNominal;
-            break;
-        case RateLevel::VERY_FAST:
-            nominalFreq = kVeryFastNominal;
-            break;
-        case RateLevel::STOP:
-            FAIL();
-    }
-
-    // allowed to be between 55% and 220% of nominal freq
-    ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec));
-    ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec));
-
-    int64_t lastTimestamp = 0;
-    bool typeErrorReported = false;
-    bool tokenErrorReported = false;
-    bool timestampErrorReported = false;
-    std::vector<Event> sensorEvents;
-    for (auto& e : events) {
-        if (!tokenErrorReported) {
-            EXPECT_EQ(eventToken, e.sensorHandle)
-                << (tokenErrorReported = true,
-                    "Event token does not match that retured from configDirectReport");
-        }
-
-        if (isMetaSensorType(e.sensorType)) {
-            continue;
-        }
-        sensorEvents.push_back(e);
-
-        if (!typeErrorReported) {
-            EXPECT_EQ(type, e.sensorType)
-                << (typeErrorReported = true,
-                    "Type in event does not match type of sensor registered.");
-        }
-        if (!timestampErrorReported) {
-            EXPECT_GT(e.timestamp, lastTimestamp)
-                << (timestampErrorReported = true, "Timestamp not monotonically increasing");
-        }
-        lastTimestamp = e.timestamp;
-    }
-
-    std::string s;
-    EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
-
-    // stop sensor and unregister channel
-    configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
-                       [](auto result, auto) { EXPECT_EQ(result, Result::OK); });
-    EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
-}
-
-void SensorsHidlTestBase::testStreamingOperation(SensorType type,
-                                                 std::chrono::nanoseconds samplingPeriod,
-                                                 std::chrono::seconds duration,
-                                                 const SensorEventsChecker& checker) {
-    std::vector<Event> events;
-    std::vector<Event> sensorEvents;
-
-    const int64_t samplingPeriodInNs = samplingPeriod.count();
-    const int64_t batchingPeriodInNs = 0;  // no batching
-    const useconds_t minTimeUs = std::chrono::microseconds(duration).count();
-    const size_t minNEvent = duration / samplingPeriod;
-
-    SensorInfo sensor = defaultSensorByType(type);
-
-    if (!isValidType(sensor.type)) {
-        // no default sensor of this type
-        return;
-    }
-
-    if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) {
-        // rate not supported
-        return;
-    }
-
-    int32_t handle = sensor.sensorHandle;
-
-    ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
-    ASSERT_EQ(activate(handle, 1), Result::OK);
-    events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
-    ASSERT_EQ(activate(handle, 0), Result::OK);
-
-    ALOGI("Collected %zu samples", events.size());
-
-    ASSERT_GT(events.size(), 0u);
-
-    bool handleMismatchReported = false;
-    bool metaSensorTypeErrorReported = false;
-    for (auto& e : events) {
-        if (e.sensorType == type) {
-            // avoid generating hundreds of error
-            if (!handleMismatchReported) {
-                EXPECT_EQ(e.sensorHandle, handle)
-                    << (handleMismatchReported = true,
-                        "Event of the same type must come from the sensor registered");
-            }
-            sensorEvents.push_back(e);
-        } else {
-            // avoid generating hundreds of error
-            if (!metaSensorTypeErrorReported) {
-                EXPECT_TRUE(isMetaSensorType(e.sensorType))
-                    << (metaSensorTypeErrorReported = true,
-                        "Only meta types are allowed besides the type registered");
-            }
-        }
-    }
-
-    std::string s;
-    EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
-
-    EXPECT_GE(sensorEvents.size(),
-              minNEvent / 2);  // make sure returned events are not all meta
-}
-
-void SensorsHidlTestBase::testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow) {
-    std::vector<Event> events1, events2;
-
-    constexpr int64_t batchingPeriodInNs = 0;          // no batching
-    constexpr int64_t collectionTimeoutUs = 60000000;  // 60s
-    constexpr size_t minNEvent = 50;
-
-    SensorInfo sensor = defaultSensorByType(type);
-
-    if (!isValidType(sensor.type)) {
-        // no default sensor of this type
-        return;
-    }
-
-    int32_t handle = sensor.sensorHandle;
-    int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
-    int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll;
-
-    if (minSamplingPeriodInNs == maxSamplingPeriodInNs) {
-        // only support single rate
-        return;
-    }
-
-    int64_t firstCollectionPeriod = fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
-    int64_t secondCollectionPeriod = !fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
-
-    // first collection
-    ASSERT_EQ(batch(handle, firstCollectionPeriod, batchingPeriodInNs), Result::OK);
-    ASSERT_EQ(activate(handle, 1), Result::OK);
-
-    usleep(500000);  // sleep 0.5 sec to wait for change rate to happen
-    events1 = collectEvents(collectionTimeoutUs, minNEvent);
-
-    // second collection, without stop sensor
-    ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK);
-
-    usleep(500000);  // sleep 0.5 sec to wait for change rate to happen
-    events2 = collectEvents(collectionTimeoutUs, minNEvent);
-
-    // end of collection, stop sensor
-    ASSERT_EQ(activate(handle, 0), Result::OK);
-
-    ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size());
-
-    ASSERT_GT(events1.size(), 0u);
-    ASSERT_GT(events2.size(), 0u);
-
-    int64_t minDelayAverageInterval, maxDelayAverageInterval;
-    std::vector<Event>& minDelayEvents(fastToSlow ? events1 : events2);
-    std::vector<Event>& maxDelayEvents(fastToSlow ? events2 : events1);
-
-    size_t nEvent = 0;
-    int64_t prevTimestamp = -1;
-    int64_t timestampInterval = 0;
-    for (auto& e : minDelayEvents) {
-        if (e.sensorType == type) {
-            ASSERT_EQ(e.sensorHandle, handle);
-            if (prevTimestamp > 0) {
-                timestampInterval += e.timestamp - prevTimestamp;
-            }
-            prevTimestamp = e.timestamp;
-            ++nEvent;
-        }
-    }
-    ASSERT_GT(nEvent, 2u);
-    minDelayAverageInterval = timestampInterval / (nEvent - 1);
-
-    nEvent = 0;
-    prevTimestamp = -1;
-    timestampInterval = 0;
-    for (auto& e : maxDelayEvents) {
-        if (e.sensorType == type) {
-            ASSERT_EQ(e.sensorHandle, handle);
-            if (prevTimestamp > 0) {
-                timestampInterval += e.timestamp - prevTimestamp;
-            }
-            prevTimestamp = e.timestamp;
-            ++nEvent;
-        }
-    }
-    ASSERT_GT(nEvent, 2u);
-    maxDelayAverageInterval = timestampInterval / (nEvent - 1);
-
-    // change of rate is significant.
-    ALOGI("min/maxDelayAverageInterval = %" PRId64 " %" PRId64, minDelayAverageInterval,
-          maxDelayAverageInterval);
-    EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10);
-
-    // fastest rate sampling time is close to spec
-    EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
-              minSamplingPeriodInNs / 10);
-
-    // slowest rate sampling time is close to spec
-    EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
-              maxSamplingPeriodInNs / 10);
-}
-
-void SensorsHidlTestBase::testBatchingOperation(SensorType type) {
-    std::vector<Event> events;
-
-    constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000;
-    constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
-
-    SensorInfo sensor = defaultSensorByType(type);
-
-    if (!isValidType(sensor.type)) {
-        // no default sensor of this type
-        return;
-    }
-
-    int32_t handle = sensor.sensorHandle;
-    int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
-    uint32_t minFifoCount = sensor.fifoReservedEventCount;
-    int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs;
-
-    if (batchingPeriodInNs < oneSecondInNs) {
-        // batching size too small to test reliably
-        return;
-    }
-
-    batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs);
-
-    ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000));
-
-    int64_t allowedBatchDeliverTimeNs = std::max(oneSecondInNs, batchingPeriodInNs / 10);
-
-    ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK);
-    ASSERT_EQ(activate(handle, 1), Result::OK);
-
-    usleep(500000);  // sleep 0.5 sec to wait for initialization
-    ASSERT_EQ(flush(handle), Result::OK);
-
-    // wait for 80% of the reserved batching period
-    // there should not be any significant amount of events
-    // since collection is not enabled all events will go down the drain
-    usleep(batchingPeriodInNs / 1000 * 8 / 10);
-
-    getEnvironment()->setCollection(true);
-    // clean existing collections
-    collectEvents(0 /*timeLimitUs*/, 0 /*nEventLimit*/, true /*clearBeforeStart*/,
-                  false /*change collection*/);
-
-    // 0.8 + 0.2 times the batching period
-    usleep(batchingPeriodInNs / 1000 * 8 / 10);
-    ASSERT_EQ(flush(handle), Result::OK);
-
-    // plus some time for the event to deliver
-    events = collectEvents(allowedBatchDeliverTimeNs / 1000, minFifoCount,
-                           false /*clearBeforeStart*/, false /*change collection*/);
-
-    getEnvironment()->setCollection(false);
-    ASSERT_EQ(activate(handle, 0), Result::OK);
-
-    size_t nEvent = 0;
-    for (auto& e : events) {
-        if (e.sensorType == type && e.sensorHandle == handle) {
-            ++nEvent;
-        }
-    }
-
-    // at least reach 90% of advertised capacity
-    ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10));
-}
diff --git a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
deleted file mode 100644
index 3b068bd..0000000
--- a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2018 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 "SensorsTestSharedMemory.h"
-
-#include <log/log.h>
-
-#include <sys/mman.h>
-#include <cinttypes>
-
-using namespace ::android::hardware::sensors::V1_0;
-
-SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const {
-    SharedMemInfo mem = {.type = mType,
-                         .format = SharedMemFormat::SENSORS_EVENT,
-                         .size = static_cast<uint32_t>(mSize),
-                         .memoryHandle = mNativeHandle};
-    return mem;
-}
-
-char* SensorsTestSharedMemory::getBuffer() const {
-    return mBuffer;
-}
-
-size_t SensorsTestSharedMemory::getSize() const {
-    return mSize;
-}
-
-std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
-    constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
-    constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
-    constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN);
-    constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE);
-    constexpr size_t kOffsetAtomicCounter =
-        static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER);
-    constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP);
-    constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA);
-
-    std::vector<Event> events;
-    std::vector<float> data(16);
-
-    while (offset + kEventSize <= mSize) {
-        int64_t atomicCounter =
-            *reinterpret_cast<uint32_t*>(mBuffer + offset + kOffsetAtomicCounter);
-        if (atomicCounter <= lastCounter) {
-            ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter,
-                  lastCounter);
-            break;
-        }
-
-        int32_t size = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetSize);
-        if (size != kEventSize) {
-            // unknown error, events parsed may be wrong, remove all
-            events.clear();
-            break;
-        }
-
-        int32_t token = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetToken);
-        int32_t type = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetType);
-        int64_t timestamp = *reinterpret_cast<int64_t*>(mBuffer + offset + kOffsetTimestamp);
-
-        ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32
-              ", timestamp %" PRId64,
-              offset, atomicCounter, token, type, timestamp);
-
-        Event event = {
-            .timestamp = timestamp,
-            .sensorHandle = token,
-            .sensorType = static_cast<SensorType>(type),
-        };
-        event.u.data = android::hardware::hidl_array<float, 16>(
-            reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
-
-        events.push_back(event);
-
-        lastCounter = atomicCounter;
-        offset += kEventSize;
-    }
-
-    return events;
-}
-
-SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size)
-    : mType(type), mSize(0), mBuffer(nullptr) {
-    native_handle_t* handle = nullptr;
-    char* buffer = nullptr;
-    switch (type) {
-        case SharedMemType::ASHMEM: {
-            int fd;
-            handle = ::native_handle_create(1 /*nFds*/, 0 /*nInts*/);
-            if (handle != nullptr) {
-                handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size);
-                if (handle->data[0] > 0) {
-                    // memory is pinned by default
-                    buffer = static_cast<char*>(
-                        ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
-                    if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
-                        break;
-                    }
-                    ::native_handle_close(handle);
-                }
-                ::native_handle_delete(handle);
-                handle = nullptr;
-            }
-            break;
-        }
-        case SharedMemType::GRALLOC: {
-            mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
-            if (!mGrallocWrapper->isInitialized()) {
-                break;
-            }
-
-            std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
-            handle = buf.first;
-            buffer = static_cast<char*>(buf.second);
-            break;
-        }
-        default:
-            break;
-    }
-
-    if (buffer != nullptr) {
-        mNativeHandle = handle;
-        mSize = size;
-        mBuffer = buffer;
-    }
-}
-
-SensorsTestSharedMemory::~SensorsTestSharedMemory() {
-    switch (mType) {
-        case SharedMemType::ASHMEM: {
-            if (mSize != 0) {
-                ::munmap(mBuffer, mSize);
-                mBuffer = nullptr;
-
-                ::native_handle_close(mNativeHandle);
-                ::native_handle_delete(mNativeHandle);
-
-                mNativeHandle = nullptr;
-                mSize = 0;
-            }
-            break;
-        }
-        case SharedMemType::GRALLOC: {
-            if (mSize != 0) {
-                mGrallocWrapper->freeBuffer(mNativeHandle);
-                mNativeHandle = nullptr;
-                mSize = 0;
-            }
-            break;
-        }
-        default: {
-            if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
-                ALOGE(
-                    "SensorsTestSharedMemory %p not properly destructed: "
-                    "type %d, native handle %p, size %zu, buffer %p",
-                    this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
-            }
-            break;
-        }
-    }
-}
-
-SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) {
-    constexpr size_t kMaxSize = 128 * 1024 * 1024;  // sensor test should not need more than 128M
-    if (size == 0 || size >= kMaxSize) {
-        return nullptr;
-    }
-
-    auto m = new SensorsTestSharedMemory(type, size);
-    if (m->mSize != size || m->mBuffer == nullptr) {
-        delete m;
-        m = nullptr;
-    }
-    return m;
-}
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h
index b5daccc..d6d3227 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h
@@ -17,26 +17,26 @@
 #ifndef ANDROID_SENSOR_EVENTS_CHECKER_H
 #define ANDROID_SENSOR_EVENTS_CHECKER_H
 
-#include <android/hardware/sensors/1.0/types.h>
-
 #include <cmath>
 
+template <class EventType>
 class SensorEventsChecker {
-   public:
-    using Event = ::android::hardware::sensors::V1_0::Event;
-    virtual bool check(const std::vector<Event>& events, std::string* out) const = 0;
+  public:
+    virtual bool check(const std::vector<EventType>& events, std::string* out) const = 0;
     virtual ~SensorEventsChecker() {}
 };
 
-class NullChecker : public SensorEventsChecker {
-   public:
-    virtual bool check(const std::vector<Event>&, std::string*) const { return true; }
+template <class EventType>
+class NullChecker : public SensorEventsChecker<EventType> {
+  public:
+    virtual bool check(const std::vector<EventType>&, std::string*) const { return true; }
 };
 
-class SensorEventPerEventChecker : public SensorEventsChecker {
-   public:
-    virtual bool checkEvent(const Event& event, std::string* out) const = 0;
-    virtual bool check(const std::vector<Event>& events, std::string* out) const {
+template <class EventType>
+class SensorEventPerEventChecker : public SensorEventsChecker<EventType> {
+  public:
+    virtual bool checkEvent(const EventType& event, std::string* out) const = 0;
+    virtual bool check(const std::vector<EventType>& events, std::string* out) const {
         for (const auto& e : events) {
             if (!checkEvent(e, out)) {
                 return false;
@@ -46,14 +46,15 @@
     }
 };
 
-class Vec3NormChecker : public SensorEventPerEventChecker {
-   public:
+template <class EventType>
+class Vec3NormChecker : public SensorEventPerEventChecker<EventType> {
+  public:
     Vec3NormChecker(float min, float max) : mLowerLimit(min), mUpperLimit(max) {}
-    static Vec3NormChecker byNominal(float nominal, float allowedError) {
-        return Vec3NormChecker(nominal - allowedError, nominal + allowedError);
+    static Vec3NormChecker<EventType> byNominal(float nominal, float allowedError) {
+        return Vec3NormChecker<EventType>(nominal - allowedError, nominal + allowedError);
     }
 
-    virtual bool checkEvent(const Event& event, std::string* out) const {
+    virtual bool checkEvent(const EventType& event, std::string* out) const {
         android::hardware::sensors::V1_0::Vec3 v = event.u.vec3;
         float norm = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
         if (norm < mLowerLimit || norm > mUpperLimit) {
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
index dbc9392..781427d 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
@@ -17,7 +17,6 @@
 #ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
 #define ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
 
-#include <android/hardware/sensors/1.0/types.h>
 #include <gtest/gtest.h>
 
 #include <atomic>
@@ -26,27 +25,59 @@
 #include <thread>
 #include <vector>
 
+template <class Event>
 class IEventCallback {
-   public:
+  public:
     virtual ~IEventCallback() = default;
-    virtual void onEvent(const ::android::hardware::sensors::V1_0::Event& event) = 0;
+    virtual void onEvent(const Event& event) = 0;
 };
 
+template <class Event>
 class SensorsHidlEnvironmentBase {
   public:
-    using Event = ::android::hardware::sensors::V1_0::Event;
-    virtual void HidlSetUp();
-    virtual void HidlTearDown();
+    virtual void HidlSetUp() {
+        ASSERT_TRUE(resetHal()) << "could not get hidl service";
+
+        mCollectionEnabled = false;
+        startPollingThread();
+
+        // In case framework just stopped for test and there is sensor events in the pipe,
+        // wait some time for those events to be cleared to avoid them messing up the test.
+        std::this_thread::sleep_for(std::chrono::seconds(3));
+    }
+
+    virtual void HidlTearDown() {
+        mStopThread = true;
+        if (mPollThread.joinable()) {
+            mPollThread.join();
+        }
+    }
 
     // Get and clear all events collected so far (like "cat" shell command).
     // If output is nullptr, it clears all collected events.
-    void catEvents(std::vector<Event>* output);
+    void catEvents(std::vector<Event>* output) {
+        std::lock_guard<std::mutex> lock(mEventsMutex);
+        if (output) {
+            output->insert(output->end(), mEvents.begin(), mEvents.end());
+        }
+        mEvents.clear();
+    }
 
     // set sensor event collection status
-    void setCollection(bool enable);
+    void setCollection(bool enable) {
+        std::lock_guard<std::mutex> lock(mEventsMutex);
+        mCollectionEnabled = enable;
+    }
 
-    void registerCallback(IEventCallback* callback);
-    void unregisterCallback();
+    void registerCallback(IEventCallback<Event>* callback) {
+        std::lock_guard<std::mutex> lock(mEventsMutex);
+        mCallback = callback;
+    }
+
+    void unregisterCallback() {
+        std::lock_guard<std::mutex> lock(mEventsMutex);
+        mCallback = nullptr;
+    }
 
    protected:
      SensorsHidlEnvironmentBase(const std::string& service_name)
@@ -55,7 +86,16 @@
      }
      virtual ~SensorsHidlEnvironmentBase(){};
 
-     void addEvent(const Event& ev);
+     void addEvent(const Event& ev) {
+         std::lock_guard<std::mutex> lock(mEventsMutex);
+         if (mCollectionEnabled) {
+             mEvents.push_back(ev);
+         }
+
+         if (mCallback != nullptr) {
+             mCallback->onEvent(ev);
+         }
+     }
 
      virtual void startPollingThread() = 0;
      virtual bool resetHal() = 0;
@@ -67,9 +107,9 @@
      std::vector<Event> mEvents;
      std::mutex mEventsMutex;
 
-     IEventCallback* mCallback;
+     IEventCallback<Event>* mCallback;
 
-     GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase);
+     GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase<Event>);
 };
 
 #endif  // ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
\ No newline at end of file
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
index 5fb6c5c..03bec87 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
@@ -19,12 +19,15 @@
 
 #include "sensors-vts-utils/SensorEventsChecker.h"
 #include "sensors-vts-utils/SensorsHidlEnvironmentBase.h"
+#include "sensors-vts-utils/SensorsTestSharedMemory.h"
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android/hardware/sensors/1.0/ISensors.h>
 #include <android/hardware/sensors/1.0/types.h>
 #include <gtest/gtest.h>
+#include <hardware/sensors.h>
+#include <log/log.h>
 
+#include <cinttypes>
 #include <unordered_set>
 #include <vector>
 
@@ -35,19 +38,130 @@
 
 using ::android::sp;
 using ::android::hardware::hidl_string;
-using ::android::hardware::sensors::V1_0::Event;
-using ::android::hardware::sensors::V1_0::ISensors;
 using ::android::hardware::sensors::V1_0::RateLevel;
 using ::android::hardware::sensors::V1_0::Result;
 using ::android::hardware::sensors::V1_0::SensorFlagBits;
-using ::android::hardware::sensors::V1_0::SensorInfo;
-using ::android::hardware::sensors::V1_0::SensorType;
+using ::android::hardware::sensors::V1_0::SensorFlagShift;
+using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
 using ::android::hardware::sensors::V1_0::SharedMemInfo;
 using ::android::hardware::sensors::V1_0::SharedMemType;
 
+template <class SensorTypeT>
+static void assertTypeMatchStringType(SensorTypeT type, const hidl_string& stringType) {
+    if (type >= SensorTypeT::DEVICE_PRIVATE_BASE) {
+        return;
+    }
+
+    switch (type) {
+#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type)                      \
+    case SensorTypeT::type:                                          \
+        ASSERT_STREQ(SENSOR_STRING_TYPE_##type, stringType.c_str()); \
+        break;
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
+        default:
+            FAIL() << "Type " << static_cast<int>(type)
+                   << " in android defined range is not checked, "
+                   << "stringType = " << stringType;
+#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
+    }
+}
+
+template <class SensorTypeT>
+static SensorFlagBits expectedReportModeForType(SensorTypeT type) {
+    switch (type) {
+        case SensorTypeT::ACCELEROMETER:
+        case SensorTypeT::ACCELEROMETER_UNCALIBRATED:
+        case SensorTypeT::GYROSCOPE:
+        case SensorTypeT::MAGNETIC_FIELD:
+        case SensorTypeT::ORIENTATION:
+        case SensorTypeT::PRESSURE:
+        case SensorTypeT::TEMPERATURE:
+        case SensorTypeT::GRAVITY:
+        case SensorTypeT::LINEAR_ACCELERATION:
+        case SensorTypeT::ROTATION_VECTOR:
+        case SensorTypeT::MAGNETIC_FIELD_UNCALIBRATED:
+        case SensorTypeT::GAME_ROTATION_VECTOR:
+        case SensorTypeT::GYROSCOPE_UNCALIBRATED:
+        case SensorTypeT::GEOMAGNETIC_ROTATION_VECTOR:
+        case SensorTypeT::POSE_6DOF:
+        case SensorTypeT::HEART_BEAT:
+            return SensorFlagBits::CONTINUOUS_MODE;
+
+        case SensorTypeT::LIGHT:
+        case SensorTypeT::PROXIMITY:
+        case SensorTypeT::RELATIVE_HUMIDITY:
+        case SensorTypeT::AMBIENT_TEMPERATURE:
+        case SensorTypeT::HEART_RATE:
+        case SensorTypeT::DEVICE_ORIENTATION:
+        case SensorTypeT::STEP_COUNTER:
+        case SensorTypeT::LOW_LATENCY_OFFBODY_DETECT:
+            return SensorFlagBits::ON_CHANGE_MODE;
+
+        case SensorTypeT::SIGNIFICANT_MOTION:
+        case SensorTypeT::WAKE_GESTURE:
+        case SensorTypeT::GLANCE_GESTURE:
+        case SensorTypeT::PICK_UP_GESTURE:
+        case SensorTypeT::MOTION_DETECT:
+        case SensorTypeT::STATIONARY_DETECT:
+            return SensorFlagBits::ONE_SHOT_MODE;
+
+        case SensorTypeT::STEP_DETECTOR:
+        case SensorTypeT::TILT_DETECTOR:
+        case SensorTypeT::WRIST_TILT_GESTURE:
+        case SensorTypeT::DYNAMIC_SENSOR_META:
+            return SensorFlagBits::SPECIAL_REPORTING_MODE;
+
+        default:
+            ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
+            return (SensorFlagBits)-1;
+    }
+}
+
+template <class SensorTypeVersion, class EventType, class SensorInfoType>
 class SensorsHidlTestBase : public testing::TestWithParam<std::string> {
   public:
-    virtual SensorsHidlEnvironmentBase* getEnvironment() = 0;
+    using ISensors = ::android::hardware::sensors::V1_0::ISensors;
+
+    SensorsHidlTestBase()
+        : mAccelNormChecker(Vec3NormChecker<EventType>::byNominal(GRAVITY_EARTH, 1.0f /*m/s^2*/)),
+          mGyroNormChecker(Vec3NormChecker<EventType>::byNominal(0.f, 0.1f /*rad/s*/)) {}
+
+    virtual SensorsHidlEnvironmentBase<EventType>* getEnvironment() = 0;
+
     virtual void SetUp() override {}
 
     virtual void TearDown() override {
@@ -67,16 +181,13 @@
     }
 
     // implementation wrapper
-    virtual SensorInfo defaultSensorByType(SensorType type) = 0;
+    virtual SensorInfoType defaultSensorByType(SensorTypeVersion type) = 0;
     virtual Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) = 0;
-
+    virtual Return<Result> injectSensorData(const EventType& event) = 0;
     virtual Return<Result> activate(int32_t sensorHandle, bool enabled) = 0;
-
     virtual Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
                                  int64_t maxReportLatencyNs) = 0;
-
     virtual Return<Result> flush(int32_t sensorHandle) = 0;
-    virtual Return<Result> injectSensorData(const Event& event) = 0;
     virtual Return<void> registerDirectChannel(const SharedMemInfo& mem,
                                                ISensors::registerDirectChannel_cb _hidl_cb) = 0;
     virtual Return<Result> unregisterDirectChannel(int32_t channelHandle) = 0;
@@ -84,12 +195,395 @@
                                             RateLevel rate,
                                             ISensors::configDirectReport_cb _hidl_cb) = 0;
 
-    std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
-                                     bool clearBeforeStart = true, bool changeCollection = true);
-    static std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
-                                            SensorsHidlEnvironmentBase* environment,
-                                            bool clearBeforeStart = true,
-                                            bool changeCollection = true);
+    std::vector<EventType> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+                                         bool clearBeforeStart = true,
+                                         bool changeCollection = true) {
+        return collectEvents(timeLimitUs, nEventLimit, getEnvironment(), clearBeforeStart,
+                             changeCollection);
+    }
+
+    std::vector<EventType> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+                                         SensorsHidlEnvironmentBase<EventType>* environment,
+                                         bool clearBeforeStart = true,
+                                         bool changeCollection = true) {
+        std::vector<EventType> events;
+        constexpr useconds_t SLEEP_GRANULARITY = 100 * 1000;  // granularity 100 ms
+
+        ALOGI("collect max of %zu events for %d us, clearBeforeStart %d", nEventLimit, timeLimitUs,
+              clearBeforeStart);
+
+        if (changeCollection) {
+            environment->setCollection(true);
+        }
+        if (clearBeforeStart) {
+            environment->catEvents(nullptr);
+        }
+
+        while (timeLimitUs > 0) {
+            useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
+            usleep(duration);
+            timeLimitUs -= duration;
+
+            environment->catEvents(&events);
+            if (events.size() >= nEventLimit) {
+                break;
+            }
+            ALOGV("time to go = %d, events to go = %d", (int)timeLimitUs,
+                  (int)(nEventLimit - events.size()));
+        }
+
+        if (changeCollection) {
+            environment->setCollection(false);
+        }
+        return events;
+    }
+
+    void testStreamingOperation(SensorTypeVersion type, std::chrono::nanoseconds samplingPeriod,
+                                std::chrono::seconds duration,
+                                const SensorEventsChecker<EventType>& checker) {
+        std::vector<EventType> events;
+        std::vector<EventType> sensorEvents;
+
+        const int64_t samplingPeriodInNs = samplingPeriod.count();
+        const int64_t batchingPeriodInNs = 0;  // no batching
+        const useconds_t minTimeUs = std::chrono::microseconds(duration).count();
+        const size_t minNEvent = duration / samplingPeriod;
+
+        SensorInfoType sensor = defaultSensorByType(type);
+
+        if (!isValidType(sensor.type)) {
+            // no default sensor of this type
+            return;
+        }
+
+        if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) {
+            // rate not supported
+            return;
+        }
+
+        int32_t handle = sensor.sensorHandle;
+
+        ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
+        ASSERT_EQ(activate(handle, 1), Result::OK);
+        events = collectEvents(minTimeUs, minNEvent, getEnvironment(), true /*clearBeforeStart*/);
+        ASSERT_EQ(activate(handle, 0), Result::OK);
+
+        ALOGI("Collected %zu samples", events.size());
+
+        ASSERT_GT(events.size(), 0u);
+
+        bool handleMismatchReported = false;
+        bool metaSensorTypeErrorReported = false;
+        for (auto& e : events) {
+            if (e.sensorType == type) {
+                // avoid generating hundreds of error
+                if (!handleMismatchReported) {
+                    EXPECT_EQ(e.sensorHandle, handle)
+                            << (handleMismatchReported = true,
+                                "Event of the same type must come from the sensor registered");
+                }
+                sensorEvents.push_back(e);
+            } else {
+                // avoid generating hundreds of error
+                if (!metaSensorTypeErrorReported) {
+                    EXPECT_TRUE(isMetaSensorType(e.sensorType))
+                            << (metaSensorTypeErrorReported = true,
+                                "Only meta types are allowed besides the type registered");
+                }
+            }
+        }
+
+        std::string s;
+        EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
+
+        EXPECT_GE(sensorEvents.size(),
+                  minNEvent / 2);  // make sure returned events are not all meta
+    }
+
+    void testSamplingRateHotSwitchOperation(SensorTypeVersion type, bool fastToSlow = true) {
+        std::vector<EventType> events1, events2;
+
+        constexpr int64_t batchingPeriodInNs = 0;          // no batching
+        constexpr int64_t collectionTimeoutUs = 60000000;  // 60s
+        constexpr size_t minNEvent = 50;
+
+        SensorInfoType sensor = defaultSensorByType(type);
+
+        if (!isValidType(sensor.type)) {
+            // no default sensor of this type
+            return;
+        }
+
+        int32_t handle = sensor.sensorHandle;
+        int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
+        int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll;
+
+        if (minSamplingPeriodInNs == maxSamplingPeriodInNs) {
+            // only support single rate
+            return;
+        }
+
+        int64_t firstCollectionPeriod = fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
+        int64_t secondCollectionPeriod =
+                !fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
+
+        // first collection
+        ASSERT_EQ(batch(handle, firstCollectionPeriod, batchingPeriodInNs), Result::OK);
+        ASSERT_EQ(activate(handle, 1), Result::OK);
+
+        usleep(500000);  // sleep 0.5 sec to wait for change rate to happen
+        events1 = collectEvents(collectionTimeoutUs, minNEvent, getEnvironment());
+
+        // second collection, without stop sensor
+        ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK);
+
+        usleep(500000);  // sleep 0.5 sec to wait for change rate to happen
+        events2 = collectEvents(collectionTimeoutUs, minNEvent, getEnvironment());
+
+        // end of collection, stop sensor
+        ASSERT_EQ(activate(handle, 0), Result::OK);
+
+        ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size());
+
+        ASSERT_GT(events1.size(), 0u);
+        ASSERT_GT(events2.size(), 0u);
+
+        int64_t minDelayAverageInterval, maxDelayAverageInterval;
+        std::vector<EventType>& minDelayEvents(fastToSlow ? events1 : events2);
+        std::vector<EventType>& maxDelayEvents(fastToSlow ? events2 : events1);
+
+        size_t nEvent = 0;
+        int64_t prevTimestamp = -1;
+        int64_t timestampInterval = 0;
+        for (auto& e : minDelayEvents) {
+            if (e.sensorType == type) {
+                ASSERT_EQ(e.sensorHandle, handle);
+                if (prevTimestamp > 0) {
+                    timestampInterval += e.timestamp - prevTimestamp;
+                }
+                prevTimestamp = e.timestamp;
+                ++nEvent;
+            }
+        }
+        ASSERT_GT(nEvent, 2u);
+        minDelayAverageInterval = timestampInterval / (nEvent - 1);
+
+        nEvent = 0;
+        prevTimestamp = -1;
+        timestampInterval = 0;
+        for (auto& e : maxDelayEvents) {
+            if (e.sensorType == type) {
+                ASSERT_EQ(e.sensorHandle, handle);
+                if (prevTimestamp > 0) {
+                    timestampInterval += e.timestamp - prevTimestamp;
+                }
+                prevTimestamp = e.timestamp;
+                ++nEvent;
+            }
+        }
+        ASSERT_GT(nEvent, 2u);
+        maxDelayAverageInterval = timestampInterval / (nEvent - 1);
+
+        // change of rate is significant.
+        ALOGI("min/maxDelayAverageInterval = %" PRId64 " %" PRId64, minDelayAverageInterval,
+              maxDelayAverageInterval);
+        EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval),
+                  minDelayAverageInterval / 10);
+
+        // fastest rate sampling time is close to spec
+        EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
+                  minSamplingPeriodInNs / 10);
+
+        // slowest rate sampling time is close to spec
+        EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
+                  maxSamplingPeriodInNs / 10);
+    }
+
+    void testBatchingOperation(SensorTypeVersion type) {
+        std::vector<EventType> events;
+
+        constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000;
+        constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
+
+        SensorInfoType sensor = defaultSensorByType(type);
+
+        if (!isValidType(sensor.type)) {
+            // no default sensor of this type
+            return;
+        }
+
+        int32_t handle = sensor.sensorHandle;
+        int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
+        uint32_t minFifoCount = sensor.fifoReservedEventCount;
+        int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs;
+
+        if (batchingPeriodInNs < oneSecondInNs) {
+            // batching size too small to test reliably
+            return;
+        }
+
+        batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs);
+
+        ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000));
+
+        int64_t allowedBatchDeliverTimeNs = std::max(oneSecondInNs, batchingPeriodInNs / 10);
+
+        ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK);
+        ASSERT_EQ(activate(handle, 1), Result::OK);
+
+        usleep(500000);  // sleep 0.5 sec to wait for initialization
+        ASSERT_EQ(flush(handle), Result::OK);
+
+        // wait for 80% of the reserved batching period
+        // there should not be any significant amount of events
+        // since collection is not enabled all events will go down the drain
+        usleep(batchingPeriodInNs / 1000 * 8 / 10);
+
+        getEnvironment()->setCollection(true);
+        // clean existing collections
+        collectEvents(0 /*timeLimitUs*/, 0 /*nEventLimit*/, true /*clearBeforeStart*/,
+                      false /*change collection*/);
+
+        // 0.8 + 0.2 times the batching period
+        usleep(batchingPeriodInNs / 1000 * 8 / 10);
+        ASSERT_EQ(flush(handle), Result::OK);
+
+        // plus some time for the event to deliver
+        events = collectEvents(allowedBatchDeliverTimeNs / 1000, minFifoCount,
+                               false /*clearBeforeStart*/, false /*change collection*/);
+
+        getEnvironment()->setCollection(false);
+        ASSERT_EQ(activate(handle, 0), Result::OK);
+
+        size_t nEvent = 0;
+        for (auto& e : events) {
+            if (e.sensorType == type && e.sensorHandle == handle) {
+                ++nEvent;
+            }
+        }
+
+        // at least reach 90% of advertised capacity
+        ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10));
+    }
+
+    void testDirectReportOperation(SensorTypeVersion type, SharedMemType memType, RateLevel rate,
+                                   const SensorEventsChecker<EventType>& checker) {
+        constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+        constexpr size_t kNEvent = 4096;
+        constexpr size_t kMemSize = kEventSize * kNEvent;
+
+        constexpr float kNormalNominal = 50;
+        constexpr float kFastNominal = 200;
+        constexpr float kVeryFastNominal = 800;
+
+        constexpr float kNominalTestTimeSec = 1.f;
+        constexpr float kMaxTestTimeSec =
+                kNominalTestTimeSec + 0.5f;  // 0.5 second for initialization
+
+        SensorInfoType sensor = defaultSensorByType(type);
+
+        if (!isValidType(sensor.type)) {
+            // no default sensor of this type
+            return;
+        }
+
+        if (!isDirectReportRateSupported(sensor, rate)) {
+            return;
+        }
+
+        if (!isDirectChannelTypeSupported(sensor, memType)) {
+            return;
+        }
+
+        std::unique_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem(
+                SensorsTestSharedMemory<SensorTypeVersion, EventType>::create(memType, kMemSize));
+        ASSERT_NE(mem, nullptr);
+
+        char* buffer = mem->getBuffer();
+        // fill memory with data
+        for (size_t i = 0; i < kMemSize; ++i) {
+            buffer[i] = '\xcc';
+        }
+
+        int32_t channelHandle;
+        registerDirectChannel(mem->getSharedMemInfo(),
+                              [&channelHandle](auto result, auto channelHandle_) {
+                                  ASSERT_EQ(result, Result::OK);
+                                  channelHandle = channelHandle_;
+                              });
+
+        // check memory is zeroed
+        for (size_t i = 0; i < kMemSize; ++i) {
+            ASSERT_EQ(buffer[i], '\0');
+        }
+
+        int32_t eventToken;
+        configDirectReport(sensor.sensorHandle, channelHandle, rate,
+                           [&eventToken](auto result, auto token) {
+                               ASSERT_EQ(result, Result::OK);
+                               eventToken = token;
+                           });
+
+        usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f));
+        auto events = mem->parseEvents();
+
+        // find norminal rate
+        float nominalFreq = 0.f;
+        switch (rate) {
+            case RateLevel::NORMAL:
+                nominalFreq = kNormalNominal;
+                break;
+            case RateLevel::FAST:
+                nominalFreq = kFastNominal;
+                break;
+            case RateLevel::VERY_FAST:
+                nominalFreq = kVeryFastNominal;
+                break;
+            case RateLevel::STOP:
+                FAIL();
+        }
+
+        // allowed to be between 55% and 220% of nominal freq
+        ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec));
+        ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec));
+
+        int64_t lastTimestamp = 0;
+        bool typeErrorReported = false;
+        bool tokenErrorReported = false;
+        bool timestampErrorReported = false;
+        std::vector<EventType> sensorEvents;
+        for (auto& e : events) {
+            if (!tokenErrorReported) {
+                EXPECT_EQ(eventToken, e.sensorHandle)
+                        << (tokenErrorReported = true,
+                            "Event token does not match that retured from configDirectReport");
+            }
+
+            if (isMetaSensorType(e.sensorType)) {
+                continue;
+            }
+            sensorEvents.push_back(e);
+
+            if (!typeErrorReported) {
+                EXPECT_EQ(type, e.sensorType)
+                        << (typeErrorReported = true,
+                            "Type in event does not match type of sensor registered.");
+            }
+            if (!timestampErrorReported) {
+                EXPECT_GT(e.timestamp, lastTimestamp) << (timestampErrorReported = true,
+                                                          "Timestamp not monotonically increasing");
+            }
+            lastTimestamp = e.timestamp;
+        }
+
+        std::string s;
+        EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
+
+        // stop sensor and unregister channel
+        configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
+                           [](auto result, auto) { EXPECT_EQ(result, Result::OK); });
+        EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
+    }
 
     inline static SensorFlagBits extractReportMode(uint64_t flag) {
         return (SensorFlagBits)(flag & ((uint64_t)SensorFlagBits::CONTINUOUS_MODE |
@@ -98,36 +592,75 @@
                                         (uint64_t)SensorFlagBits::SPECIAL_REPORTING_MODE));
     }
 
-    inline static bool isMetaSensorType(SensorType type) {
-        return (type == SensorType::META_DATA || type == SensorType::DYNAMIC_SENSOR_META ||
-                type == SensorType::ADDITIONAL_INFO);
+    inline static bool isMetaSensorType(SensorTypeVersion type) {
+        return (type == SensorTypeVersion::META_DATA ||
+                type == SensorTypeVersion::DYNAMIC_SENSOR_META ||
+                type == SensorTypeVersion::ADDITIONAL_INFO);
     }
 
-    inline static bool isValidType(SensorType type) { return (int32_t)type > 0; }
+    inline static bool isValidType(SensorTypeVersion type) { return (int32_t)type > 0; }
 
-    void testStreamingOperation(SensorType type, std::chrono::nanoseconds samplingPeriod,
-                                std::chrono::seconds duration, const SensorEventsChecker& checker);
-    void testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow = true);
-    void testBatchingOperation(SensorType type);
-    void testDirectReportOperation(SensorType type, SharedMemType memType, RateLevel rate,
-                                   const SensorEventsChecker& checker);
-
-    static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType);
-    static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode);
     static void assertDelayMatchReportMode(int32_t minDelay, int32_t maxDelay,
-                                           SensorFlagBits reportMode);
-    static SensorFlagBits expectedReportModeForType(SensorType type);
-    static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate);
-    static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type);
+                                           SensorFlagBits reportMode) {
+        switch (reportMode) {
+            case SensorFlagBits::CONTINUOUS_MODE:
+                ASSERT_LT(0, minDelay);
+                ASSERT_LE(0, maxDelay);
+                break;
+            case SensorFlagBits::ON_CHANGE_MODE:
+                ASSERT_LE(0, minDelay);
+                ASSERT_LE(0, maxDelay);
+                break;
+            case SensorFlagBits::ONE_SHOT_MODE:
+                ASSERT_EQ(-1, minDelay);
+                ASSERT_EQ(0, maxDelay);
+                break;
+            case SensorFlagBits::SPECIAL_REPORTING_MODE:
+                // do not enforce anything for special reporting mode
+                break;
+            default:
+                FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
+        }
+    }
 
-   protected:
-    // checkers
-    static const Vec3NormChecker sAccelNormChecker;
-    static const Vec3NormChecker sGyroNormChecker;
+  protected:
+    static void assertTypeMatchReportMode(SensorTypeVersion type, SensorFlagBits reportMode) {
+        if (type >= SensorTypeVersion::DEVICE_PRIVATE_BASE) {
+            return;
+        }
+
+        SensorFlagBits expected = expectedReportModeForType(type);
+
+        ASSERT_TRUE(expected == (SensorFlagBits)-1 || expected == reportMode)
+                << "reportMode=" << static_cast<int>(reportMode)
+                << "expected=" << static_cast<int>(expected);
+    }
+
+    static bool isDirectReportRateSupported(SensorInfoType sensor, RateLevel rate) {
+        unsigned int r =
+                static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT) >>
+                static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT);
+        return r >= static_cast<unsigned int>(rate);
+    }
+
+    static bool isDirectChannelTypeSupported(SensorInfoType sensor, SharedMemType type) {
+        switch (type) {
+            case SharedMemType::ASHMEM:
+                return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0;
+            case SharedMemType::GRALLOC:
+                return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0;
+            default:
+                return false;
+        }
+    }
+
+    // Checkers
+    Vec3NormChecker<EventType> mAccelNormChecker;
+    Vec3NormChecker<EventType> mGyroNormChecker;
 
     // all sensors and direct channnels used
     std::unordered_set<int32_t> mSensorHandles;
     std::unordered_set<int32_t> mDirectChannelHandles;
 };
 
-#endif  // ANDROID_SENSORS_HIDL_TEST_BASE_H
\ No newline at end of file
+#endif  // ANDROID_SENSORS_HIDL_TEST_BASE_H
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
index 002f42c..39084a4 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
@@ -20,25 +20,177 @@
 #include "GrallocWrapper.h"
 
 #include <android-base/macros.h>
-#include <android/hardware/sensors/1.0/types.h>
+#include <log/log.h>
+
+#include <sys/mman.h>
+#include <cinttypes>
 
 #include <cutils/ashmem.h>
 
+using namespace ::android::hardware::sensors::V1_0;
+
+template <class SensorTypeVersion, class EventType>
 class SensorsTestSharedMemory {
-    using SharedMemType = ::android::hardware::sensors::V1_0::SharedMemType;
-    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
-    using Event = ::android::hardware::sensors::V1_0::Event;
+  public:
+    static SensorsTestSharedMemory* create(SharedMemType type, size_t size) {
+        constexpr size_t kMaxSize =
+                128 * 1024 * 1024;  // sensor test should not need more than 128M
+        if (size == 0 || size >= kMaxSize) {
+            return nullptr;
+        }
 
-   public:
-    static SensorsTestSharedMemory* create(SharedMemType type, size_t size);
-    SharedMemInfo getSharedMemInfo() const;
-    char* getBuffer() const;
-    size_t getSize() const;
-    std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const;
-    virtual ~SensorsTestSharedMemory();
+        auto m = new SensorsTestSharedMemory<SensorTypeVersion, EventType>(type, size);
+        if (m->mSize != size || m->mBuffer == nullptr) {
+            delete m;
+            m = nullptr;
+        }
+        return m;
+    }
 
-   private:
-    SensorsTestSharedMemory(SharedMemType type, size_t size);
+    SharedMemInfo getSharedMemInfo() const {
+        SharedMemInfo mem = {.type = mType,
+                             .format = SharedMemFormat::SENSORS_EVENT,
+                             .size = static_cast<uint32_t>(mSize),
+                             .memoryHandle = mNativeHandle};
+        return mem;
+    }
+    char* getBuffer() const { return mBuffer; }
+    size_t getSize() const { return mSize; }
+    std::vector<EventType> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const {
+        constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+        constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
+        constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN);
+        constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE);
+        constexpr size_t kOffsetAtomicCounter =
+                static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER);
+        constexpr size_t kOffsetTimestamp =
+                static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP);
+        constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA);
+
+        std::vector<EventType> events;
+        std::vector<float> data(16);
+
+        while (offset + kEventSize <= mSize) {
+            int64_t atomicCounter =
+                    *reinterpret_cast<uint32_t*>(mBuffer + offset + kOffsetAtomicCounter);
+            if (atomicCounter <= lastCounter) {
+                ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter,
+                      lastCounter);
+                break;
+            }
+
+            int32_t size = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetSize);
+            if (size != kEventSize) {
+                // unknown error, events parsed may be wrong, remove all
+                events.clear();
+                break;
+            }
+
+            int32_t token = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetToken);
+            int32_t type = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetType);
+            int64_t timestamp = *reinterpret_cast<int64_t*>(mBuffer + offset + kOffsetTimestamp);
+
+            ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32
+                  ", timestamp %" PRId64,
+                  offset, atomicCounter, token, type, timestamp);
+
+            EventType event = {
+                    .timestamp = timestamp,
+                    .sensorHandle = token,
+                    .sensorType = static_cast<SensorTypeVersion>(type),
+            };
+            event.u.data = android::hardware::hidl_array<float, 16>(
+                    reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
+
+            events.push_back(event);
+
+            lastCounter = atomicCounter;
+            offset += kEventSize;
+        }
+
+        return events;
+    }
+
+    virtual ~SensorsTestSharedMemory() {
+        switch (mType) {
+            case SharedMemType::ASHMEM: {
+                if (mSize != 0) {
+                    ::munmap(mBuffer, mSize);
+                    mBuffer = nullptr;
+
+                    ::native_handle_close(mNativeHandle);
+                    ::native_handle_delete(mNativeHandle);
+
+                    mNativeHandle = nullptr;
+                    mSize = 0;
+                }
+                break;
+            }
+            case SharedMemType::GRALLOC: {
+                if (mSize != 0) {
+                    mGrallocWrapper->freeBuffer(mNativeHandle);
+                    mNativeHandle = nullptr;
+                    mSize = 0;
+                }
+                break;
+            }
+            default: {
+                if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
+                    ALOGE("SensorsTestSharedMemory %p not properly destructed: "
+                          "type %d, native handle %p, size %zu, buffer %p",
+                          this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
+                }
+                break;
+            }
+        }
+    }
+
+  private:
+    SensorsTestSharedMemory(SharedMemType type, size_t size)
+        : mType(type), mSize(0), mBuffer(nullptr) {
+        native_handle_t* handle = nullptr;
+        char* buffer = nullptr;
+        switch (type) {
+            case SharedMemType::ASHMEM: {
+                int fd;
+                handle = ::native_handle_create(1 /*nFds*/, 0 /*nInts*/);
+                if (handle != nullptr) {
+                    handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size);
+                    if (handle->data[0] > 0) {
+                        // memory is pinned by default
+                        buffer = static_cast<char*>(
+                                ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+                        if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
+                            break;
+                        }
+                        ::native_handle_close(handle);
+                    }
+                    ::native_handle_delete(handle);
+                    handle = nullptr;
+                }
+                break;
+            }
+            case SharedMemType::GRALLOC: {
+                mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
+                if (!mGrallocWrapper->isInitialized()) {
+                    break;
+                }
+
+                std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
+                handle = buf.first;
+                buffer = static_cast<char*>(buf.second);
+                break;
+            }
+            default:
+                break;
+        }
+
+        if (buffer != nullptr) {
+            mNativeHandle = handle;
+            mSize = size;
+            mBuffer = buffer;
+        }
+    }
 
     SharedMemType mType;
     native_handle_t* mNativeHandle;
diff --git a/soundtrigger/2.3/ISoundTriggerHw.hal b/soundtrigger/2.3/ISoundTriggerHw.hal
index 270b00e..3e761e5 100644
--- a/soundtrigger/2.3/ISoundTriggerHw.hal
+++ b/soundtrigger/2.3/ISoundTriggerHw.hal
@@ -114,8 +114,10 @@
      * @return status Operation completion status: 0 in case of success
      *                -ENODEV if the native service cannot be reached
      *                -EINVAL invalid input parameter
-     * @return retval ModelParameter structure indicating supported attributes
-     *                of the parameter for the given model handle
+     * @return retval OptionalModelParameterRange safe union structure wrapping
+     *                ModelParameterRange. This structure indicates supported attributes
+     *                of the parameter for the given model handle. If the parameter is not
+     *                supported the Monostate of the union is used.
      */
     queryParameter(SoundModelHandle modelHandle, ModelParameter modelParam)
             generates (int32_t status, OptionalModelParameterRange retval);
diff --git a/soundtrigger/2.3/default/SoundTriggerHw.cpp b/soundtrigger/2.3/default/SoundTriggerHw.cpp
index d3136b9..8fe3108 100644
--- a/soundtrigger/2.3/default/SoundTriggerHw.cpp
+++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp
@@ -889,7 +889,7 @@
     int32_t status = mHwDevice->query_parameter(
             mHwDevice, client->getHalHandle(), convertModelParameterToHal(modelParam), &paramRange);
 
-    if (status == 0) {
+    if (status == 0 && paramRange.is_supported) {
         optionalParamRange.range({.start = paramRange.start, .end = paramRange.end});
     }
     _hidl_cb(status, optionalParamRange);
diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal
index 730f969..10fc34e 100644
--- a/soundtrigger/2.3/types.hal
+++ b/soundtrigger/2.3/types.hal
@@ -66,7 +66,7 @@
      * Bit field encoding of the AudioCapabilities
      * supported by the firmware.
      */
-    uint32_t audioCapabilities;
+    bitfield<AudioCapabilities> audioCapabilities;
 };
 
 /**
diff --git a/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd
new file mode 100644
index 0000000..45c01c1
--- /dev/null
+++ b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd
@@ -0,0 +1,111 @@
+<?xml version="1.0"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+         Licensed under the Apache License, Version 2.0 (the "License");
+         you may not use this file except in compliance with the License.
+         You may obtain a copy of the License at
+
+                    http://www.apache.org/licenses/LICENSE-2.0
+
+         Unless required by applicable law or agreed to in writing, software
+         distributed under the License is distributed on an "AS IS" BASIS,
+         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+         See the License for the specific language governing permissions and
+         limitations under the License.
+-->
+<xs:schema version="1.0"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <!-- List of the Tuner Resource Manager client use case priority hint. -->
+    <xs:simpleType name="version">
+        <xs:restriction base="xs:decimal">
+            <xs:enumeration value="1.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="config">
+        <xs:sequence>
+            <xs:element name="useCaseDefault" type="useCaseDefault" minOccurs="1" maxOccurs="1"/>
+            <xs:element name="useCasePreDefined" type="useCasePreDefined" minOccurs="0" maxOccurs="5"/>
+            <xs:element name="useCaseVendor" type="useCaseVendor" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="version" type="version"/>
+    </xs:complexType>
+
+    <xs:complexType name="useCaseDefault">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                useCaseDefault section:
+                Default value for predefined use cases priority hint.
+                    "fgPriority": priority when the use case is in foreground.
+                    "bgPriority": priority when the use case is in background.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="fgPriority" type="priority"/>
+        <xs:attribute name="bgPriority" type="priority"/>
+    </xs:complexType>
+
+    <xs:complexType name="useCasePreDefined">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                useCasePreDefined section:
+                A list of predefined use cases and their foreground/background priority hint.
+                Each use case has the following attributes:
+                    "type": type of the use case. Pre-defined use cases start with "USE_CASE_"
+                            and have been predefined in "predefinedUseCaseType".
+                    "fgPriority": priority when the use case is in foreground.
+                    "bgPriority": priority when the use case is in background.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="type" type="predefinedUseCaseType"/>
+        <xs:attribute name="fgPriority" type="priority"/>
+        <xs:attribute name="bgPriority" type="priority"/>
+    </xs:complexType>
+
+    <xs:complexType name="useCaseVendor">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                useCaseVendor section:
+                A list of vendor defined use cases and their foreground/background priority hint.
+                Each use case has the following attributes:
+                    "type": type of the use case. Vendor defined use cases start with "VENDOR_USE_CASE_".
+                    "fgPriority": priority when the use case is in foreground.
+                    "bgPriority": priority when the use case is in background.
+                    "id": Vendor defined use case must have an id greater than 1000 to be associated with.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="type" type="vendorUseCaseType"/>
+        <xs:attribute name="id" type="id"/>
+        <xs:attribute name="fgPriority" type="priority"/>
+        <xs:attribute name="bgPriority" type="priority"/>
+    </xs:complexType>
+
+    <xs:simpleType name="predefinedUseCaseType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="USE_CASE_RECORD"/>
+            <xs:enumeration value="USE_CASE_LIVE"/>
+            <xs:enumeration value="USE_CASE_PLAYBACK"/>
+            <xs:enumeration value="USE_CASE_SCAN"/>
+            <xs:enumeration value="USE_CASE_BACKGROUND"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="vendorUseCaseType">
+        <xs:restriction base="xs:string">
+            <xs:pattern value="VENDOR_USE_CASE_[_A-Z0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="priority">
+        <xs:restriction base="xs:integer">
+            <xs:minInclusive value="0"/>
+            <xs:maxInclusive value="1000"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="id">
+        <xs:restriction base="xs:integer">
+            <xs:minInclusive value="1001"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:element name="config" type="config"/>
+</xs:schema>
diff --git a/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml
new file mode 100644
index 0000000..938faeb
--- /dev/null
+++ b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+         Licensed under the Apache License, Version 2.0 (the "License");
+         you may not use this file except in compliance with the License.
+         You may obtain a copy of the License at
+
+                    http://www.apache.org/licenses/LICENSE-2.0
+
+         Unless required by applicable law or agreed to in writing, software
+         distributed under the License is distributed on an "AS IS" BASIS,
+         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+         See the License for the specific language governing permissions and
+         limitations under the License.
+-->
+<!-- A sample Tuner Resource Manager use case priority configuration xml -->
+<config version="1.0" xmlns:xi="http://www.w3.org/2001/XMLSchema">
+    <!-- useCaseDefault section:
+        Default value for predefined use cases priority hint.
+            "fgPriority": priority when the use case is in foreground. Value range [0-1000].
+            "bgPriority": priority when the use case is in background. Value range [0-1000].
+    -->
+    <useCaseDefault fgPriority="150" bgPriority="50"/>
+    <!-- useCasePreDefined section:
+        A list of predefined use cases and their foreground/background priority hint.
+        Each use case has the following attributes:
+            "type": type of the use case. Pre-defined use cases start with "USE_CASE_"
+                    and could only use the types defined in "predefinedUseCaseType" in xsd.
+            "fgPriority": priority when the use case is in foreground. Value range [0-1000].
+            "bgPriority": priority when the use case is in background. Value range [0-1000].
+    -->
+    <useCasePreDefined type="USE_CASE_RECORD" fgPriority="600" bgPriority="500"/>
+    <useCasePreDefined type="USE_CASE_LIVE" fgPriority="490" bgPriority="400"/>
+    <useCasePreDefined type="USE_CASE_PLAYBACK" fgPriority="480" bgPriority="300"/>
+    <useCasePreDefined type="USE_CASE_SCAN" fgPriority="450" bgPriority="200"/>
+    <useCasePreDefined type="USE_CASE_BACKGROUND" fgPriority="180" bgPriority="100"/>
+    <!-- useCaseVendor section:
+        A list of vendor defined use cases and their foreground/background priority hint.
+        Each use case has the following attributes:
+            "type": type of the use case. Vendor defined use cases start with "VENDOR_USE_CASE_".
+            "fgPriority": priority when the use case is in foreground. Value range [0-1000].
+            "bgPriority": priority when the use case is in background. Value range [0-1000].
+            "id": Vendor defined use case must have an id greater than 1000 to be associated with.
+    -->
+    <useCaseVendor type="VENDOR_USE_CASE_SPECIAL_1" id="1001" fgPriority="300" bgPriority="80"/>
+    <useCaseVendor type="VENDOR_USE_CASE_SPECIAL_2" id="1002" fgPriority="200" bgPriority="40"/>
+</config>
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 1e07edd..dd2f8a6 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -90,11 +90,66 @@
     return Result::SUCCESS;
 }
 
-Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& /* statusTypes */,
+Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
                                  getStatus_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
     vector<FrontendStatus> statuses;
+    for (int i = 0; i < statusTypes.size(); i++) {
+        FrontendStatusType type = statusTypes[i];
+        FrontendStatus status;
+        // assign randomly selected values for testing.
+        switch (type) {
+            case FrontendStatusType::DEMOD_LOCK: {
+                status.isDemodLocked(true);
+                break;
+            }
+            case FrontendStatusType::SNR: {
+                status.snr(221);
+                break;
+            }
+            case FrontendStatusType::FEC: {
+                status.innerFec(FrontendInnerFec::FEC_2_9);  // value = 1 << 7
+                break;
+            }
+            case FrontendStatusType::MODULATION: {
+                FrontendModulationStatus modulationStatus;
+                modulationStatus.isdbt(FrontendIsdbtModulation::MOD_16QAM);  // value = 1 << 3
+                status.modulation(modulationStatus);
+                break;
+            }
+            case FrontendStatusType::PLP_ID: {
+                status.plpId(101);  // type uint8_t
+                break;
+            }
+            case FrontendStatusType::LAYER_ERROR: {
+                vector<bool> v = {false, true, true};
+                status.isLayerError(v);
+                break;
+            }
+            case FrontendStatusType::ATSC3_PLP_INFO: {
+                vector<FrontendStatusAtsc3PlpInfo> v;
+                FrontendStatusAtsc3PlpInfo info1{
+                        .plpId = 3,
+                        .isLocked = false,
+                        .uec = 313,
+                };
+                FrontendStatusAtsc3PlpInfo info2{
+                        .plpId = 5,
+                        .isLocked = true,
+                        .uec = 515,
+                };
+                v.push_back(info1);
+                v.push_back(info2);
+                status.plpInfo(v);
+                break;
+            }
+            default: {
+                continue;
+            }
+        }
+        statuses.push_back(status);
+    }
     _hidl_cb(Result::SUCCESS, statuses);
 
     return Void();
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index c6017f0..4fd3355 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -109,7 +109,37 @@
 Return<void> Tuner::getFrontendInfo(FrontendId /* frontendId */, getFrontendInfo_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    FrontendInfo info;
+    vector<FrontendStatusType> statusCaps = {
+            FrontendStatusType::DEMOD_LOCK,
+            FrontendStatusType::SNR,
+            FrontendStatusType::FEC,
+            FrontendStatusType::MODULATION,
+            FrontendStatusType::PLP_ID,
+            FrontendStatusType::LAYER_ERROR,
+            FrontendStatusType::ATSC3_PLP_INFO,
+    };
+    FrontendInfo::FrontendCapabilities frontendCaps;
+    FrontendIsdbtCapabilities isdbtCaps{
+            .modeCap = FrontendIsdbtMode::MODE_1 | FrontendIsdbtMode::MODE_2,
+            .bandwidthCap = (unsigned int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ,
+            .modulationCap = (unsigned int)FrontendIsdbtModulation::MOD_16QAM,
+            // ISDBT shares coderate and guard interval with DVBT
+            .coderateCap = FrontendDvbtCoderate::CODERATE_4_5 | FrontendDvbtCoderate::CODERATE_6_7,
+            .guardIntervalCap = (unsigned int)FrontendDvbtGuardInterval::INTERVAL_1_128,
+    };
+    frontendCaps.isdbtCaps(isdbtCaps);
+    // assign randomly selected values for testing.
+    FrontendInfo info{
+            .type = FrontendType::ISDBT,
+            .minFrequency = 139,
+            .maxFrequency = 1139,
+            .minSymbolRate = 45,
+            .maxSymbolRate = 1145,
+            .acquireRange = 30,
+            .exclusiveGroupId = 57,
+            .statusCaps = statusCaps,
+            .frontendCaps = frontendCaps,
+    };
 
     _hidl_cb(Result::SUCCESS, info);
     return Void();
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 2eaab36..dd2b48f 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -1425,18 +1425,6 @@
      */
     LAYER_ERROR,
     /**
-     * CN value by VBER.
-     */
-    VBER_CN,
-    /**
-     * CN value by LBER.
-     */
-    LBER_CN,
-    /**
-     * CN value by XER.
-     */
-    XER_CN,
-    /**
      * Moduration Error Ratio.
      */
     MER,
@@ -1559,21 +1547,6 @@
     vec<bool> isLayerError;
 
     /**
-     * CN value by VBER measured by 0.001 dB
-     */
-    int32_t vberCn;
-
-    /**
-     * CN value by LBER measured by 0.001 dB
-     */
-    int32_t lberCn;
-
-    /**
-     * CN value by XER measured by 0.001 dB
-     */
-    int32_t xerCn;
-
-    /**
      * MER value measured by 0.001 dB
      */
     int32_t mer;
@@ -1951,7 +1924,7 @@
 };
 
 @export
-enum Constant : uint16_t {
+enum Constant : uint32_t {
     /**
      * An invalid packet ID in transport stream according to ISO/IEC 13818-1.
      */
@@ -1960,6 +1933,14 @@
      * An invalid Stream ID.
      */
     INVALID_STREAM_ID = 0xFFFF,
+    /**
+     * An invalid Filter ID.
+     */
+    INVALID_FILTER_ID = 0xFFFFFFFF,
+    /**
+     * An invalid AV sync hardware ID.
+     */
+    INVALID_AV_SYNC_ID = 0xFFFFFFFF,
 };
 
 /**
@@ -2178,19 +2159,37 @@
  */
 struct DemuxIpAddress {
     safe_union SrcIpAddress {
+        /**
+         * 0.0.0.0 is invalid. should be ignored.
+         */
         uint8_t[4] v4;
 
+        /**
+         * 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 is invalid. should be ignored.
+         */
         uint8_t[16] v6;
     } srcIpAddress;
 
     safe_union DstIpAddress {
+        /**
+         * 0.0.0.0 is invalid. should be ignored.
+         */
         uint8_t[4] v4;
 
+        /**
+         * 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 is invalid. should be ignored.
+         */
         uint8_t[16] v6;
     } dstIpAddress;
 
+    /**
+     * 0 is invalid. should be ignored.
+     */
     uint16_t srcPort;
 
+    /**
+     * 0 is invalid. should be ignored.
+     */
     uint16_t dstPort;
 };
 
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 0d7131a..9236b95 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -139,6 +139,9 @@
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
 
+    std::vector<CompositePrimitive> supported;
+    getSupportedPrimitives(&supported);
+
     for (auto& e : composite) {
         if (e.delayMs > kComposeDelayMaxMs) {
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
@@ -146,8 +149,7 @@
         if (e.scale <= 0.0f || e.scale > 1.0f) {
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
-        if (e.primitive < CompositePrimitive::NOOP ||
-            e.primitive > CompositePrimitive::LIGHT_TICK) {
+        if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
             return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
         }
     }
diff --git a/wifi/1.2/IWifiStaIface.hal b/wifi/1.2/IWifiStaIface.hal
index 3a7f777..d65b33b 100644
--- a/wifi/1.2/IWifiStaIface.hal
+++ b/wifi/1.2/IWifiStaIface.hal
@@ -23,7 +23,7 @@
 /**
  * Interface used to represent a single STA iface.
  *
- * IWifiChip.createStaIface() may return a @1.2::IWifiStaIface when supported.
+ * IWifiChip.createStaIface() must return a @1.2::IWifiStaIface when supported.
  */
 interface IWifiStaIface extends @1.0::IWifiStaIface {
     /**
diff --git a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
index 6e55664..96656f3 100644
--- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -439,7 +439,7 @@
     // synchronization objects
     std::mutex mtx_;
     std::condition_variable cv_;
-    int count_;
+    int count_ = 0;
 
    protected:
     android::sp<::android::hardware::wifi::V1_2::IWifiNanIface> iwifiNanIface;
diff --git a/wifi/1.3/IWifiStaIface.hal b/wifi/1.3/IWifiStaIface.hal
index 81c0c38..3a75509 100644
--- a/wifi/1.3/IWifiStaIface.hal
+++ b/wifi/1.3/IWifiStaIface.hal
@@ -23,7 +23,7 @@
 /**
  * Interface used to represent a single STA iface.
  *
- * IWifiChip.createStaIface() may return a @1.3::IWifiStaIface when supported.
+ * IWifiChip.createStaIface() must return a @1.3::IWifiStaIface when supported.
  */
 interface IWifiStaIface extends @1.2::IWifiStaIface {
     /**
diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp
index 4996e35..fd1d5b1 100644
--- a/wifi/1.4/default/hidl_struct_util.cpp
+++ b/wifi/1.4/default/hidl_struct_util.cpp
@@ -2715,6 +2715,21 @@
     }
     return true;
 }
+
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
+    IfaceType hidl_interface_type) {
+    switch (hidl_interface_type) {
+        case IfaceType::STA:
+            return legacy_hal::WIFI_INTERFACE_TYPE_STA;
+        case IfaceType::AP:
+            return legacy_hal::WIFI_INTERFACE_TYPE_AP;
+        case IfaceType::P2P:
+            return legacy_hal::WIFI_INTERFACE_TYPE_P2P;
+        case IfaceType::NAN:
+            return legacy_hal::WIFI_INTERFACE_TYPE_NAN;
+    }
+    CHECK(false);
+}
 }  // namespace hidl_struct_util
 }  // namespace implementation
 }  // namespace V1_4
diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h
index d040c1f..929f877 100644
--- a/wifi/1.4/default/hidl_struct_util.h
+++ b/wifi/1.4/default/hidl_struct_util.h
@@ -65,6 +65,8 @@
 bool convertLegacyWifiMacInfosToHidl(
     const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
     std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
+    IfaceType hidl_interface_type);
 
 // STA iface conversion methods.
 bool convertLegacyFeaturesToHidlStaCapabilities(
diff --git a/wifi/1.4/default/wifi.cpp b/wifi/1.4/default/wifi.cpp
index 4f48d7e..9c6b0f0 100644
--- a/wifi/1.4/default/wifi.cpp
+++ b/wifi/1.4/default/wifi.cpp
@@ -124,6 +124,8 @@
             }
         }
         LOG(ERROR) << "Wifi HAL start failed";
+        // Clear the event callback objects since the HAL start failed.
+        event_cb_handler_.invalidate();
     }
     return wifi_status;
 }
@@ -158,6 +160,8 @@
         }
         LOG(ERROR) << "Wifi HAL stop failed";
     }
+    // Clear the event callback objects since the HAL is now stopped.
+    event_cb_handler_.invalidate();
     return wifi_status;
 }
 
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
index 3498510..4c9fad1 100644
--- a/wifi/1.4/default/wifi_chip.cpp
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -797,6 +797,15 @@
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
     std::string ifname = allocateApIfaceName();
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->createVirtualInterface(
+            ifname,
+            hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to add interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
     sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_, iface_util_);
     ap_ifaces_.push_back(iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -835,6 +844,12 @@
     // nan/rtt objects over AP iface. But, there is no harm to do it
     // here and not make that assumption all over the place.
     invalidateAndRemoveDependencies(ifname);
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->deleteVirtualInterface(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+    }
     invalidateAndClear(ap_ifaces_, iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
         if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
@@ -944,6 +959,15 @@
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
     std::string ifname = allocateStaIfaceName();
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->createVirtualInterface(
+            ifname,
+            hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::STA));
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to add interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
     sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
     sta_ifaces_.push_back(iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -979,6 +1003,12 @@
     }
     // Invalidate & remove any dependent objects first.
     invalidateAndRemoveDependencies(ifname);
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->deleteVirtualInterface(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+    }
     invalidateAndClear(sta_ifaces_, iface);
     for (const auto& callback : event_cb_handler_.getCallbacks()) {
         if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
index 3ca3226..a040c89 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -19,6 +19,7 @@
 
 #include <android-base/logging.h>
 #include <cutils/properties.h>
+#include <net/if.h>
 
 #include "hidl_sync_util.h"
 #include "wifi_legacy_hal.h"
@@ -1355,6 +1356,7 @@
         LOG(ERROR) << "Failed to enumerate interface handles";
         return status;
     }
+    iface_name_to_handle_.clear();
     for (int i = 0; i < num_iface_handles; ++i) {
         std::array<char, IFNAMSIZ> iface_name_arr = {};
         status = global_func_table_.wifi_get_iface_name(
@@ -1421,6 +1423,39 @@
     return {status, std::move(cached_scan_results)};
 }
 
+wifi_error WifiLegacyHal::createVirtualInterface(const std::string& ifname,
+                                                 wifi_interface_type iftype) {
+    // Create the interface if it doesn't exist. If interface already exist,
+    // Vendor Hal should return WIFI_SUCCESS.
+    wifi_error status = global_func_table_.wifi_virtual_interface_create(
+        global_handle_, ifname.c_str(), iftype);
+    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::deleteVirtualInterface(const std::string& ifname) {
+    // Delete the interface if it was created dynamically.
+    wifi_error status = global_func_table_.wifi_virtual_interface_delete(
+        global_handle_, ifname.c_str());
+    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::handleVirtualInterfaceCreateOrDeleteStatus(
+    const std::string& ifname, wifi_error status) {
+    if (status == WIFI_SUCCESS) {
+        // refresh list of handlers now.
+        status = retrieveIfaceHandles();
+    } else if (status == WIFI_ERROR_NOT_SUPPORTED) {
+        // Vendor hal does not implement this API. Such vendor implementations
+        // are expected to create / delete interface by other means.
+
+        // check if interface exists.
+        if (if_nametoindex(ifname.c_str())) {
+            status = retrieveIfaceHandles();
+        }
+    }
+    return status;
+}
+
 void WifiLegacyHal::invalidate() {
     global_handle_ = nullptr;
     iface_name_to_handle_.clear();
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h
index a7b40a0..72cf197 100644
--- a/wifi/1.4/default/wifi_legacy_hal.h
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -369,6 +369,11 @@
     wifi_error setCountryCode(const std::string& iface_name,
                               std::array<int8_t, 2> code);
 
+    // interface functions.
+    wifi_error createVirtualInterface(const std::string& ifname,
+                                      wifi_interface_type iftype);
+    wifi_error deleteVirtualInterface(const std::string& ifname);
+
    private:
     // Retrieve interface handles for all the available interfaces.
     wifi_error retrieveIfaceHandles();
@@ -380,6 +385,9 @@
     std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
     getGscanCachedResults(const std::string& iface_name);
     void invalidate();
+    // Handles wifi (error) status of Virtual interface create/delete
+    wifi_error handleVirtualInterfaceCreateOrDeleteStatus(
+        const std::string& ifname, wifi_error status);
 
     // Global function table of legacy HAL.
     wifi_hal_fn global_func_table_;
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
index bbe470e..6945b4c 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
@@ -139,6 +139,8 @@
     populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
     populateStubFor(&hal_fn->wifi_set_latency_mode);
     populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
+    populateStubFor(&hal_fn->wifi_virtual_interface_create);
+    populateStubFor(&hal_fn->wifi_virtual_interface_delete);
     return true;
 }
 }  // namespace legacy_hal
diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp
index 46ac3ee..d857be1 100644
--- a/wifi/1.4/vts/functional/Android.bp
+++ b/wifi/1.4/vts/functional/Android.bp
@@ -22,7 +22,8 @@
         "VtsHalWifiV1_4TargetTest.cpp",
         "wifi_ap_iface_hidl_test.cpp",
         "wifi_chip_hidl_test.cpp",
-		"wifi_nan_iface_hidl_test.cpp"
+        "wifi_nan_iface_hidl_test.cpp",
+        "wifi_rtt_controller_hidl_test.cpp",
     ],
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
@@ -31,7 +32,10 @@
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
         "android.hardware.wifi@1.4",
-        "libwifi-system-iface"
+        "libwifi-system-iface",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
index 7896067..1c39550 100644
--- a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
@@ -19,6 +19,7 @@
 
 #undef NAN  // NAN is defined in bionic/libc/include/math.h:38
 
+#include <android/hardware/wifi/1.3/IWifiStaIface.h>
 #include <android/hardware/wifi/1.4/IWifi.h>
 #include <android/hardware/wifi/1.4/IWifiChip.h>
 #include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
@@ -34,10 +35,12 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
+using ::android::hardware::wifi::V1_0::ChipModeId;
 using ::android::hardware::wifi::V1_0::IfaceType;
 using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus;
 using ::android::hardware::wifi::V1_0::WifiStatus;
 using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_3::IWifiStaIface;
 using ::android::hardware::wifi::V1_4::IWifiChip;
 using ::android::hardware::wifi::V1_4::IWifiChipEventCallback;
 
@@ -110,6 +113,16 @@
     };
 
    protected:
+    // Helper function to configure the Chip in one of the supported modes.
+    // Most of the non-mode-configuration-related methods require chip
+    // to be first configured.
+    ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) {
+        ChipModeId mode_id;
+        EXPECT_EQ(expectSuccess,
+                  configureChipToSupportIfaceType(wifi_chip_, type, &mode_id));
+        return mode_id;
+    }
+
     sp<IWifiChip> wifi_chip_;
 
    private:
@@ -136,3 +149,31 @@
         return;
     }
 }
+
+/*
+ * createRttController_1_4
+ * Ensures that an instance of the IWifiRttController proxy object is
+ * successfully created.
+ */
+TEST_P(WifiChipHidlTest, createRttController_1_4) {
+    configureChipForIfaceType(IfaceType::STA, true);
+
+    const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createStaIface);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface.first.code);
+    sp<IWifiStaIface> iface = IWifiStaIface::castFrom(status_and_iface.second);
+    EXPECT_NE(nullptr, iface.get());
+
+    const auto& status_and_controller =
+        HIDL_INVOKE(wifi_chip_, createRttController_1_4, iface);
+    if (status_and_controller.first.code !=
+        WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code);
+        EXPECT_NE(nullptr, status_and_controller.second.get());
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_4::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
index 688faf1..24daee6 100644
--- a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -440,7 +440,7 @@
     // synchronization objects
     std::mutex mtx_;
     std::condition_variable cv_;
-    int count_;
+    int count_ = 0;
 
    protected:
     android::sp<::android::hardware::wifi::V1_4::IWifiNanIface> iwifiNanIface;
@@ -545,3 +545,9 @@
                           nanConfigRequest, nanConfigRequestSupp)
                   .code);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiNanIfaceHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_4::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
new file mode 100644
index 0000000..726470c
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -0,0 +1,224 @@
+/*
+ * 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 <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+
+#undef NAN  // NAN is defined in bionic/libc/include/math.h:38
+
+#include <android/hardware/wifi/1.3/IWifiStaIface.h>
+#include <android/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifiChip.h>
+#include <android/hardware/wifi/1.4/IWifiRttController.h>
+#include <android/hardware/wifi/1.4/IWifiRttControllerEventCallback.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::V1_0::CommandId;
+using ::android::hardware::wifi::V1_0::RttBw;
+using ::android::hardware::wifi::V1_0::RttPeerType;
+using ::android::hardware::wifi::V1_0::RttType;
+using ::android::hardware::wifi::V1_0::WifiChannelInfo;
+using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_3::IWifiStaIface;
+using ::android::hardware::wifi::V1_4::IWifiChip;
+using ::android::hardware::wifi::V1_4::IWifiRttController;
+using ::android::hardware::wifi::V1_4::IWifiRttControllerEventCallback;
+using ::android::hardware::wifi::V1_4::RttCapabilities;
+using ::android::hardware::wifi::V1_4::RttConfig;
+using ::android::hardware::wifi::V1_4::RttPreamble;
+using ::android::hardware::wifi::V1_4::RttResponder;
+using ::android::hardware::wifi::V1_4::RttResult;
+
+/**
+ * Fixture to use for all RTT controller HIDL interface tests.
+ */
+class WifiRttControllerHidlTest : public ::testing::TestWithParam<std::string> {
+   public:
+    virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_rtt_controller_ = getWifiRttController();
+        ASSERT_NE(nullptr, wifi_rtt_controller_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+    // A simple test implementation of WifiChipEventCallback.
+    class WifiRttControllerEventCallback
+        : public ::testing::VtsHalHidlTargetCallbackBase<
+              WifiRttControllerHidlTest>,
+          public IWifiRttControllerEventCallback {
+       public:
+        WifiRttControllerEventCallback(){};
+
+        virtual ~WifiRttControllerEventCallback() = default;
+
+        Return<void> onResults(
+            CommandId cmdId __unused,
+            const hidl_vec<::android::hardware::wifi::V1_0::RttResult>& results
+                __unused) {
+            return Void();
+        };
+
+        Return<void> onResults_1_4(CommandId cmdId __unused,
+                                   const hidl_vec<RttResult>& results
+                                       __unused) {
+            return Void();
+        };
+    };
+
+   protected:
+    sp<IWifiRttController> wifi_rtt_controller_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
+
+    sp<IWifiRttController> getWifiRttController() {
+        const std::string& instance_name = GetInstanceName();
+
+        sp<IWifiChip> wifi_chip =
+            IWifiChip::castFrom(getWifiChip(instance_name));
+        EXPECT_NE(nullptr, wifi_chip.get());
+
+        sp<IWifiStaIface> wifi_sta_iface =
+            IWifiStaIface::castFrom(getWifiStaIface(instance_name));
+        EXPECT_NE(nullptr, wifi_sta_iface.get());
+
+        const auto& status_and_controller =
+            HIDL_INVOKE(wifi_chip, createRttController_1_4, wifi_sta_iface);
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code);
+        EXPECT_NE(nullptr, status_and_controller.second.get());
+
+        return status_and_controller.second.get();
+    }
+};
+
+/*
+ * registerEventCallback_1_4
+ * This test case tests the registerEventCallback_1_4() API which registers
+ * a call back function with the hal implementation
+ *
+ * Note: it is not feasible to test the invocation of the call back function
+ * since event is triggered internally in the HAL implementation, and can not be
+ * triggered from the test case
+ */
+TEST_P(WifiRttControllerHidlTest, RegisterEventCallback_1_4) {
+    sp<WifiRttControllerEventCallback> wifiRttControllerEventCallback =
+        new WifiRttControllerEventCallback();
+    const auto& status =
+        HIDL_INVOKE(wifi_rtt_controller_, registerEventCallback_1_4,
+                    wifiRttControllerEventCallback);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+
+/*
+ * rangeRequest_1_4
+ */
+TEST_P(WifiRttControllerHidlTest, RangeRequest_1_4) {
+    std::vector<RttConfig> configs;
+    RttConfig config;
+    int cmdId = 55;
+    // Set the config with test data
+    for (int i = 0; i < 6; i++) {
+        config.addr[i] = i;
+    }
+    config.type = RttType::ONE_SIDED;
+    config.peer = RttPeerType::STA;
+    config.channel.width = WifiChannelWidthInMhz::WIDTH_80;
+    config.channel.centerFreq = 5765;
+    config.channel.centerFreq0 = 5775;
+    config.channel.centerFreq1 = 0;
+    config.bw = RttBw::BW_80MHZ;
+    config.preamble = RttPreamble::HE;
+    config.mustRequestLci = false;
+    config.mustRequestLcr = false;
+    config.burstPeriod = 0;
+    config.numBurst = 0;
+    config.numFramesPerBurst = 8;
+    config.numRetriesPerRttFrame = 3;
+    config.numRetriesPerFtmr = 3;
+    config.burstDuration = 9;
+    // Insert config in the vector
+    configs.push_back(config);
+
+    // Invoke the call
+    const auto& status =
+        HIDL_INVOKE(wifi_rtt_controller_, rangeRequest_1_4, cmdId, configs);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+
+/*
+ * getCapabilities_1_4
+ */
+TEST_P(WifiRttControllerHidlTest, GetCapabilities_1_4) {
+    std::pair<WifiStatus, RttCapabilities> status_and_caps;
+
+    // Invoke the call
+    status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_4);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+}
+
+/*
+ * getResponderInfo_1_4
+ */
+TEST_P(WifiRttControllerHidlTest, GetResponderInfo_1_4) {
+    std::pair<WifiStatus, RttResponder> status_and_info;
+
+    // Invoke the call
+    status_and_info = HIDL_INVOKE(wifi_rtt_controller_, getResponderInfo_1_4);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_info.first.code);
+}
+
+/*
+ * enableResponder_1_4
+ */
+TEST_P(WifiRttControllerHidlTest, EnableResponder_1_4) {
+    std::pair<WifiStatus, RttResponder> status_and_info;
+    int cmdId = 55;
+    WifiChannelInfo channelInfo;
+    channelInfo.width = WifiChannelWidthInMhz::WIDTH_80;
+    channelInfo.centerFreq = 5690;
+    channelInfo.centerFreq0 = 5690;
+    channelInfo.centerFreq1 = 0;
+
+    // Get the responder first
+    status_and_info = HIDL_INVOKE(wifi_rtt_controller_, getResponderInfo_1_4);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_info.first.code);
+
+    // Invoke the call
+    const auto& status =
+        HIDL_INVOKE(wifi_rtt_controller_, enableResponder_1_4, cmdId,
+                    channelInfo, 10, status_and_info.second);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiRttControllerHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_4::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_call_util.h b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_call_util.h
index 2f71ccb..ec7ebee 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_call_util.h
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_call_util.h
@@ -25,8 +25,6 @@
 #include <type_traits>
 #include <utility>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace {
 namespace detail {
 template <typename>
diff --git a/wifi/hostapd/1.2/types.hal b/wifi/hostapd/1.2/types.hal
index 54e6529..9c187fa 100644
--- a/wifi/hostapd/1.2/types.hal
+++ b/wifi/hostapd/1.2/types.hal
@@ -38,6 +38,9 @@
     WLAN_REASON_DISASSOC_AP_BUSY = 5,
 };
 
+/**
+ * Mac Address type. 6 octets representing physical address of a device.
+ */
 typedef uint8_t[6] MacAddress;
 
 /**
diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
index 9f57934..2715891 100644
--- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <VtsCoreUtil.h>
+
 #include <android-base/logging.h>
 #include <cutils/properties.h>
 
@@ -62,11 +64,19 @@
                                           hostapd_instance_name_);
         hostapd_ = IHostapd::getService(hostapd_instance_name_);
         ASSERT_NE(hostapd_.get(), nullptr);
+        isAcsSupport_ = testing::checkSubstringInCommandOutput(
+            "/system/bin/cmd wifi get-softap-supported-features",
+            "wifi_softap_acs_supported");
+        isWpa3SaeSupport_ = testing::checkSubstringInCommandOutput(
+            "/system/bin/cmd wifi get-softap-supported-features",
+            "wifi_softap_wpa3_sae_supported");
     }
 
     virtual void TearDown() override { stopHostapd(hostapd_instance_name_); }
 
    protected:
+    bool isWpa3SaeSupport_ = false;
+    bool isAcsSupport_ = false;
     std::string getPrimaryWlanIfaceName() {
         std::array<char, PROPERTY_VALUE_MAX> buffer;
         auto res = property_get("ro.vendor.wifi.sap.interface", buffer.data(),
@@ -208,10 +218,10 @@
  * Access point creation should pass.
  */
 TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) {
+    if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
                               getIfaceParamsWithAcs(), getPskNwParams());
-    // TODO: b/140172237, fix this in R.
-    // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
 
 /**
@@ -219,11 +229,11 @@
  * Access point creation should pass.
  */
 TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndFreqRange) {
+    if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
     auto status =
         HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
                     getIfaceParamsWithAcsAndFreqRange(), getPskNwParams());
-    // TODO: b/140172237, fix this in R
-    // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
 
 /**
@@ -231,11 +241,11 @@
  * Access point creation should fail.
  */
 TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidFreqRange) {
+    if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
                               getIfaceParamsWithAcsAndInvalidFreqRange(),
                               getPskNwParams());
-    // TODO: b/140172237, fix this in R
-    // EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+    EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
 }
 
 /**
@@ -243,10 +253,10 @@
  * Access point creation should pass.
  */
 TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) {
+    if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
                               getIfaceParamsWithAcs(), getOpenNwParams());
-    // TODO: b/140172237, fix this in R
-    // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
 
 /**
@@ -274,6 +284,7 @@
  * Access point creation should pass.
  */
 TEST_P(HostapdHidlTest, AddSaeTransitionAccessPointWithoutAcs) {
+    if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
     auto status =
         HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
                     getSaeTransitionNwParams());
@@ -285,6 +296,7 @@
  * Access point creation should pass.
  */
 TEST_P(HostapdHidlTest, AddSAEAccessPointWithoutAcs) {
+    if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
                               getIfaceParamsWithoutAcs(), getSaeNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
@@ -295,16 +307,15 @@
  * Access point creation & removal should pass.
  */
 TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) {
+    if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
     auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
                                   getIfaceParamsWithAcs(), getPskNwParams());
-    // TODO: b/140172237, fix this in R
-    /*
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
     auto status =
         HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
-    EXPECT_EQ(android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
-    status.code);
-    */
+    EXPECT_EQ(
+        android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
+        status.code);
 }
 
 /**
@@ -349,6 +360,7 @@
  * Access point creation should fail.
  */
 TEST_P(HostapdHidlTest, AddInvalidSaeTransitionAccessPointWithoutAcs) {
+    if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
     auto status =
         HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
                     getInvalidSaeTransitionNwParams());
@@ -360,6 +372,7 @@
  * Access point creation should fail.
  */
 TEST_P(HostapdHidlTest, AddInvalidSaeAccessPointWithoutAcs) {
+    if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
     auto status =
         HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
                     getInvalidSaeNwParams());
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index 332ee4a..8013906 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -46,6 +46,8 @@
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
+        "android.hardware.wifi.supplicant@1.2",
+        "android.hardware.wifi.supplicant@1.3",
         "android.hardware.wifi@1.0",
         "libgmock",
         "libwifi-system",
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
index 52f77a1..5467e02 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -19,6 +19,7 @@
 #include <VtsCoreUtil.h>
 #include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -93,6 +94,11 @@
         EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
         sta_network_ = createSupplicantStaNetwork(supplicant_);
         ASSERT_NE(sta_network_.get(), nullptr);
+        /* variable used to check if the underlying HAL version is 1.3 or
+         * higher. This is to skip tests which are using deprecated methods.
+         */
+        v1_3 = ::android::hardware::wifi::supplicant::V1_3::
+            ISupplicantStaNetwork::castFrom(sta_network_);
 
         ssid_.assign(kTestSsidStr, kTestSsidStr + strlen(kTestSsidStr));
     }
@@ -114,6 +120,8 @@
         });
     }
 
+    sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork>
+        v1_3 = nullptr;
     bool isP2pOn_ = false;
     sp<ISupplicant> supplicant_;
     // ISupplicantStaNetwork object used for all tests in this fixture.
@@ -221,6 +229,9 @@
  * SetGetKeyMgmt
  */
 TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt) {
+    if (v1_3 != nullptr) {
+        GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher";
+    }
     sta_network_->setKeyMgmt(kTestKeyMgmt, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -235,6 +246,9 @@
  * SetGetProto
  */
 TEST_P(SupplicantStaNetworkHidlTest, SetGetProto) {
+    if (v1_3 != nullptr) {
+        GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher";
+    }
     sta_network_->setProto(kTestProto, [](const SupplicantStatus& status) {
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
@@ -262,6 +276,9 @@
  * SetGetGroupCipher
  */
 TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher) {
+    if (v1_3 != nullptr) {
+        GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher";
+    }
     sta_network_->setGroupCipher(
         kTestGroupCipher, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -277,6 +294,9 @@
  * SetGetPairwiseCipher
  */
 TEST_P(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher) {
+    if (v1_3 != nullptr) {
+        GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher";
+    }
     sta_network_->setPairwiseCipher(
         kTestPairwiseCipher, [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -627,6 +647,9 @@
  * Enable
  */
 TEST_P(SupplicantStaNetworkHidlTest, Enable) {
+    if (v1_3 != nullptr) {
+        GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher";
+    }
     // wpa_supplicant doesn't perform any connection initiation
     // unless atleast the Ssid and Ket mgmt params are set.
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
@@ -654,6 +677,9 @@
  * Disable
  */
 TEST_P(SupplicantStaNetworkHidlTest, Disable) {
+    if (v1_3 != nullptr) {
+        GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher";
+    }
     // wpa_supplicant doesn't perform any connection initiation
     // unless atleast the Ssid and Ket mgmt params are set.
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
@@ -677,6 +703,9 @@
  * Select.
  */
 TEST_P(SupplicantStaNetworkHidlTest, Select) {
+    if (v1_3 != nullptr) {
+        GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher";
+    }
     // wpa_supplicant doesn't perform any connection initiation
     // unless atleast the Ssid and Ket mgmt params are set.
     sta_network_->setSsid(ssid_, [](const SupplicantStatus& status) {
@@ -788,6 +817,9 @@
  * GetWpsNfcConfigurationToken
  */
 TEST_P(SupplicantStaNetworkHidlTest, GetWpsNfcConfigurationToken) {
+    if (v1_3 != nullptr) {
+        GTEST_SKIP() << "Skipping test since HAL is 1.3 or higher";
+    }
     ASSERT_EQ(SupplicantStatusCode::SUCCESS,
               HIDL_INVOKE(sta_network_, setSsid, ssid_).code);
     ASSERT_EQ(SupplicantStatusCode::SUCCESS,
@@ -808,4 +840,4 @@
             android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
             ISupplicant::descriptor))),
-    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
+    android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp
index 9781074..22dec84 100644
--- a/wifi/supplicant/1.2/vts/functional/Android.bp
+++ b/wifi/supplicant/1.2/vts/functional/Android.bp
@@ -68,7 +68,7 @@
     name: "VtsHalWifiSupplicantP2pV1_2TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiSupplicantV1_2TargetTest.cpp",
+        "VtsHalWifiSupplicantP2pV1_2TargetTest.cpp",
         "supplicant_p2p_iface_hidl_test.cpp",
     ],
     static_libs: [
diff --git a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp
new file mode 100644
index 0000000..22bf1db
--- /dev/null
+++ b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp
@@ -0,0 +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.
+ */
+
+#include <VtsCoreUtil.h>
+#include "supplicant_hidl_test_utils.h"
+
+// TODO(b/143892896): Remove this line after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
+
+int main(int argc, char** argv) {
+    if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct"))
+        return 0;
+
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 8116c3f..f38dda4 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -111,9 +111,14 @@
         // If DPP is not supported, we just pass the test.
         sta_iface_->getKeyMgmtCapabilities(
             [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
-                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                // Since getKeyMgmtCapabilities() is overridden by an
+                // upgraded API in newer HAL versions, allow for
+                // FAILURE_UNKNOWN and return DPP is not supported.
+                if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                    EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
 
-                keyMgmtMask = keyMgmtMaskInternal;
+                    keyMgmtMask = keyMgmtMaskInternal;
+                }
             });
 
         if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) {
@@ -268,8 +273,12 @@
  * GetKeyMgmtCapabilities
  */
 TEST_P(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) {
-    sta_iface_->getKeyMgmtCapabilities(
-        [&](const SupplicantStatus& status, uint32_t keyMgmtMask) {
+    sta_iface_->getKeyMgmtCapabilities([&](const SupplicantStatus& status,
+                                           uint32_t keyMgmtMask) {
+        // Since this API is overridden by an upgraded API in newer HAL
+        // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+        // longer supported on newer HAL.
+        if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
 
             // Even though capabilities vary, these two are always set in HAL
@@ -277,7 +286,8 @@
             EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::NONE);
             EXPECT_TRUE(keyMgmtMask &
                         ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X);
-        });
+        }
+    });
 }
 
 /*
@@ -455,4 +465,4 @@
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
             android::hardware::wifi::supplicant::V1_2::ISupplicant::
                 descriptor))),
-    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
+    android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
index 4c3d808..54ceb20 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -112,13 +112,23 @@
     uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::SAE;
 
     sta_network_->setKeyMgmt_1_2(keyMgmt, [](const SupplicantStatus &status) {
-        EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        // Since this API is overridden by an upgraded API in newer HAL
+        // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+        // longer supported on newer HALs.
+        if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        }
     });
 
     sta_network_->getKeyMgmt_1_2(
         [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-            EXPECT_EQ(keyMgmtOut, keyMgmt);
+            // Since this API is overridden by an upgraded API in newer HAL
+            // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+            // longer supported on newer HALs.
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                EXPECT_EQ(keyMgmtOut, keyMgmt);
+            }
         });
 }
 
@@ -131,14 +141,24 @@
 
     sta_network_->setGroupCipher_1_2(
         groupCipher, [](const SupplicantStatus &status) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            // Since this API is overridden by an upgraded API in newer HAL
+            // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+            // longer supported on newer HALs.
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            }
         });
 
     sta_network_->getGroupCipher_1_2(
         [&groupCipher](const SupplicantStatus &status,
                        uint32_t groupCipherOut) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-            EXPECT_EQ(groupCipherOut, groupCipher);
+            // Since this API is overridden by an upgraded API in newer HAL
+            // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+            // longer supported on newer HALs.
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                EXPECT_EQ(groupCipherOut, groupCipher);
+            }
         });
 }
 
@@ -151,14 +171,24 @@
 
     sta_network_->setPairwiseCipher_1_2(
         pairwiseCipher, [](const SupplicantStatus &status) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            // Since this API is overridden by an upgraded API in newer HAL
+            // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+            // longer supported on newer HALs.
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            }
         });
 
     sta_network_->getPairwiseCipher_1_2(
         [&pairwiseCipher](const SupplicantStatus &status,
                           uint32_t pairwiseCipherOut) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-            EXPECT_EQ(pairwiseCipherOut, pairwiseCipher);
+            // Since this API is overridden by an upgraded API in newer HAL
+            // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+            // longer supported on newer HALs.
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                EXPECT_EQ(pairwiseCipherOut, pairwiseCipher);
+            }
         });
 }
 
diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal
index b501a95..4506f37 100644
--- a/wifi/supplicant/1.3/ISupplicantStaIface.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal
@@ -69,7 +69,7 @@
         bitfield<WpaDriverCapabilitiesMask> driverCapabilitiesMask);
 
     /**
-     * Set MBO cellular data status.
+     * Set Wi-Fi Alliance Agile Multiband (MBO) cellular data status.
      *
      * @param available true means cellular data available, false otherwise.
      * @return status Status of the operation.
@@ -93,8 +93,10 @@
         generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
 
     /**
-     * Flush FILS HLP IEs
-     * Use this to flush all the HLP IEs in wpa_supplicant
+     * Flush fast initial link setup (IEEE 802.11ai FILS) HLP packets.
+     * Use this to flush all the higher layer protocol (HLP) packets added in
+     * wpa_supplicant to send in FILS (Re)Association Request frame
+     * (Eg: DHCP discover packet).
      *
      * @return status Status of the operation.
      *         Possible status codes:
@@ -106,11 +108,12 @@
     filsHlpFlushRequest() generates (SupplicantStatus status);
 
     /**
-     * Add FILS HLP IEs
-     * Use this to add a HLP IE to wpa_supplicant
+     * Add fast initial link setup (IEEE 802.11ai FILS) HLP packets.
+     * Use this to add higher layer protocol (HLP) packet in FILS (Re)Association Request frame
+     * (Eg: DHCP discover packet).
      *
      * @param dst_mac MAC address of the destination
-     * @param pkt The contents of the HLP IE starting from ethertype
+     * @param pkt The contents of the HLP packet starting from ethertype
      * @return status Status of the operation.
      *         Possible status codes:
      *         |SupplicantStatusCode.SUCCESS|,
diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
index 6828dcd..c5da29c 100644
--- a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
@@ -147,7 +147,7 @@
     };
 
     /**
-     * Indicates PMK cache added event.
+     * Indicates pairwise master key (PMK) cache added event.
      *
      * @param expirationTimeInSec expiration time in seconds
      * @param serializedEntry is serialized PMK cache entry, the content is
@@ -192,6 +192,9 @@
 
     /**
      * Indicates an EAP authentication failure.
+     * @param errorCode Error code for EAP authentication failure.
+     *        Either standard error code (enum EapErrorCode) or
+     *        private error code defined by network provider.
      */
     oneway onEapFailure_1_3(uint32_t errorCode);
 
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
index 0566a21..2505912 100644
--- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
@@ -214,7 +214,7 @@
         generates (SupplicantStatus status, bitfield<GroupCipherMask> groupCipherMask);
 
     /**
-     * Set WAPI certificate suite for this network.
+     * Set WAPI certificate suite name for this network.
      *
      * @param suite value to set.
      * @return status Status of the operation.
@@ -227,7 +227,7 @@
     setWapiCertSuite(string suite) generates (SupplicantStatus status);
 
     /**
-     * Get WAPI certificate suite set for this network.
+     * Get WAPI certificate suite name set for this network.
      *
      * @return status Status of the operation.
      *         Possible status codes:
@@ -239,7 +239,7 @@
     getWapiCertSuite() generates (SupplicantStatus status, string suite);
 
     /**
-     * Add a PMK into supplicant PMK cache.
+     * Add a pairwise master key (PMK) into supplicant PMK cache.
      *
      * @param serializedEntry is serialized PMK cache entry, the content is
      *              opaque for the framework and depends on the native implementation.
@@ -278,7 +278,7 @@
     getAuthAlg_1_3() generates (SupplicantStatus status, bitfield<AuthAlgMask> authAlgMask);
 
     /**
-     * Enable EAP ERP for this network.
+     * Enable Extensible Authentication (EAP) - Re-authentication Protocol (ERP) for this network.
      *
      * @param enable true to set, false otherwise.
      * @return status Status of the operation.
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
index 13f3366..6be24bc 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -17,7 +17,6 @@
 #include <android-base/logging.h>
 
 #include <VtsCoreUtil.h>
-#include <VtsHalHidlTargetTestBase.h>
 #include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.1/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
@@ -57,6 +56,8 @@
         supplicant_ =
             getSupplicant_1_3(supplicant_v1_3_instance_name_, isP2pOn_);
         EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_iface_ = getSupplicantStaIface_1_3(supplicant_);
+        ASSERT_NE(nullptr, sta_iface_.get());
         sta_network_ = createSupplicantStaNetwork_1_3(supplicant_);
         ASSERT_NE(sta_network_.get(), nullptr);
     }