Merge changes from topic "tuner-vts-ref"

* changes:
  Refactor Tuner VTS dvr and descrambler test implementation
  Refactor Tuner VTS broadcast data flow test
  Refactor Tuner VTS filter part
  Refactor Tuner vts test Demux part
  Refactoring Tuner VTS frontend test part
diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal
index 941ba61..13a86ec 100644
--- a/audio/6.0/IStreamOut.hal
+++ b/audio/6.0/IStreamOut.hal
@@ -276,4 +276,90 @@
      */
     selectPresentation(int32_t presentationId, int32_t programId)
             generates (Result retval);
+
+    /**
+     * Returns the Dual Mono mode presentation setting.
+     *
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return mode current setting of Dual Mono mode.
+     */
+    getDualMonoMode() generates (Result retval, DualMonoMode mode);
+
+    /**
+     * Sets the Dual Mono mode presentation on the output device.
+     *
+     * The Dual Mono mode is generally applied to stereo audio streams
+     * where the left and right channels come from separate sources.
+     *
+     * Optional method
+     *
+     * @param mode selected Dual Mono mode.
+     * @return retval operation completion status.
+     */
+    setDualMonoMode(DualMonoMode mode) generates (Result retval);
+
+    /**
+     * Returns the Audio Description Mix level in dB.
+     *
+     * The level is applied to streams incorporating a secondary Audio
+     * Description stream. It specifies the relative level of mixing for
+     * the Audio Description with a reference to the Main Audio.
+     *
+     * Optional method
+     *
+     * The value of the relative level is in the range from negative infinity
+     * to +48.
+     *
+     * @return retval operation completion status.
+     * @return leveldB the current Audio Description Mix Level in dB.
+     */
+    getAudioDescriptionMixLevel() generates (Result retval, float leveldB);
+
+    /**
+     * Sets the Audio Description Mix level in dB.
+     *
+     * For streams incorporating a secondary Audio Description stream
+     * the relative level of mixing of the Audio Description to the Main Audio
+     * is controlled by this method.
+     *
+     * Optional method
+     *
+     * The value of the relative level must be in the range from negative
+     * infinity to +48.
+     *
+     * @param leveldB Audio Description Mix Level in dB
+     * @return retval operation completion status.
+     */
+    setAudioDescriptionMixLevel(float leveldB) generates (Result retval);
+
+    /**
+     * Retrieves current playback rate parameters.
+     *
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return playbackRate current playback parameters
+     */
+    getPlaybackRateParameters()
+            generates (Result retval, PlaybackRate playbackRate);
+
+    /**
+     * Sets the playback rate parameters that control playback behavior.
+     * This is normally used when playing encoded content and decoding
+     * is performed in hardware. Otherwise, the framework can apply
+     * necessary transformations.
+     *
+     * Optional method
+     *
+     * If the HAL supports setting the playback rate, it is recommended
+     * to support speed and pitch values at least in the range
+     * from 0.5f to 2.0f, inclusive (see the definition of PlaybackRate struct).
+     *
+     * @param playbackRate playback parameters
+     * @return retval operation completion status.
+     */
+    setPlaybackRateParameters(PlaybackRate playbackRate)
+            generates (Result retval);
 };
diff --git a/audio/6.0/types.hal b/audio/6.0/types.hal
index 1a704f8..8ff618e 100644
--- a/audio/6.0/types.hal
+++ b/audio/6.0/types.hal
@@ -247,3 +247,111 @@
      */
     EXTERNAL = 3,
 };
+
+
+/* Dual Mono handling is used when a stereo audio stream
+ * contains separate audio content on the left and right channels.
+ * Such information about the content of the stream may be found, for example,
+ * in ITU T-REC-J.94-201610 A.6.2.3 Component descriptor.
+ */
+@export(name="audio_dual_mono_mode_t", value_prefix="AUDIO_DUAL_MONO_MODE_")
+enum DualMonoMode : int32_t {
+    // Need to be in sync with DUAL_MONO_MODE* constants in
+    // frameworks/base/media/java/android/media/AudioTrack.java
+    /**
+     * Disable any Dual Mono presentation effect.
+     *
+     */
+    OFF = 0,
+    /**
+     * This mode indicates that a stereo stream should be presented
+     * with the left and right audio channels blended together
+     * and delivered to both channels.
+     *
+     * Behavior for non-stereo streams is implementation defined.
+     * A suggested guideline is that the left-right stereo symmetric
+     * channels are pairwise blended, the other channels such as center
+     * are left alone.
+     */
+    LR = 1,
+    /**
+     * This mode indicates that a stereo stream should be presented
+     * with the left audio channel replicated into the right audio channel.
+     *
+     * Behavior for non-stereo streams is implementation defined.
+     * A suggested guideline is that all channels with left-right
+     * stereo symmetry will have the left channel position replicated
+     * into the right channel position. The center channels (with no
+     * left/right symmetry) or unbalanced channels are left alone.
+     */
+    LL = 2,
+    /**
+     * This mode indicates that a stereo stream should be presented
+     * with the right audio channel replicated into the left audio channel.
+     *
+     * Behavior for non-stereo streams is implementation defined.
+     * A suggested guideline is that all channels with left-right
+     * stereo symmetry will have the right channel position replicated
+     * into the left channel position. The center channels (with no
+     * left/right symmetry) or unbalanced channels are left alone.
+     */
+    RR = 3,
+};
+
+/**
+ * Algorithms used for timestretching (preserving pitch while playing audio
+ * content at different speed).
+ */
+@export(name="audio_timestretch_stretch_mode_t", value_prefix="AUDIO_TIMESTRETCH_STRETCH_")
+enum TimestretchMode : int32_t {
+    // Need to be in sync with AUDIO_STRETCH_MODE_* constants in
+    // frameworks/base/media/java/android/media/PlaybackParams.java
+    DEFAULT = 0,
+    /** Selects timestretch algorithm best suitable for voice (speech) content. */
+    VOICE = 1,
+};
+
+/**
+ * Behavior when the values for speed and / or pitch are out
+ * of applicable range.
+ */
+@export(name="audio_timestretch_fallback_mode_t", value_prefix="AUDIO_TIMESTRETCH_FALLBACK_")
+enum TimestretchFallbackMode : int32_t {
+    // Need to be in sync with AUDIO_FALLBACK_MODE_* constants in
+    // frameworks/base/media/java/android/media/PlaybackParams.java
+    /** Play silence for parameter values that are out of range. */
+    MUTE = 1,
+    /** Return an error while trying to set the parameters. */
+    FAIL = 2,
+};
+
+/**
+ * Parameters determining playback behavior. They are used to speed up or
+ * slow down playback and / or change the tonal frequency of the audio content
+ * (pitch).
+ */
+struct PlaybackRate {
+    /**
+     * Speed factor (multiplier). Normal speed has the value of 1.0f.
+     * Values less than 1.0f slow down playback, value greater than 1.0f
+     * speed it up.
+     */
+    float speed;
+    /**
+     * Pitch factor (multiplier). Setting pitch value to 1.0f together
+     * with changing playback speed preserves the pitch, this is often
+     * called "timestretching." Setting the pitch value equal to speed produces
+     * the same effect as playing audio content at different sampling rate.
+     */
+    float pitch;
+    /**
+     * Selects the algorithm used for timestretching (preserving pitch while
+     * playing audio at different speed).
+     */
+    TimestretchMode timestretchMode;
+    /**
+     * Selects the behavior when the specified values for speed and / or pitch
+     * are out of applicable range.
+     */
+    TimestretchFallbackMode fallbackMode;
+};
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
index b2806c7..67217ab 100644
--- a/audio/common/6.0/types.hal
+++ b/audio/common/6.0/types.hal
@@ -903,6 +903,25 @@
     SONIFICATION = 4,
 };
 
+/** Encapsulation mode used for sending audio compressed data. */
+@export(name="audio_encapsulation_mode_t", value_prefix="AUDIO_ENCAPSULATION_MODE_")
+enum AudioEncapsulationMode : int32_t {
+    // Do not change these values without updating their counterparts
+    // in frameworks/base/media/java/android/media/AudioTrack.java
+    /**
+     * No encapsulation mode for metadata.
+     */
+    NONE              = 0,
+    /**
+     * Elementary stream payload with metadata
+     */
+    ELEMENTARY_STREAM = 1,
+    /**
+     *  Handle-based payload with metadata
+     */
+    HANDLE            = 2,
+};
+
 /**
  * Additional information about the stream passed to hardware decoders.
  */
@@ -918,6 +937,9 @@
     uint32_t bitWidth;
     uint32_t bufferSize;
     AudioUsage usage;
+    AudioEncapsulationMode encapsulationMode;
+    int32_t contentId;
+    int32_t syncId;
 };
 
 /**
diff --git a/audio/common/all-versions/default/HidlUtils.cpp b/audio/common/all-versions/default/HidlUtils.cpp
index 08002c8..a470c9c 100644
--- a/audio/common/all-versions/default/HidlUtils.cpp
+++ b/audio/common/all-versions/default/HidlUtils.cpp
@@ -28,12 +28,13 @@
 namespace CPP_VERSION {
 namespace implementation {
 
-void HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config) {
+status_t HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config) {
     config->sampleRateHz = halConfig.sample_rate;
     config->channelMask = EnumBitfield<AudioChannelMask>(halConfig.channel_mask);
     config->format = AudioFormat(halConfig.format);
-    audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo);
+    status_t status = audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo);
     config->frameCount = halConfig.frame_count;
+    return status;
 }
 
 void HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) {
@@ -106,8 +107,8 @@
     return static_cast<audio_usage_t>(usage);
 }
 
-void HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
-                                        AudioOffloadInfo* offload) {
+status_t HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
+                                            AudioOffloadInfo* offload) {
     offload->sampleRateHz = halOffload.sample_rate;
     offload->channelMask = EnumBitfield<AudioChannelMask>(halOffload.channel_mask);
     offload->format = AudioFormat(halOffload.format);
@@ -119,6 +120,26 @@
     offload->bitWidth = halOffload.bit_width;
     offload->bufferSize = halOffload.offload_buffer_size;
     offload->usage = audioUsageFromHal(halOffload.usage);
+#if MAJOR_VERSION >= 6
+    if (halOffload.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2) {
+        offload->encapsulationMode =
+                static_cast<AudioEncapsulationMode>(halOffload.encapsulation_mode);
+        offload->contentId = halOffload.content_id;
+        offload->syncId = halOffload.sync_id;
+    } else {
+        offload->encapsulationMode = AudioEncapsulationMode::NONE;
+        offload->contentId = 0;
+        offload->syncId = 0;
+    }
+#else
+    // nonzero values here are not compatible with HAL versions below 6.
+    if (halOffload.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2 &&
+        (halOffload.encapsulation_mode != AUDIO_ENCAPSULATION_MODE_NONE ||
+         halOffload.content_id != 0 || halOffload.sync_id != 0)) {
+        return BAD_VALUE;
+    }
+#endif
+    return OK;
 }
 
 void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload,
@@ -135,6 +156,14 @@
     halOffload->bit_width = offload.bitWidth;
     halOffload->offload_buffer_size = offload.bufferSize;
     halOffload->usage = audioUsageToHal(offload.usage);
+#if MAJOR_VERSION >= 6
+    halOffload->encapsulation_mode =
+            static_cast<audio_encapsulation_mode_t>(offload.encapsulationMode);
+    halOffload->content_id = offload.contentId;
+    halOffload->sync_id = offload.syncId;
+#else
+    // offload doesn't contain encapsulationMode, contentId, syncId, so this is OK.
+#endif
 }
 
 void HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig,
diff --git a/audio/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/HidlUtils.h
index 758a7f4..ef6dee3 100644
--- a/audio/common/all-versions/default/HidlUtils.h
+++ b/audio/common/all-versions/default/HidlUtils.h
@@ -35,8 +35,11 @@
 using namespace ::android::hardware::audio::common::CPP_VERSION;
 
 class HidlUtils {
-   public:
-    static void audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config);
+  public:
+    // A failure here indicates a platform config that is incompatible with
+    // the compiled HIDL interface version.
+    static status_t audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config);
+
     static void audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig);
     static void audioGainConfigFromHal(const struct audio_gain_config& halConfig,
                                        AudioGainConfig* config);
@@ -46,8 +49,10 @@
     static void audioGainToHal(const AudioGain& gain, struct audio_gain* halGain);
     static AudioUsage audioUsageFromHal(const audio_usage_t halUsage);
     static audio_usage_t audioUsageToHal(const AudioUsage usage);
-    static void audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
-                                        AudioOffloadInfo* offload);
+    // A failure here indicates a platform offload info that is incompatible with
+    // the compiled HIDL interface version.
+    static status_t audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
+                                            AudioOffloadInfo* offload);
     static void audioOffloadInfoToHal(const AudioOffloadInfo& offload,
                                       audio_offload_info_t* halOffload);
     static void audioPortConfigFromHal(const struct audio_port_config& halConfig,
@@ -58,7 +63,7 @@
                                         const struct audio_port_config* halConfigs,
                                         hidl_vec<AudioPortConfig>* configs);
     static std::unique_ptr<audio_port_config[]> audioPortConfigsToHal(
-        const hidl_vec<AudioPortConfig>& configs);
+            const hidl_vec<AudioPortConfig>& configs);
     static void audioPortFromHal(const struct audio_port& halPort, AudioPort* port);
     static void audioPortToHal(const AudioPort& port, struct audio_port* halPort);
     static void uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid);
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index 47e31c1..6260ba1 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -171,7 +171,8 @@
         streamOut = new StreamOut(this, halStream);
         ++mOpenedStreamsCount;
     }
-    HidlUtils::audioConfigFromHal(halConfig, suggestedConfig);
+    status_t convertStatus = HidlUtils::audioConfigFromHal(halConfig, suggestedConfig);
+    ALOGW_IF(convertStatus != OK, "%s: suggested config with incompatible fields", __func__);
     return {analyzeStatus("open_output_stream", status, {EINVAL} /*ignore*/), streamOut};
 }
 
@@ -198,7 +199,8 @@
         streamIn = new StreamIn(this, halStream);
         ++mOpenedStreamsCount;
     }
-    HidlUtils::audioConfigFromHal(halConfig, suggestedConfig);
+    status_t convertStatus = HidlUtils::audioConfigFromHal(halConfig, suggestedConfig);
+    ALOGW_IF(convertStatus != OK, "%s: suggested config with incompatible fields", __func__);
     return {analyzeStatus("open_input_stream", status, {EINVAL} /*ignore*/), streamIn};
 }
 
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 1a2a764..7a4d72b 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -582,6 +582,38 @@
 }
 #endif
 
+#if MAJOR_VERSION >= 6
+Return<void> StreamOut::getDualMonoMode(getDualMonoMode_cb _hidl_cb) {
+    _hidl_cb(Result::NOT_SUPPORTED, DualMonoMode::OFF);
+    return Void();
+}
+
+Return<Result> StreamOut::setDualMonoMode(DualMonoMode /*mode*/) {
+    return Result::NOT_SUPPORTED;
+}
+
+Return<void> StreamOut::getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) {
+    _hidl_cb(Result::NOT_SUPPORTED, -std::numeric_limits<float>::infinity());
+    return Void();
+}
+
+Return<Result> StreamOut::setAudioDescriptionMixLevel(float /*leveldB*/) {
+    return Result::NOT_SUPPORTED;
+}
+
+Return<void> StreamOut::getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) {
+    _hidl_cb(Result::NOT_SUPPORTED,
+             // Same as AUDIO_PLAYBACK_RATE_INITIALIZER
+             PlaybackRate{1.0f, 1.0f, TimestretchMode::DEFAULT, TimestretchFallbackMode::FAIL});
+    return Void();
+}
+
+Return<Result> StreamOut::setPlaybackRateParameters(const PlaybackRate& /*playbackRate*/) {
+    return Result::NOT_SUPPORTED;
+}
+
+#endif
+
 }  // namespace implementation
 }  // namespace CPP_VERSION
 }  // namespace audio
diff --git a/audio/core/all-versions/default/include/core/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h
index 6334785..5db8626 100644
--- a/audio/core/all-versions/default/include/core/default/StreamOut.h
+++ b/audio/core/all-versions/default/include/core/default/StreamOut.h
@@ -121,6 +121,14 @@
     Return<void> updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
     Return<Result> selectPresentation(int32_t presentationId, int32_t programId) override;
 #endif
+#if MAJOR_VERSION >= 6
+    Return<void> getDualMonoMode(getDualMonoMode_cb _hidl_cb) override;
+    Return<Result> setDualMonoMode(DualMonoMode mode) override;
+    Return<void> getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) override;
+    Return<Result> setAudioDescriptionMixLevel(float leveldB) override;
+    Return<void> getPlaybackRateParameters(getPlaybackRateParameters_cb _hidl_cb) override;
+    Return<Result> setPlaybackRateParameters(const PlaybackRate& playbackRate) override;
+#endif
 
     static Result getPresentationPositionImpl(audio_stream_out_t* stream, uint64_t* frames,
                                               TimeSpec* timeStamp);
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
index 09ef330..9e2a050 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -190,3 +190,64 @@
             hidl_vec<AudioPortConfig>(), hidl_vec<AudioPortConfig>(), returnIn(res, ignored)));
     ASSERT_RESULT(Result::INVALID_ARGUMENTS, res);
 }
+
+using DualMonoModeAccessorHidlTest = AccessorHidlTest<DualMonoMode, OutputStreamTest>;
+TEST_P(DualMonoModeAccessorHidlTest, DualMonoModeTest) {
+    doc::test("Check that dual mono mode can be set and retrieved");
+    testAccessors<OPTIONAL>(&OutputStreamTest::getStream, "dual mono mode",
+                            Initial{DualMonoMode::OFF},
+                            {DualMonoMode::LR, DualMonoMode::LL, DualMonoMode::RR},
+                            &IStreamOut::setDualMonoMode, &IStreamOut::getDualMonoMode);
+}
+
+INSTANTIATE_TEST_CASE_P(DualMonoModeHidl, DualMonoModeAccessorHidlTest,
+                        ::testing::ValuesIn(getOutputDeviceConfigParameters()),
+                        &DeviceConfigParameterToString);
+
+using AudioDescriptionMixLevelHidlTest = AccessorHidlTest<float, OutputStreamTest>;
+TEST_P(AudioDescriptionMixLevelHidlTest, AudioDescriptionMixLevelTest) {
+    doc::test("Check that audio description mix level can be set and retrieved");
+    testAccessors<OPTIONAL>(
+            &OutputStreamTest::getStream, "audio description mix level",
+            Initial{-std::numeric_limits<float>::infinity()}, {-48.0f, -1.0f, 0.0f, 1.0f, 48.0f},
+            &IStreamOut::setAudioDescriptionMixLevel, &IStreamOut::getAudioDescriptionMixLevel,
+            {48.5f, 1000.0f, std::numeric_limits<float>::infinity()});
+}
+
+INSTANTIATE_TEST_CASE_P(AudioDescriptionMixLevelHidl, AudioDescriptionMixLevelHidlTest,
+                        ::testing::ValuesIn(getOutputDeviceConfigParameters()),
+                        &DeviceConfigParameterToString);
+
+using PlaybackRateParametersHidlTest = AccessorHidlTest<PlaybackRate, OutputStreamTest>;
+TEST_P(PlaybackRateParametersHidlTest, PlaybackRateParametersTest) {
+    doc::test("Check that playback rate parameters can be set and retrieved");
+    testAccessors<OPTIONAL>(
+            &OutputStreamTest::getStream, "playback rate parameters",
+            Initial{PlaybackRate{1.0f, 1.0f, TimestretchMode::DEFAULT,
+                                 TimestretchFallbackMode::FAIL}},
+            {// Speed and pitch values in the range from 0.5f to 2.0f must be supported
+             // (see the definition of IStreamOut::setPlaybackRateParameters).
+             PlaybackRate{1.0f, 1.0f, TimestretchMode::DEFAULT, TimestretchFallbackMode::MUTE},
+             PlaybackRate{2.0f, 2.0f, TimestretchMode::DEFAULT, TimestretchFallbackMode::MUTE},
+             PlaybackRate{0.5f, 0.5f, TimestretchMode::DEFAULT, TimestretchFallbackMode::MUTE},
+             // Gross speed / pitch values must not be rejected if the fallback mode is "mute"
+             PlaybackRate{1000.0f, 1000.0f, TimestretchMode::DEFAULT,
+                          TimestretchFallbackMode::MUTE},
+             // Default speed / pitch values must not be rejected in "fail" fallback mode
+             PlaybackRate{1.0f, 1.0f, TimestretchMode::DEFAULT, TimestretchFallbackMode::FAIL},
+             // Same for "voice" mode
+             PlaybackRate{1.0f, 1.0f, TimestretchMode::VOICE, TimestretchFallbackMode::MUTE},
+             PlaybackRate{2.0f, 2.0f, TimestretchMode::VOICE, TimestretchFallbackMode::MUTE},
+             PlaybackRate{0.5f, 0.5f, TimestretchMode::VOICE, TimestretchFallbackMode::MUTE},
+             PlaybackRate{1000.0f, 1000.0f, TimestretchMode::VOICE, TimestretchFallbackMode::MUTE},
+             PlaybackRate{1.0f, 1.0f, TimestretchMode::VOICE, TimestretchFallbackMode::FAIL}},
+            &IStreamOut::setPlaybackRateParameters, &IStreamOut::getPlaybackRateParameters,
+            {PlaybackRate{1000.0f, 1000.0f, TimestretchMode::DEFAULT,
+                          TimestretchFallbackMode::FAIL},
+             PlaybackRate{1000.0f, 1000.0f, TimestretchMode::VOICE,
+                          TimestretchFallbackMode::FAIL}});
+}
+
+INSTANTIATE_TEST_CASE_P(PlaybackRateParametersHidl, PlaybackRateParametersHidlTest,
+                        ::testing::ValuesIn(getOutputDeviceConfigParameters()),
+                        &DeviceConfigParameterToString);
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index d0d39e8..b77aec9 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -140,6 +140,11 @@
 class HidlTest : public HidlTestBase {
   public:
     virtual ~HidlTest() = default;
+    // public access to avoid annoyances when using this method in template classes
+    // derived from test classes
+    sp<IDevice> getDevice() const {
+        return DeviceManager::getInstance().get(getFactoryName(), getDeviceName());
+    }
 
   protected:
     // Factory and device name getters to be overridden in subclasses.
@@ -149,9 +154,6 @@
     sp<IDevicesFactory> getDevicesFactory() const {
         return DevicesFactoryManager::getInstance().get(getFactoryName());
     }
-    sp<IDevice> getDevice() const {
-        return DeviceManager::getInstance().get(getFactoryName(), getDeviceName());
-    }
     bool resetDevice() const {
         return DeviceManager::getInstance().reset(getFactoryName(), getDeviceName());
     }
@@ -419,7 +421,8 @@
         ASSERT_TRUE(getDevice() != nullptr);
     }
 
-  protected:
+    // public access to avoid annoyances when using this method in template classes
+    // derived from test classes
     sp<IPrimaryDevice> getDevice() const {
         return DeviceManager::getInstance().getPrimary(getFactoryName());
     }
@@ -450,15 +453,15 @@
     /** Test a property getter and setter.
      *  The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL.
      */
-    template <Optionality optionality = REQUIRED, class Getter, class Setter>
-    void testAccessors(const string& propertyName, const Initial expectedInitial,
-                       list<Property> valuesToTest, Setter setter, Getter getter,
-                       const vector<Property>& invalidValues = {}) {
+    template <Optionality optionality = REQUIRED, class IUTGetter, class Getter, class Setter>
+    void testAccessors(IUTGetter iutGetter, const string& propertyName,
+                       const Initial expectedInitial, list<Property> valuesToTest, Setter setter,
+                       Getter getter, const vector<Property>& invalidValues = {}) {
         const auto expectedResults = {Result::OK,
                                       optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
 
         Property initialValue = expectedInitial.value;
-        ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, initialValue)));
+        ASSERT_OK(((this->*iutGetter)().get()->*getter)(returnIn(res, initialValue)));
         ASSERT_RESULT(expectedResults, res);
         if (res == Result::OK && expectedInitial.check == REQUIRED) {
             EXPECT_EQ(expectedInitial.value, initialValue);
@@ -469,7 +472,7 @@
         for (Property setValue : valuesToTest) {
             SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
                          testing::PrintToString(setValue));
-            auto ret = (BaseTestClass::getDevice().get()->*setter)(setValue);
+            auto ret = ((this->*iutGetter)().get()->*setter)(setValue);
             ASSERT_RESULT(expectedResults, ret);
             if (ret == Result::NOT_SUPPORTED) {
                 doc::partialTest(propertyName + " setter is not supported");
@@ -477,7 +480,7 @@
             }
             Property getValue;
             // Make sure the getter returns the same value just set
-            ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, getValue)));
+            ASSERT_OK(((this->*iutGetter)().get()->*getter)(returnIn(res, getValue)));
             ASSERT_RESULT(expectedResults, res);
             if (res == Result::NOT_SUPPORTED) {
                 doc::partialTest(propertyName + " getter is not supported");
@@ -490,11 +493,18 @@
             SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
                          testing::PrintToString(invalidValue));
             EXPECT_RESULT(invalidArgsOrNotSupported,
-                          (BaseTestClass::getDevice().get()->*setter)(invalidValue));
+                          ((this->*iutGetter)().get()->*setter)(invalidValue));
         }
 
         // Restore initial value
-        EXPECT_RESULT(expectedResults, (BaseTestClass::getDevice().get()->*setter)(initialValue));
+        EXPECT_RESULT(expectedResults, ((this->*iutGetter)().get()->*setter)(initialValue));
+    }
+    template <Optionality optionality = REQUIRED, class Getter, class Setter>
+    void testAccessors(const string& propertyName, const Initial expectedInitial,
+                       list<Property> valuesToTest, Setter setter, Getter getter,
+                       const vector<Property>& invalidValues = {}) {
+        testAccessors<optionality>(&BaseTestClass::getDevice, propertyName, expectedInitial,
+                                   valuesToTest, setter, getter, invalidValues);
     }
 };
 
@@ -872,6 +882,11 @@
 
 template <class Stream>
 class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
+  public:
+    // public access to avoid annoyances when using this method in template classes
+    // derived from test classes
+    sp<Stream> getStream() const { return stream; }
+
   protected:
     OpenStreamTest() : AudioHidlTestWithDeviceConfigParameter(), helper(stream) {}
     template <class Open>
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..f9bccef 100644
--- a/automotive/evs/1.1/Android.bp
+++ b/automotive/evs/1.1/Android.bp
@@ -10,9 +10,13 @@
         "types.hal",
         "IEvsCamera.hal",
         "IEvsCameraStream.hal",
+        "IEvsDisplay.hal",
         "IEvsEnumerator.hal",
+        "IEvsUltrasonicsArray.hal",
+        "IEvsUltrasonicsArrayStream.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 7752b0e..d604e4f 100644
--- a/automotive/evs/1.1/IEvsEnumerator.hal
+++ b/automotive/evs/1.1/IEvsEnumerator.hal
@@ -17,12 +17,14 @@
 package android.hardware.automotive.evs@1.1;
 
 import IEvsCamera;
+import IEvsDisplay;
+import IEvsUltrasonicsArray;
 import @1.0::IEvsEnumerator;
 import @1.0::EvsResult;
 import android.hardware.camera.device@3.2::Stream;
 
 /**
- * Provides the mechanism for EVS camera discovery
+ * Provides the mechanism for EVS camera and ultrasonics array discovery
  */
 interface IEvsEnumerator extends @1.0::IEvsEnumerator {
     /**
@@ -54,4 +56,54 @@
      * @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);
+
+    /**
+     * Returns a list of all ultrasonics array available to the system.
+     * Will return an empty vector if ultrasonics is not supported.
+     *
+     * @return ultrasonicsArrays A list of ultrasonics available for EVS service.
+     */
+    getUltrasonicsArrayList() generates (vec<UltrasonicsArrayDesc> ultrasonicsArrays);
+
+    /**
+     * Gets the IEvsUltrasonicsArray associated with a ultrasonicsArrayId from a
+     * UltrasonicsDataDesc
+     *
+     * @param  ultrasonicsArrayId  A unique identifier of the ultrasonic array.
+     * @return evsUltrasonicsArray IEvsUltrasonicsArray object associated with a
+     *                             given ultrasonicsArrayId.
+     */
+    openUltrasonicsArray(string ultrasonicsArrayId) generates (
+            IEvsUltrasonicsArray evsUltrasonicsArray);
+
+    /**
+     * Return the specified IEvsUltrasonicsArray interface as no longer in use
+     *
+     * When the IEvsUltrasonicsArray object is no longer required, it must be released.
+     * NOTE: Data streaming must be cleanly stopped before making this call.
+     *
+     * @param  evsUltrasonicsArray EvsUltrasonics array object to be closed.
+     */
+    closeUltrasonicsArray(IEvsUltrasonicsArray evsUltrasonicsArray);
 };
diff --git a/automotive/evs/1.1/IEvsUltrasonicsArray.hal b/automotive/evs/1.1/IEvsUltrasonicsArray.hal
new file mode 100644
index 0000000..ae4f941
--- /dev/null
+++ b/automotive/evs/1.1/IEvsUltrasonicsArray.hal
@@ -0,0 +1,81 @@
+/*
+ * 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::EvsResult;
+import UltrasonicsArrayDesc;
+import UltrasonicsDataFrameDesc;
+import IEvsUltrasonicsArrayStream;
+
+/**
+ * HAL interface for ultrasonics sensor array.
+ */
+interface IEvsUltrasonicsArray {
+   /**
+    * Returns the ultrasonic sensor array information.
+    *
+    * @return  info  The description of this ultrasonic array. This must be the
+    *                same value as reported by IEvsEnumerator::getUltrasonicsArrayList().
+    */
+   getUltrasonicArrayInfo() generates (UltrasonicsArrayDesc info);
+
+   /**
+    * Specifies the depth of the buffer chain the ultrasonic sensors is
+    * asked to support.
+    *
+    * Up to this many data frames may be held concurrently by the client of IEvsUltrasonicsArray.
+    * If this many frames have been delivered to the receiver without being returned
+    * by doneWithFrame, the stream must skip frames until a buffer is returned for reuse.
+    * It is legal for this call to come at any time, even while streams are already running,
+    * in which case buffers should be added or removed from the chain as appropriate.
+    * If no call is made to this entry point, the IEvsUltrasonicsArray must support at least one
+    * data frame by default. More is acceptable.
+    *
+    * @param  bufferCount Number of buffers the client of
+    *                     IEvsUltrasonicsArray may hold concurrently.
+    * @return result      EvsResult::OK is returned if this call is successful.
+    *                     Will return EvsResult::INVALID_ARG on invalid bufferCount.
+    */
+   setMaxFramesInFlight(uint32_t bufferCount) generates (EvsResult result);
+
+   /**
+    * Requests to start the stream.
+    *
+    * @param  stream Implementation of IEvsUltrasonicsArrayStream.
+    * @return result EvsResult::OK is returned if this call is successful. Returns
+    *                EvsResult::STREAM_ALREADY_RUNNING if stream is already running.
+    */
+   startStream(IEvsUltrasonicsArrayStream stream) generates (EvsResult result);
+
+   /**
+    * Requests to stop the delivery of the ultrasonic array data frames.
+    *
+    * Because delivery is asynchronous, frames may continue to arrive for
+    * some time after this call returns. Each must be returned until the
+    * closure of the stream is signaled to the IEvsCameraStream.
+    * This function cannot fail and is ignored if the stream isn't running.
+    */
+   stopStream();
+
+   /**
+    * Notifies the UltrasonicsDataDesc is consumed that was received from
+    * IEvsUltrasonicsArrayStream.
+    *
+    * @param  dataFrameDesc Ultrasonics data descriptor.
+    */
+    doneWithDataFrame(UltrasonicsDataFrameDesc dataFrameDesc);
+};
diff --git a/automotive/evs/1.1/IEvsUltrasonicsArrayStream.hal b/automotive/evs/1.1/IEvsUltrasonicsArrayStream.hal
new file mode 100644
index 0000000..f95209f
--- /dev/null
+++ b/automotive/evs/1.1/IEvsUltrasonicsArrayStream.hal
@@ -0,0 +1,40 @@
+/*
+ * 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 UltrasonicsDataFrameDesc;
+import @1.1::EvsEventDesc;
+
+/**
+ * Implemented on client side to receive asynchronous ultrasonic data
+ * deliveries.
+ */
+interface IEvsUltrasonicsArrayStream {
+   /**
+    * Receives calls from the HAL each time a data frame is ready.
+    *
+    * @param dataFrameDesc Ultrasonic array data frame descriptor.
+    */
+    oneway deliverDataFrame(UltrasonicsDataFrameDesc dataFrameDesc);
+
+    /**
+     * Receives calls from the HAL each time an event happens.
+     *
+     * @param event Event EVS event with possible event information.
+     */
+    oneway notify(EvsEventDesc event);
+};
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
index a7c7b42..d843167 100644
--- a/automotive/evs/1.1/default/Android.bp
+++ b/automotive/evs/1.1/default/Android.bp
@@ -10,6 +10,7 @@
         "EvsDisplay.cpp",
         "ConfigManager.cpp",
         "ConfigManagerUtil.cpp",
+        "EvsUltrasonicsArray.cpp",
     ],
     init_rc: ["android.hardware.automotive.evs@1.1-service.rc"],
 
@@ -17,16 +18,23 @@
         "android.hardware.automotive.evs@1.0",
         "android.hardware.automotive.evs@1.1",
         "android.hardware.camera.device@3.3",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
         "libbase",
         "libbinder",
         "liblog",
         "libhardware",
         "libhidlbase",
+        "libhidlmemory",
         "liblog",
         "libui",
         "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: [
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 cb7403a..117ee7a 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -19,6 +19,7 @@
 #include "EvsEnumerator.h"
 #include "EvsCamera.h"
 #include "EvsDisplay.h"
+#include "EvsUltrasonicsArray.h"
 
 namespace android {
 namespace hardware {
@@ -31,21 +32,45 @@
 // NOTE:  All members values are static so that all clients operate on the same state
 //        That is to say, this is effectively a singleton despite the fact that HIDL
 //        constructs a new instance for each client.
-std::list<EvsEnumerator::CameraRecord>   EvsEnumerator::sCameraList;
-wp<EvsDisplay>                           EvsEnumerator::sActiveDisplay;
-unique_ptr<ConfigManager>                EvsEnumerator::sConfigManager;
+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;
+std::list<EvsEnumerator::UltrasonicsArrayRecord>    EvsEnumerator::sUltrasonicsArrayRecordList;
 
-
-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("/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);
+            }
+        });
+    }
+
+    // Add ultrasonics array desc.
+    sUltrasonicsArrayRecordList.emplace_back(
+            EvsUltrasonicsArray::GetDummyArrayDesc("front_array"));
 }
 
 
@@ -165,7 +190,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 +210,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?
@@ -300,6 +360,102 @@
     return pRecord;
 }
 
+EvsEnumerator::UltrasonicsArrayRecord* EvsEnumerator::findUltrasonicsArrayById(
+        const std::string& ultrasonicsArrayId) {
+    auto recordIt = std::find_if(
+            sUltrasonicsArrayRecordList.begin(), sUltrasonicsArrayRecordList.end(),
+                    [&ultrasonicsArrayId](const UltrasonicsArrayRecord& record) {
+                            return ultrasonicsArrayId == record.desc.ultrasonicsArrayId;});
+
+    return (recordIt != sUltrasonicsArrayRecordList.end()) ? &*recordIt : nullptr;
+}
+
+Return<void> EvsEnumerator::getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) {
+    hidl_vec<UltrasonicsArrayDesc> desc;
+    desc.resize(sUltrasonicsArrayRecordList.size());
+
+    // Copy over desc from sUltrasonicsArrayRecordList.
+    for (auto p = std::make_pair(sUltrasonicsArrayRecordList.begin(), desc.begin());
+            p.first != sUltrasonicsArrayRecordList.end(); p.first++, p.second++) {
+        *p.second = p.first->desc;
+    }
+
+    // Send back the results
+    ALOGD("reporting %zu ultrasonics arrays available", desc.size());
+    _hidl_cb(desc);
+
+    // HIDL convention says we return Void if we sent our result back via callback
+    return Void();
+}
+
+Return<sp<IEvsUltrasonicsArray>> EvsEnumerator::openUltrasonicsArray(
+        const hidl_string& ultrasonicsArrayId) {
+    // Find the named ultrasonic array.
+    UltrasonicsArrayRecord* pRecord = findUltrasonicsArrayById(ultrasonicsArrayId);
+
+    // Is this a recognized ultrasonic array id?
+    if (!pRecord) {
+        ALOGE("Requested ultrasonics array %s not found", ultrasonicsArrayId.c_str());
+        return nullptr;
+    }
+
+    // Has this ultrasonic array already been instantiated by another caller?
+    sp<EvsUltrasonicsArray> pActiveUltrasonicsArray = pRecord->activeInstance.promote();
+    if (pActiveUltrasonicsArray != nullptr) {
+        ALOGW("Killing previous ultrasonics array because of new caller");
+        closeUltrasonicsArray(pActiveUltrasonicsArray);
+    }
+
+    // Construct a ultrasonic array instance for the caller
+    pActiveUltrasonicsArray = EvsUltrasonicsArray::Create(ultrasonicsArrayId.c_str());
+    pRecord->activeInstance = pActiveUltrasonicsArray;
+    if (pActiveUltrasonicsArray == nullptr) {
+        ALOGE("Failed to allocate new EvsUltrasonicsArray object for %s\n",
+              ultrasonicsArrayId.c_str());
+    }
+
+    return pActiveUltrasonicsArray;
+}
+
+Return<void> EvsEnumerator::closeUltrasonicsArray(
+        const sp<IEvsUltrasonicsArray>& pEvsUltrasonicsArray) {
+
+    if (pEvsUltrasonicsArray.get() == nullptr) {
+        ALOGE("Ignoring call to closeUltrasonicsArray with null ultrasonics array");
+        return Void();
+    }
+
+    // Get the ultrasonics array id so we can find it in our list.
+    std::string ultrasonicsArrayId;
+    pEvsUltrasonicsArray->getUltrasonicArrayInfo([&ultrasonicsArrayId](UltrasonicsArrayDesc desc) {
+        ultrasonicsArrayId.assign(desc.ultrasonicsArrayId);
+    });
+
+    // Find the named ultrasonics array
+    UltrasonicsArrayRecord* pRecord = findUltrasonicsArrayById(ultrasonicsArrayId);
+    if (!pRecord) {
+        ALOGE("Asked to close a ultrasonics array whose name isnt not found");
+        return Void();
+    }
+
+    sp<EvsUltrasonicsArray> pActiveUltrasonicsArray = pRecord->activeInstance.promote();
+
+    if (pActiveUltrasonicsArray.get() == nullptr) {
+        ALOGE("Somehow a ultrasonics array is being destroyed when the enumerator didn't know "
+              "one existed");
+    } else if (pActiveUltrasonicsArray != pEvsUltrasonicsArray) {
+        // This can happen if the ultrasonics array was aggressively reopened,
+        // orphaning this previous instance
+        ALOGW("Ignoring close of previously orphaned ultrasonics array - why did a client steal?");
+    } else {
+        // Drop the active ultrasonics array
+        pActiveUltrasonicsArray->forceShutdown();
+        pRecord->activeInstance = nullptr;
+    }
+
+    return Void();
+}
+
 } // namespace implementation
 } // namespace V1_1
 } // namespace evs
diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h
index ca35dc6..d80124b 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.h
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -19,19 +19,23 @@
 
 #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 <android/hardware/automotive/evs/1.1/IEvsUltrasonicsArray.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 {
@@ -43,6 +47,7 @@
 
 class EvsCamera;    // from EvsCamera.h
 class EvsDisplay;   // from EvsDisplay.h
+class EvsUltrasonicsArray;  // from EvsUltrasonicsArray.h
 
 
 class EvsEnumerator : public IEvsEnumerator {
@@ -51,8 +56,8 @@
     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.
@@ -60,9 +65,16 @@
     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;
+    Return<void> getUltrasonicsArrayList(getUltrasonicsArrayList_cb _hidl_cb) override;
+    Return<sp<IEvsUltrasonicsArray>> openUltrasonicsArray(
+            const hidl_string& ultrasonicsArrayId) override;
+    Return<void> closeUltrasonicsArray(
+            const ::android::sp<IEvsUltrasonicsArray>& evsUltrasonicsArray) 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
@@ -75,14 +87,29 @@
         CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; }
     };
 
+    struct UltrasonicsArrayRecord {
+        UltrasonicsArrayDesc desc;
+        wp<EvsUltrasonicsArray> activeInstance;
+
+        UltrasonicsArrayRecord(const UltrasonicsArrayDesc& arrayDesc) : desc(arrayDesc) {};
+    };
+
     static CameraRecord* findCameraById(const std::string& cameraId);
 
     static std::list<CameraRecord>   sCameraList;
 
+    static UltrasonicsArrayRecord* findUltrasonicsArrayById(const std::string& ultrasonicsArrayId);
+
+    static std::list<UltrasonicsArrayRecord> sUltrasonicsArrayRecordList;
+
     // Weak pointer. Object destructs if client dies.
     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/EvsUltrasonicsArray.cpp b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
new file mode 100644
index 0000000..bc69aa4
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
@@ -0,0 +1,551 @@
+/*
+ * 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 "EvsUltrasonicsArray.h"
+
+#include <android-base/logging.h>
+#include <hidlmemory/mapping.h>
+#include <log/log.h>
+#include <time.h>
+#include <utils/SystemClock.h>
+#include <utils/Timers.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+// Arbitrary limit on number of data frames allowed to be allocated
+// Safeguards against unreasonable resource consumption and provides a testable limit
+const unsigned int kMaximumDataFramesInFlight = 100;
+
+const uint32_t kMaxReadingsPerSensor = 5;
+const uint32_t kMaxReceiversCount = 3;
+
+const unsigned int kSharedMemoryMaxSize =
+        kMaxReadingsPerSensor * kMaxReceiversCount * 2 * sizeof(float);
+
+// Target frame rate in frames per second.
+const int kTargetFrameRate = 10;
+
+namespace {
+
+void fillDummyArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
+    arrayDesc.maxReadingsPerSensorCount = kMaxReadingsPerSensor;
+    arrayDesc.maxReceiversCount = kMaxReceiversCount;
+
+    const int kSensorCount = 3;
+    const float kMaxRange = 4000;                // 4 metres.
+    const float kAngleOfMeasurement = 0.261799;  // 15 degrees.
+
+    std::vector<UltrasonicSensor> sensors(kSensorCount);
+
+    // Sensor pointing forward on left side of front bumper.
+    sensors[0].maxRange = kMaxRange;
+    sensors[0].angleOfMeasurement = kAngleOfMeasurement;
+    sensors[0].pose = {{1, 0, 0, 0}, {-1000, 2000, 200}};
+
+    // Sensor pointing forward on center of front bumper.
+    sensors[1].maxRange = kMaxRange;
+    sensors[1].angleOfMeasurement = kAngleOfMeasurement;
+    sensors[1].pose = {{1, 0, 0, 0}, {0, 2000, 200}};
+
+    // Sensor pointing forward on right side of front bumper.
+    sensors[2].maxRange = kMaxRange;
+    sensors[2].angleOfMeasurement = kAngleOfMeasurement;
+    sensors[2].pose = {{1, 0, 0, 0}, {1000, 2000, 200}};
+
+    arrayDesc.sensors = sensors;
+}
+
+// Struct used by SerializeWaveformData().
+struct WaveformData {
+    uint8_t receiverId;
+    std::vector<std::pair<float, float>> readings;
+};
+
+// Serializes data provided in waveformDataList to a shared memory data pointer.
+// TODO(b/149950362): Add a common library for serialiazing and deserializing waveform data.
+void SerializeWaveformData(const std::vector<WaveformData>& waveformDataList, uint8_t* pData) {
+    for (auto& waveformData : waveformDataList) {
+        // Set Id
+        memcpy(pData, &waveformData.receiverId, sizeof(uint8_t));
+        pData += sizeof(uint8_t);
+
+        for (auto& reading : waveformData.readings) {
+            // Set the time of flight.
+            memcpy(pData, &reading.first, sizeof(float));
+            pData += sizeof(float);
+
+            // Set the resonance.
+            memcpy(pData, &reading.second, sizeof(float));
+            pData += sizeof(float);
+        }
+    }
+}
+
+// Fills dataFrameDesc with dummy data.
+bool fillDummyDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
+    dataFrameDesc.timestampNs = elapsedRealtimeNano();
+
+    const std::vector<uint8_t> transmittersIdList = {0};
+    dataFrameDesc.transmittersIdList = transmittersIdList;
+
+    const std::vector<uint8_t> recvIdList = {0, 1, 2};
+    dataFrameDesc.receiversIdList = recvIdList;
+
+    const std::vector<uint32_t> receiversReadingsCountList = {2, 2, 4};
+    dataFrameDesc.receiversReadingsCountList = receiversReadingsCountList;
+
+    const std::vector<WaveformData> waveformDataList = {
+            {recvIdList[0], { {1000, 0.1f}, {2000, 0.8f} }},
+            {recvIdList[1], { {1000, 0.1f}, {2000, 1.0f} }},
+            {recvIdList[2], { {1000, 0.1f}, {2000, 0.2f}, {4000, 0.2f}, {5000, 0.1f} }}
+    };
+
+    if (pIMemory.get() == nullptr) {
+        return false;
+    }
+
+    uint8_t* pData = (uint8_t*)((void*)pIMemory->getPointer());
+
+    pIMemory->update();
+    SerializeWaveformData(waveformDataList, pData);
+    pIMemory->commit();
+
+    return true;
+}
+
+}  // namespace
+
+EvsUltrasonicsArray::EvsUltrasonicsArray(const char* deviceName)
+    : mFramesAllowed(0), mFramesInUse(0), mStreamState(STOPPED) {
+    LOG(DEBUG) << "EvsUltrasonicsArray instantiated";
+
+    // Set up dummy data for description.
+    mArrayDesc.ultrasonicsArrayId = deviceName;
+    fillDummyArrayDesc(mArrayDesc);
+
+    // Assign allocator.
+    mShmemAllocator = IAllocator::getService("ashmem");
+    if (mShmemAllocator.get() == nullptr) {
+        LOG(ERROR) << "SurroundViewHidlTest getService ashmem failed";
+    }
+}
+
+sp<EvsUltrasonicsArray> EvsUltrasonicsArray::Create(const char* deviceName) {
+    return sp<EvsUltrasonicsArray>(new EvsUltrasonicsArray(deviceName));
+}
+
+EvsUltrasonicsArray::~EvsUltrasonicsArray() {
+    LOG(DEBUG) << "EvsUltrasonicsArray being destroyed";
+    forceShutdown();
+}
+
+// This gets called if another caller "steals" ownership of the ultrasonic array.
+void EvsUltrasonicsArray::forceShutdown() {
+    LOG(DEBUG) << "EvsUltrasonicsArray forceShutdown";
+
+    // Make sure our output stream is cleaned up
+    // (It really should be already)
+    stopStream();
+
+    // Claim the lock while we work on internal state
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    // Drop all the data frames we've been using
+    for (auto&& dataFrame : mDataFrames) {
+        if (dataFrame.inUse) {
+            LOG(ERROR) << "Error - releasing data frame despite remote ownership";
+        }
+        dataFrame.sharedMemory.clear();
+    }
+    mDataFrames.clear();
+
+    // Put this object into an unrecoverable error state since somebody else
+    // is going to own the underlying ultrasonic array now
+    mStreamState = DEAD;
+}
+
+UltrasonicsArrayDesc EvsUltrasonicsArray::GetDummyArrayDesc(const char* deviceName) {
+    UltrasonicsArrayDesc ultrasonicsArrayDesc;
+    ultrasonicsArrayDesc.ultrasonicsArrayId = deviceName;
+    fillDummyArrayDesc(ultrasonicsArrayDesc);
+    return ultrasonicsArrayDesc;
+}
+
+Return<void> EvsUltrasonicsArray::getUltrasonicArrayInfo(getUltrasonicArrayInfo_cb _get_info_cb) {
+    LOG(DEBUG) << "EvsUltrasonicsArray getUltrasonicsArrayInfo";
+
+    // Return the description for the get info callback.
+    _get_info_cb(mArrayDesc);
+
+    return Void();
+}
+
+Return<EvsResult> EvsUltrasonicsArray::setMaxFramesInFlight(uint32_t bufferCount) {
+    LOG(DEBUG) << "EvsUltrasonicsArray setMaxFramesInFlight";
+
+    // Lock mutex for performing changes to available frames.
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    // We cannot function without at least one buffer to send data.
+    if (bufferCount < 1) {
+        LOG(ERROR) << "Ignoring setMaxFramesInFlight with less than one buffer requested";
+        return EvsResult::INVALID_ARG;
+    }
+
+    // Update our internal state of buffer count.
+    if (setAvailableFrames_Locked(bufferCount)) {
+        return EvsResult::OK;
+    } else {
+        return EvsResult::BUFFER_NOT_AVAILABLE;
+    }
+
+    return EvsResult::OK;
+}
+
+Return<void> EvsUltrasonicsArray::doneWithDataFrame(const UltrasonicsDataFrameDesc& dataFrameDesc) {
+    LOG(DEBUG) << "EvsUltrasonicsArray doneWithFrame";
+
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    if (dataFrameDesc.dataFrameId >= mDataFrames.size()) {
+        LOG(ERROR) << "ignoring doneWithFrame called with invalid dataFrameId "
+                   << dataFrameDesc.dataFrameId << "(max is " << mDataFrames.size() - 1 << ")";
+        return Void();
+    }
+
+    if (!mDataFrames[dataFrameDesc.dataFrameId].inUse) {
+        LOG(ERROR) << "ignoring doneWithFrame called on frame " << dataFrameDesc.dataFrameId
+                   << "which is already free";
+        return Void();
+    }
+
+    // Mark the frame as available
+    mDataFrames[dataFrameDesc.dataFrameId].inUse = false;
+    mFramesInUse--;
+
+    // If this frame's index is high in the array, try to move it down
+    // to improve locality after mFramesAllowed has been reduced.
+    if (dataFrameDesc.dataFrameId >= mFramesAllowed) {
+        // Find an empty slot lower in the array (which should always exist in this case)
+        for (auto&& dataFrame : mDataFrames) {
+            if (!dataFrame.sharedMemory.IsValid()) {
+                dataFrame.sharedMemory = mDataFrames[dataFrameDesc.dataFrameId].sharedMemory;
+                mDataFrames[dataFrameDesc.dataFrameId].sharedMemory.clear();
+                return Void();
+            }
+        }
+    }
+
+    return Void();
+}
+
+Return<EvsResult> EvsUltrasonicsArray::startStream(
+        const ::android::sp<IEvsUltrasonicsArrayStream>& stream) {
+    LOG(DEBUG) << "EvsUltrasonicsArray startStream";
+
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    if (mStreamState != STOPPED) {
+        LOG(ERROR) << "ignoring startStream call when a stream is already running.";
+        return EvsResult::STREAM_ALREADY_RUNNING;
+    }
+
+    // If the client never indicated otherwise, configure ourselves for a single streaming buffer
+    if (mFramesAllowed < 1) {
+        if (!setAvailableFrames_Locked(1)) {
+            LOG(ERROR)
+                    << "Failed to start stream because we couldn't get shared memory data buffer";
+            return EvsResult::BUFFER_NOT_AVAILABLE;
+        }
+    }
+
+    // Record the user's callback for use when we have a frame ready
+    mStream = stream;
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = std::thread([this]() { generateDataFrames(); });
+
+    return EvsResult::OK;
+}
+
+Return<void> EvsUltrasonicsArray::stopStream() {
+    LOG(DEBUG) << "EvsUltrasonicsArray stopStream";
+
+    bool streamStateStopping = false;
+    {
+        std::lock_guard<std::mutex> lock(mAccessLock);
+        if (mStreamState == RUNNING) {
+            // Tell the GenerateFrames loop we want it to stop
+            mStreamState = STOPPING;
+            streamStateStopping = true;
+        }
+    }
+
+    if (streamStateStopping) {
+        // Block outside the mutex until the "stop" flag has been acknowledged
+        // We won't send any more frames, but the client might still get some already in flight
+        LOG(DEBUG) << "Waiting for stream thread to end...";
+        mCaptureThread.join();
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(mAccessLock);
+        mStreamState = STOPPED;
+        mStream = nullptr;
+        LOG(DEBUG) << "Stream marked STOPPED.";
+    }
+
+    return Void();
+}
+
+bool EvsUltrasonicsArray::setAvailableFrames_Locked(unsigned bufferCount) {
+    if (bufferCount < 1) {
+        LOG(ERROR) << "Ignoring request to set buffer count to zero";
+        return false;
+    }
+    if (bufferCount > kMaximumDataFramesInFlight) {
+        LOG(ERROR) << "Rejecting buffer request in excess of internal limit";
+        return false;
+    }
+
+    // Is an increase required?
+    if (mFramesAllowed < bufferCount) {
+        // An increase is required
+        unsigned needed = bufferCount - mFramesAllowed;
+        LOG(INFO) << "Number of data frame buffers to add: " << needed;
+
+        unsigned added = increaseAvailableFrames_Locked(needed);
+        if (added != needed) {
+            // If we didn't add all the frames we needed, then roll back to the previous state
+            LOG(ERROR) << "Rolling back to previous frame queue size";
+            decreaseAvailableFrames_Locked(added);
+            return false;
+        }
+    } else if (mFramesAllowed > bufferCount) {
+        // A decrease is required
+        unsigned framesToRelease = mFramesAllowed - bufferCount;
+        LOG(INFO) << "Number of data frame buffers to reduce: " << framesToRelease;
+
+        unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
+        if (released != framesToRelease) {
+            // This shouldn't happen with a properly behaving client because the client
+            // should only make this call after returning sufficient outstanding buffers
+            // to allow a clean resize.
+            LOG(ERROR) << "Buffer queue shrink failed -- too many buffers currently in use?";
+        }
+    }
+
+    return true;
+}
+
+EvsUltrasonicsArray::SharedMemory EvsUltrasonicsArray::allocateAndMapSharedMemory() {
+    SharedMemory sharedMemory;
+
+    // Check shared memory allocator is valid.
+    if (mShmemAllocator.get() == nullptr) {
+        LOG(ERROR) << "Shared memory allocator not initialized.";
+        return SharedMemory();
+    }
+
+    // Allocate memory.
+    bool allocateSuccess = false;
+    Return<void> result = mShmemAllocator->allocate(kSharedMemoryMaxSize,
+                                                    [&](bool success, const hidl_memory& hidlMem) {
+                                                        if (!success) {
+                                                            return;
+                                                        }
+                                                        allocateSuccess = success;
+                                                        sharedMemory.hidlMemory = hidlMem;
+                                                    });
+
+    // Check result of allocated memory.
+    if (!result.isOk() || !allocateSuccess) {
+        LOG(ERROR) << "Shared memory allocation failed.";
+        return SharedMemory();
+    }
+
+    // Map shared memory.
+    sharedMemory.pIMemory = mapMemory(sharedMemory.hidlMemory);
+    if (sharedMemory.pIMemory.get() == nullptr) {
+        LOG(ERROR) << "Shared memory mapping failed.";
+        return SharedMemory();
+    }
+
+    // Return success.
+    return sharedMemory;
+}
+
+unsigned EvsUltrasonicsArray::increaseAvailableFrames_Locked(unsigned numToAdd) {
+    unsigned added = 0;
+
+    while (added < numToAdd) {
+        SharedMemory sharedMemory = allocateAndMapSharedMemory();
+
+        // If allocate and map fails, break.
+        if (!sharedMemory.IsValid()) {
+            break;
+        }
+
+        // Find a place to store the new buffer
+        bool stored = false;
+        for (auto&& dataFrame : mDataFrames) {
+            if (!dataFrame.sharedMemory.IsValid()) {
+                // Use this existing entry
+                dataFrame.sharedMemory = sharedMemory;
+                dataFrame.inUse = false;
+                stored = true;
+                break;
+            }
+        }
+
+        if (!stored) {
+            // Add a BufferRecord wrapping this handle to our set of available buffers
+            mDataFrames.emplace_back(sharedMemory);
+        }
+
+        mFramesAllowed++;
+        added++;
+    }
+
+    return added;
+}
+
+unsigned EvsUltrasonicsArray::decreaseAvailableFrames_Locked(unsigned numToRemove) {
+    unsigned removed = 0;
+
+    for (auto&& dataFrame : mDataFrames) {
+        // Is this record not in use, but holding a buffer that we can free?
+        if (!dataFrame.inUse && dataFrame.sharedMemory.IsValid()) {
+            // Release buffer and update the record so we can recognize it as "empty"
+            dataFrame.sharedMemory.clear();
+
+            mFramesAllowed--;
+            removed++;
+
+            if (removed == numToRemove) {
+                break;
+            }
+        }
+    }
+
+    return removed;
+}
+
+// This is the asynchronous data frame generation thread that runs in parallel with the
+// main serving thread. There is one for each active ultrasonic array instance.
+void EvsUltrasonicsArray::generateDataFrames() {
+    LOG(DEBUG) << "Data frame generation loop started";
+
+    unsigned idx = 0;
+
+    while (true) {
+        bool timeForFrame = false;
+
+        nsecs_t startTime = elapsedRealtimeNano();
+
+        // Lock scope for updating shared state
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (mStreamState != RUNNING) {
+                // Break out of our main thread loop
+                break;
+            }
+
+            // Are we allowed to issue another buffer?
+            if (mFramesInUse >= mFramesAllowed) {
+                // Can't do anything right now -- skip this frame
+                LOG(WARNING) << "Skipped a frame because too many are in flight";
+            } else {
+                // Identify an available buffer to fill
+                for (idx = 0; idx < mDataFrames.size(); idx++) {
+                    if (!mDataFrames[idx].inUse && mDataFrames[idx].sharedMemory.IsValid()) {
+                        // Found an available record, so stop looking
+                        break;
+                    }
+                }
+                if (idx >= mDataFrames.size()) {
+                    // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
+                    LOG(ERROR) << "Failed to find an available buffer slot";
+                } else {
+                    // We're going to make the frame busy
+                    mDataFrames[idx].inUse = true;
+                    mFramesInUse++;
+                    timeForFrame = true;
+                }
+            }
+        }
+
+        if (timeForFrame) {
+            // Assemble the buffer description we'll transmit below
+            UltrasonicsDataFrameDesc dummyDataFrameDesc;
+            dummyDataFrameDesc.dataFrameId = idx;
+            dummyDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
+
+            // Fill dummy waveform data.
+            fillDummyDataFrame(dummyDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
+
+            // Issue the (asynchronous) callback to the client -- can't be holding the lock
+            auto result = mStream->deliverDataFrame(dummyDataFrameDesc);
+            if (result.isOk()) {
+                LOG(DEBUG) << "Delivered data frame id: " << dummyDataFrameDesc.dataFrameId;
+            } else {
+                // This can happen if the client dies and is likely unrecoverable.
+                // To avoid consuming resources generating failing calls, we stop sending
+                // frames.  Note, however, that the stream remains in the "STREAMING" state
+                // until cleaned up on the main thread.
+                LOG(ERROR) << "Frame delivery call failed in the transport layer.";
+
+                // Since we didn't actually deliver it, mark the frame as available
+                std::lock_guard<std::mutex> lock(mAccessLock);
+                mDataFrames[idx].inUse = false;
+                mFramesInUse--;
+
+                break;
+            }
+        }
+
+        // Sleep to generate frames at kTargetFrameRate.
+        static const nsecs_t kTargetFrameTimeUs = 1000 * 1000 / kTargetFrameRate;
+        const nsecs_t now = elapsedRealtimeNano();
+        const nsecs_t workTimeUs = (now - startTime) / 1000;
+        const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs;
+        if (sleepDurationUs > 0) {
+            usleep(sleepDurationUs);
+        }
+    }
+
+    // If we've been asked to stop, send an event to signal the actual end of stream
+    EvsEventDesc event;
+    event.aType = EvsEventType::STREAM_STOPPED;
+    auto result = mStream->notify(event);
+    if (!result.isOk()) {
+        LOG(ERROR) << "Error delivering end of stream marker";
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.h b/automotive/evs/1.1/default/EvsUltrasonicsArray.h
new file mode 100644
index 0000000..7a41012
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSULTRASONICSARRAY_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSULTRASONICSARRAY_H
+
+#include <thread>
+#include <utility>
+
+#include <android-base/macros.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <utils/threads.h>
+
+#include <android/hardware/automotive/evs/1.1/IEvsUltrasonicsArray.h>
+#include <android/hardware/automotive/evs/1.1/IEvsUltrasonicsArrayStream.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+using ::android::hardware::hidl_memory;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray;
+using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream;
+using ::android::hardware::automotive::evs::V1_1::UltrasonicsArrayDesc;
+using ::android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+class EvsUltrasonicsArray : public IEvsUltrasonicsArray {
+  public:
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray follow.
+    Return<void> getUltrasonicArrayInfo(getUltrasonicArrayInfo_cb _get_info_cb) override;
+    Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+    Return<void> doneWithDataFrame(const UltrasonicsDataFrameDesc& dataFrameDesc) override;
+    Return<EvsResult> startStream(const ::android::sp<IEvsUltrasonicsArrayStream>& stream) override;
+    Return<void> stopStream() override;
+
+    // Factory function to create a array.
+    static sp<EvsUltrasonicsArray> Create(const char* deviceName);
+
+    // Returns a ultrasonics array descriptor filled with sample data.
+    static UltrasonicsArrayDesc GetDummyArrayDesc(const char* id);
+
+    DISALLOW_COPY_AND_ASSIGN(EvsUltrasonicsArray);
+    virtual ~EvsUltrasonicsArray() override;
+    void forceShutdown();  // This gets called if another caller "steals" ownership
+
+  private:
+    // Structure holding the hidl memory struct and the interface to a shared memory.
+    struct SharedMemory {
+        hidl_memory hidlMemory;
+        sp<IMemory> pIMemory;
+
+        SharedMemory() : hidlMemory(hidl_memory()), pIMemory(nullptr){};
+
+        SharedMemory(hidl_memory hidlMem, sp<IMemory> pIMem)
+            : hidlMemory(hidlMem), pIMemory(pIMem) {}
+
+        bool IsValid() { return (pIMemory.get() != nullptr && hidlMemory.valid()); }
+
+        void clear() {
+            hidlMemory = hidl_memory();
+            pIMemory.clear();
+        }
+    };
+
+    // Struct for a data frame record.
+    struct DataFrameRecord {
+        SharedMemory sharedMemory;
+        bool inUse;
+        explicit DataFrameRecord(SharedMemory shMem) : sharedMemory(shMem), inUse(false){};
+    };
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+
+    EvsUltrasonicsArray(const char* deviceName);
+
+    // These three functions are expected to be called while mAccessLock is held
+    bool setAvailableFrames_Locked(unsigned bufferCount);
+    unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
+    unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
+
+    void generateDataFrames();
+
+    SharedMemory allocateAndMapSharedMemory();
+
+    UltrasonicsArrayDesc mArrayDesc = {};  // The properties of this ultrasonic array.
+
+    std::thread mCaptureThread;  // The thread we'll use to synthesize frames
+
+    sp<IEvsUltrasonicsArrayStream> mStream = nullptr;  // The callback used to deliver each frame
+
+    sp<IAllocator> mShmemAllocator = nullptr;  // Shared memory allocator.
+
+    std::mutex mAccessLock;
+    std::vector<DataFrameRecord> mDataFrames GUARDED_BY(mAccessLock);  // Shared memory buffers.
+    unsigned mFramesAllowed GUARDED_BY(mAccessLock);  // How many buffers are we currently using.
+    unsigned mFramesInUse GUARDED_BY(mAccessLock);  // How many buffers are currently outstanding.
+
+    StreamStateValues mStreamState GUARDED_BY(mAccessLock);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace evs
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSULTRASONICSARRAY_H
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 aafdb70..b34e7e7 100644
--- a/automotive/evs/1.1/types.hal
+++ b/automotive/evs/1.1/types.hal
@@ -177,3 +177,194 @@
      */
     ABSOLUTE_ZOOM,
 };
+
+/**
+ * Structure identifies and describes an ultrasonics array in the car.
+ *
+ * A ultrasonics array represents a group of ultrasonic sensors within the
+ * car. These may be sensors that are physically connected to the same hardware
+ * control unit or represent a logical group of sensors like front and back.
+ * The HAL is responsible for filling out this structure for each Ultrasonics
+ * Array.
+ */
+struct UltrasonicsArrayDesc {
+    /**
+     * Unique identifier for the ultrasonic array. This may be a path or name of the
+     * physical control device or a string identifying a logical group of sensors forming an array
+     * such as "front_array" and "back_array".
+     */
+    string ultrasonicsArrayId;
+
+    /**
+     * Maximum number of readings (points on waveform) provided per sensor in
+     * each data frame. Used by client to pre-allocate required memory buffer for
+     * incoming data.
+     */
+    uint32_t maxReadingsPerSensorCount;
+
+    /**
+     * Maximum number of receiver sensors in a data frame. Must be between 1
+     * and sensorCount. Used by client to pre-allocate required memory buffer for
+     * incoming data.
+     */
+    uint32_t maxReceiversCount;
+
+    /**
+     * The order of sensors specified should preferably be in clockwise order
+     * around the car, starting from front left-most sensor.
+     */
+    vec<UltrasonicSensor> sensors;
+};
+
+/**
+ * Structure for rotation expressed as quaternions.
+ * Convention used: Unit quaternion with hamilton convention.
+ */
+struct RotationQuat {
+    float x;
+    float y;
+    float z;
+    float w;
+};
+
+/** Structure for translation with x, y and z units. */
+struct Translation {
+    float x;
+    float y;
+    float z;
+};
+
+/**
+ * Provides the orientation and location of a car sensor relative to the android automotive
+ * coordinate system:
+ * https://source.android.com/devices/sensors/sensor-types#auto_axes
+ * The sensor pose defines the transformation to be applied to the android automotive axes to
+ * obtain the sensor local axes.
+ * The pose consists of rotation, (specified as a quaternions) and translation
+ * (vector with x, y, z).
+ * This rotation and translation applied to the sensor data in the sensor's local coordinate
+ * system transform the data to the automotive coordinate system.
+ * i.e   Pcar =  ( Rot * Psensor ) + Trans
+ * Here Pcar is a point in automotive coordinate system and Psensor is a point in the sensor's
+ * coordinate system.
+ * Example:
+ * For a sensor on the front bumper and on the left corner of the car with its X axis pointing to
+ * the front, the sensor is located at (-2, 4, 0) meters w.r.t android automotive axes and the
+ * sensor local axes has a rotation of 90 degrees counter-clockwise w.r.t android automotive axes
+ * when viewing the car from top on the +Z axis side:
+ *
+ *      ↑X sensor
+ *    Y←∘______
+ *      |      |  front
+ *      | car  |
+ *      |  ↑Y  |
+ *      |  ∘→X |  rear
+ *      |______|
+ *
+ * For this example the rotation and translation will be:
+ * Rotation = + 90 degrees around Z axis = (0.7071, 0, 0, 0.7071) as a unit quaternion.
+ * Translation = (-2, 4, 0) in meters = (-2000, 4000, 0) in milli-meters.
+ * Note: Every sensor type must specify its own pose.
+ */
+struct SensorPose {
+    /**
+     * Rotation part of the sensor pose, expressed as a unit quaternion.
+     */
+    RotationQuat rotation;
+
+    /**
+     * Translation part of the sensor pose, in (x, y, z) format with milli-meter units.
+     */
+    Translation translation;
+};
+
+/**
+ * Structure that contains all information of an ultrasonic sensor.
+ */
+struct UltrasonicSensor {
+    /**
+     * Pose provides the orientation and location of the ultrasonic sensor within the car.
+     * The +Y axis points along the center of the beam spread the X axis to the right and the Z
+     * axis in the up direction.
+     */
+    SensorPose pose;
+
+    /**
+     * Maximum range of the sensor in milli-metres.
+     */
+    float maxRange;
+
+    /**
+     * Half-angle of the angle of measurement of the sensor, relative to the
+     * sensor’s x axis, in radians.
+     */
+    float angleOfMeasurement;
+};
+
+/**
+ * Structure that describes the data frame received from an ultrasonics array.
+ *
+ * Each data frame returned consists of received waveform signals from a subset
+ * of sensors in an array as indicated by the receiversIdList. The signal is
+ * transmitted at a particular time instant indicated by timestampNs from a
+ * subset of sensors in the array as provided in the transmittersIdList.
+ */
+struct UltrasonicsDataFrameDesc {
+    /**
+     * Timestamp of the start of the transmit signal for this data frame.
+     * Timestamp unit is nanoseconds and is obtained from android elapsed realtime clock which is
+     * the time since system was booted and includes deep sleep.
+     * timeOfFlight readings are future-deltas to this timestamp.
+     */
+    uint64_t timestampNs;
+
+    /**
+     * Identifier of data frame. Used by implementation for managing multiple frames in flight.
+     */
+    uint32_t dataFrameId;
+
+    /**
+     * List of indexes of sensors in range [0, sensorCount - 1] that
+     * transmitted the signal for this data frame.
+     */
+    vec<uint8_t> transmittersIdList;
+
+    /**
+     * List of indexes of sensors in range [0, sensorCount - 1] that received
+     * the signal. The order of ids must match the order of the waveforms in the
+     * waveformsData.
+     * Size of list is upper bound by maxReceiversCount.
+     */
+    vec<uint8_t> receiversIdList;
+
+    /**
+     * List of the number of readings corresponding to each ultrasonics sensor in
+     * the receiversIdList. Order of the readings count must match the order in
+     * receiversIdList.
+     * Size of list is upper bound by maxReadingsPerSensorCount.
+     */
+    vec<uint32_t> receiversReadingsCountList;
+
+    /**
+     * Shared memory object containing the waveforms data. Contains one waveform
+     * for each sensor specified in receiversIdList, in order.
+     * Each waveform is represented by a number of readings, which are sample
+     * points on the waveform. The number of readings for each waveform is as
+     * specified in the receiversReadingsCountList.
+     * Each reading is a pair of time Of flight and resonance.
+     * Time of flight (float): Time between transmit and receive signal in nanoseconds.
+     * Resonance (float): Resonance at time on waveform in range [0.0, 1.0].
+     *
+     * The structure of shared memory (example with 2 waveforms, each with 2 readings):
+     *
+     * Byte: |   0    |  1-4  |  5-8  | 9-12  | 13-16 ||   17   |  18-21 | 22-25  | 26-29 | 30-33 |
+     * Data: | RecId1 | TOF1  | RES1  | TOF2  | RES2  || RecId2 |  TOF1  |  RES1  | TOF2  | RES2  |
+     *       |              Waveform1                 ||             Waveform2                    |
+     * Here:
+     * RecId : Receiver's Id. Order matches the receiversIdList, type uint8_t
+     * TOF : Time of flight, type float (4 bytes)
+     * RES : Resonance, type float (4 bytes)
+     * Note: All readings and waveforms are contigious with no padding.
+     */
+    memory waveformsData;
+};
diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp
index 4753933..086a199 100644
--- a/automotive/evs/1.1/vts/functional/Android.bp
+++ b/automotive/evs/1.1/vts/functional/Android.bp
@@ -18,12 +18,16 @@
     name: "VtsHalEvsV1_1TargetTest",
     srcs: [
         "FrameHandler.cpp",
+        "FrameHandlerUltrasonics.cpp",
         "VtsHalEvsV1_1TargetTest.cpp",
     ],
     defaults: ["VtsHalTargetTestDefaults"],
     shared_libs: [
         "libui",
         "libcamera_metadata",
+        "libhidlmemory",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
     ],
     static_libs: [
         "android.hardware.automotive.evs@1.0",
@@ -34,7 +38,7 @@
         "android.hardware.graphics.common@1.2",
         "android.hardware.camera.device@3.2",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["vts-core"],
     cflags: [
         "-O0",
         "-g",
diff --git a/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.cpp b/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.cpp
new file mode 100644
index 0000000..22522ce
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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 "FrameHandlerUltrasonics.h"
+
+#include <android-base/logging.h>
+#include <hidlmemory/mapping.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::Return;
+using ::android::sp;
+
+using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream;
+using ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray;
+using ::android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc;
+using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
+using ::android::hardware::automotive::evs::V1_1::EvsEventType;
+
+FrameHandlerUltrasonics::FrameHandlerUltrasonics(sp<IEvsUltrasonicsArray> pEvsUltrasonicsArray) :
+    mEvsUltrasonicsArray(pEvsUltrasonicsArray), mReceiveFramesCount(0) {
+    // Nothing but member initialization
+}
+
+Return<void> FrameHandlerUltrasonics::notify(const EvsEventDesc& evsEvent) {
+    switch (evsEvent.aType) {
+        case EvsEventType::STREAM_STARTED:
+        case EvsEventType::STREAM_STOPPED:
+        case EvsEventType::FRAME_DROPPED:
+        case EvsEventType::TIMEOUT:
+            mReceivedEvents.emplace_back(evsEvent);
+            break;
+        default:
+            LOG(ERROR) << "Received unexpected event";
+    }
+
+    return android::hardware::Void();
+}
+
+// Struct used by SerializeWaveformData().
+struct WaveformData {
+    uint8_t receiverId;
+    std::vector<std::pair<float, float>> readings;
+};
+
+// De-serializes shared memory to vector of WaveformData.
+// TODO(b/149950362): Add a common library for serialiazing and deserializing waveform data.
+std::vector<WaveformData> DeSerializeWaveformData(std::vector<uint32_t> recvReadingsCountList,
+        uint8_t* pData) {
+    std::vector<WaveformData> waveformDataList(recvReadingsCountList.size());
+
+    for (int i = 0; i < waveformDataList.size(); i++) {
+        // Set Id
+        memcpy(&waveformDataList[i].receiverId, pData, sizeof(uint8_t));
+        pData += sizeof(uint8_t);
+
+        waveformDataList[i].readings.resize(recvReadingsCountList[i]);
+
+        for (auto& reading : waveformDataList[i].readings) {
+            // Set the time of flight.
+            memcpy(&reading.first, pData, sizeof(float));
+            pData += sizeof(float);
+
+            // Set the resonance.
+            memcpy(&reading.second, pData, sizeof(float));
+            pData += sizeof(float);
+        }
+    }
+    return waveformDataList;
+}
+
+bool DataFrameValidator(const UltrasonicsDataFrameDesc& dataFrameDesc) {
+
+    if (dataFrameDesc.receiversIdList.size() != dataFrameDesc.receiversReadingsCountList.size()) {
+        LOG(ERROR) << "Size mismatch of receiversIdList and receiversReadingsCountList";
+        return false;
+    }
+
+    if(!dataFrameDesc.waveformsData.valid()) {
+        LOG(ERROR) << "Data frame does not valid hidl memory";
+        return false;
+    }
+
+    // Check total bytes from dataFrameDesc are within the shared memory size.
+    int totalWaveformDataBytesSize = 0;
+    for (int i = 0; i < dataFrameDesc.receiversIdList.size(); i++) {
+        totalWaveformDataBytesSize = 1 + (4 * 2 * dataFrameDesc.receiversReadingsCountList[i]);
+    }
+    if (totalWaveformDataBytesSize > dataFrameDesc.waveformsData.size()) {
+        LOG(ERROR) << "Total waveform data bytes in desc exceed shared memory size";
+        return false;
+    }
+
+    sp<IMemory> pIMemory = mapMemory(dataFrameDesc.waveformsData);
+    if(pIMemory.get() == nullptr) {
+        LOG(ERROR) << "Failed to map hidl memory";
+        return false;
+    }
+
+    uint8_t* pData = (uint8_t*)((void*)pIMemory->getPointer());
+    if(pData == nullptr) {
+        LOG(ERROR) << "Failed getPointer from mapped shared memory";
+        return false;
+    }
+
+    const std::vector<WaveformData> waveformDataList = DeSerializeWaveformData(
+            dataFrameDesc.receiversReadingsCountList, pData);
+
+    // Verify the waveforms data.
+    for(int i = 0; i < waveformDataList.size(); i++) {
+        if (waveformDataList[i].receiverId != dataFrameDesc.receiversIdList[i]) {
+            LOG(ERROR) << "Receiver Id mismatch";
+            return false;
+        }
+        for(auto& reading : waveformDataList[i].readings) {
+            if (reading.second < 0.0f || reading.second > 1.0f) {
+                LOG(ERROR) << "Resonance reading is not in range [0, 1]";
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+Return<void> FrameHandlerUltrasonics::deliverDataFrame(
+        const UltrasonicsDataFrameDesc& dataFrameDesc) {
+    LOG(DEBUG) << "FrameHandlerUltrasonics::receiveFrames";
+
+    mReceiveFramesCount++;
+    mLastReceivedFrames = dataFrameDesc;
+
+    if(!DataFrameValidator(dataFrameDesc)) {
+        mAllFramesValid = false;
+    }
+
+    // Send done with data frame.
+    mEvsUltrasonicsArray->doneWithDataFrame(dataFrameDesc);
+
+    return android::hardware::Void();
+}
+
+bool FrameHandlerUltrasonics::checkEventReceived(EvsEventDesc evsEvent) {
+    LOG(DEBUG) << "FrameHandlerUltrasonics::checkEventReceived";
+    int size = mReceivedEvents.size(); // work around
+    LOG(DEBUG) << "Received event number: " << size;
+    auto iter = find(mReceivedEvents.begin(), mReceivedEvents.end(), evsEvent);
+    return iter != mReceivedEvents.end();
+}
+
+int FrameHandlerUltrasonics::getReceiveFramesCount() {
+    return mReceiveFramesCount;
+}
+
+bool FrameHandlerUltrasonics::areAllFramesValid() {
+    return mAllFramesValid;
+}
diff --git a/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.h b/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.h
new file mode 100644
index 0000000..1fc2143
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/FrameHandlerUltrasonics.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAME_HANDLER_ULTRASONICS_H
+#define FRAME_HANDLER_ULTRASONICS_H
+
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android/hardware/automotive/evs/1.1/IEvsUltrasonicsArrayStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsUltrasonicsArray.h>
+
+#include <vector>
+
+class FrameHandlerUltrasonics : public
+        android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream {
+public:
+    FrameHandlerUltrasonics(
+            android::sp<android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray>
+            pEvsUltrasonicsArray);
+
+    // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArrayStream
+    android::hardware::Return<void> notify(
+            const android::hardware::automotive::evs::V1_1::EvsEventDesc& evsEvent) override;
+    android::hardware::Return<void> deliverDataFrame(
+            const android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc&
+             dataFrameDesc) override;
+
+    bool checkEventReceived(android::hardware::automotive::evs::V1_1::EvsEventDesc evsEvent);
+    int getReceiveFramesCount();
+    bool areAllFramesValid();
+
+private:
+    android::sp<android::hardware::automotive::evs::V1_1::IEvsUltrasonicsArray>
+            mEvsUltrasonicsArray;
+    android::hardware::automotive::evs::V1_1::UltrasonicsDataFrameDesc mLastReceivedFrames;
+    std::vector<android::hardware::automotive::evs::V1_1::EvsEventDesc> mReceivedEvents;
+    int mReceiveFramesCount;
+    bool mAllFramesValid = true;
+};
+
+#endif //FRAME_HANDLER_ULTRASONICS_H
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 1a62245..cde8048 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -17,15 +17,6 @@
 #define LOG_TAG "VtsHalEvsTest"
 
 
-// Note:  We have't got a great way to indicate which target
-// should be tested, so we'll leave the interface served by the
-// default (mock) EVS driver here for easy reference.  All
-// actual EVS drivers should serve on the EvsEnumeratorHw name,
-// however, so the code is checked in that way.
-//const static char kEnumeratorName[]  = "EvsEnumeratorHw-Mock";
-const static char kEnumeratorName[]  = "EvsEnumeratorHw";
-
-
 // These values are called out in the EVS design doc (as of Mar 8, 2017)
 static const int kMaxStreamStartMilliseconds = 500;
 static const int kMinimumFramesPerSecond = 10;
@@ -37,6 +28,7 @@
 
 
 #include "FrameHandler.h"
+#include "FrameHandlerUltrasonics.h"
 
 #include <cstdio>
 #include <cstring>
@@ -54,14 +46,18 @@
 #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>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 using namespace ::android::hardware::automotive::evs::V1_1;
+using namespace std::chrono_literals;
 
 using ::android::hardware::Return;
 using ::android::hardware::Void;
@@ -76,6 +72,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
@@ -92,29 +90,13 @@
 } RawStreamConfig;
 
 
-// Test environment for Evs HIDL HAL.
-class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static EvsHidlEnvironment* Instance() {
-        static EvsHidlEnvironment* instance = new EvsHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IEvsEnumerator>(); }
-
-   private:
-    EvsHidlEnvironment() {}
-};
-
 // The main test class for EVS
-class EvsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class EvsHidlTest : public ::testing::TestWithParam<std::string> {
 public:
     virtual void SetUp() override {
         // Make sure we can connect to the enumerator
-        string service_name =
-            EvsHidlEnvironment::Instance()->getServiceName<IEvsEnumerator>(kEnumeratorName);
-        pEnumerator = getService<IEvsEnumerator>(service_name);
+        std::string service_name = GetParam();
+        pEnumerator = IEvsEnumerator::getService(service_name);
         ASSERT_NE(pEnumerator.get(), nullptr);
 
         mIsHwModule = pEnumerator->isHardware();
@@ -147,9 +129,21 @@
                 }
             }
         );
+    }
 
-        // We insist on at least one camera for EVS to pass any camera tests
-        ASSERT_GE(cameraInfo.size(), 1u);
+    void loadUltrasonicsArrayList() {
+        // SetUp() must run first!
+        assert(pEnumerator != nullptr);
+
+        // Get the ultrasonics array list
+        pEnumerator->getUltrasonicsArrayList([this](hidl_vec<UltrasonicsArrayDesc> ultraList) {
+            ALOGI("Ultrasonics array list callback received %zu arrays", ultraList.size());
+            ultrasonicsArraysInfo.reserve(ultraList.size());
+            for (auto&& ultraArray : ultraList) {
+                ALOGI("Found ultrasonics array %s", ultraArray.ultrasonicsArrayId.c_str());
+                ultrasonicsArraysInfo.push_back(ultraArray);
+            }
+        });
     }
 
     bool isLogicalCamera(const camera_metadata_t *metadata) {
@@ -236,6 +230,11 @@
                                                    // is HW module implementation.
     std::deque<wp<IEvsCamera_1_1>>  activeCameras; // A list of active camera handles that are
                                                    // needed to be cleaned up.
+    std::vector<UltrasonicsArrayDesc>
+            ultrasonicsArraysInfo;                           // Empty unless/until
+                                                             // loadUltrasonicsArrayList() is called
+    std::deque<wp<IEvsCamera_1_1>> activeUltrasonicsArrays;  // A list of active ultrasonic array
+                                                             // handles that are to be cleaned up.
 };
 
 
@@ -247,7 +246,7 @@
  * Opens each camera reported by the enumerator and then explicitly closes it via a
  * call to closeCamera.  Then repeats the test to ensure all cameras can be reopened.
  */
-TEST_F(EvsHidlTest, CameraOpenClean) {
+TEST_P(EvsHidlTest, CameraOpenClean) {
     ALOGI("Starting CameraOpenClean test");
 
     // Get the camera list
@@ -292,6 +291,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);
         }
@@ -305,7 +315,7 @@
  * call.  This ensures that the intended "aggressive open" behavior works.  This is necessary for
  * the system to be tolerant of shutdown/restart race conditions.
  */
-TEST_F(EvsHidlTest, CameraOpenAggressive) {
+TEST_P(EvsHidlTest, CameraOpenAggressive) {
     ALOGI("Starting CameraOpenAggressive test");
 
     // Get the camera list
@@ -382,7 +392,7 @@
  * CameraStreamPerformance:
  * Measure and qualify the stream start up time and streaming frame rate of each reported camera
  */
-TEST_F(EvsHidlTest, CameraStreamPerformance) {
+TEST_P(EvsHidlTest, CameraStreamPerformance) {
     ALOGI("Starting CameraStreamPerformance test");
 
     // Get the camera list
@@ -472,7 +482,7 @@
  * Ensure the camera implementation behaves properly when the client holds onto buffers for more
  * than one frame time.  The camera must cleanly skip frames until the client is ready again.
  */
-TEST_F(EvsHidlTest, CameraStreamBuffering) {
+TEST_P(EvsHidlTest, CameraStreamBuffering) {
     ALOGI("Starting CameraStreamBuffering test");
 
     // Arbitrary constant (should be > 1 and less than crazy)
@@ -557,7 +567,7 @@
  * imagery is simply copied to the display buffer and presented on screen.  This is the one test
  * which a human could observe to see the operation of the system on the physical display.
  */
-TEST_F(EvsHidlTest, CameraToDisplayRoundTrip) {
+TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) {
     ALOGI("Starting CameraToDisplayRoundTrip test");
 
     // Get the camera list
@@ -567,9 +577,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) {
@@ -635,7 +666,7 @@
  * Verify that each client can start and stop video streams on the same
  * underlying camera.
  */
-TEST_F(EvsHidlTest, MultiCameraStream) {
+TEST_P(EvsHidlTest, MultiCameraStream) {
     ALOGI("Starting MultiCameraStream test");
 
     if (mIsHwModule) {
@@ -742,7 +773,7 @@
  * CameraParameter:
  * Verify that a client can adjust a camera parameter.
  */
-TEST_F(EvsHidlTest, CameraParameter) {
+TEST_P(EvsHidlTest, CameraParameter) {
     ALOGI("Starting CameraParameter test");
 
     // Get the camera list
@@ -886,7 +917,7 @@
  * Verify that non-master client gets notified when the master client either
  * terminates or releases a role.
  */
-TEST_F(EvsHidlTest, CameraMasterRelease) {
+TEST_P(EvsHidlTest, CameraMasterRelease) {
     ALOGI("Starting CameraMasterRelease test");
 
     if (mIsHwModule) {
@@ -1067,7 +1098,7 @@
  * Verify that master and non-master clients behave as expected when they try to adjust
  * camera parameters.
  */
-TEST_F(EvsHidlTest, MultiCameraParameter) {
+TEST_P(EvsHidlTest, MultiCameraParameter) {
     ALOGI("Starting MultiCameraParameter test");
 
     if (mIsHwModule) {
@@ -1350,7 +1381,7 @@
 
         std::mutex eventLock;
         auto timer = std::chrono::system_clock::now();
-        unique_lock<std::mutex> lock(eventLock);
+        std::unique_lock<std::mutex> lock(eventLock);
         while (!listening) {
             eventCond.wait_until(lock, timer + 1s);
         }
@@ -1540,7 +1571,7 @@
  * EVS client, which owns the display, is priortized and therefore can take over
  * a master role from other EVS clients without the display.
  */
-TEST_F(EvsHidlTest, HighPriorityCameraClient) {
+TEST_P(EvsHidlTest, HighPriorityCameraClient) {
     ALOGI("Starting HighPriorityCameraClient test");
 
     if (mIsHwModule) {
@@ -1556,7 +1587,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
@@ -1913,14 +1944,14 @@
  * CameraToDisplayRoundTrip test case but this case retrieves available stream
  * configurations from EVS and uses one of them to start a video stream.
  */
-TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) {
+TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) {
     ALOGI("Starting CameraUseStreamConfigToDisplay test");
 
     // Get the camera list
     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
@@ -2017,7 +2048,7 @@
  * Verify that each client can start and stop video streams on the same
  * underlying camera with same configuration.
  */
-TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) {
+TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) {
     ALOGI("Starting MultiCameraStream test");
 
     if (mIsHwModule) {
@@ -2166,7 +2197,7 @@
  * checking its capability and locating supporting physical camera device
  * identifiers.
  */
-TEST_F(EvsHidlTest, LogicalCameraMetadata) {
+TEST_P(EvsHidlTest, LogicalCameraMetadata) {
     ALOGI("Starting LogicalCameraMetadata test");
 
     // Get the camera list
@@ -2184,11 +2215,113 @@
 }
 
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    EvsHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
+/*
+ * UltrasonicsArrayOpenClean:
+ * Opens each ultrasonics arrays reported by the enumerator and then explicitly closes it via a
+ * call to closeUltrasonicsArray. Then repeats the test to ensure all ultrasonics arrays
+ * can be reopened.
+ */
+TEST_P(EvsHidlTest, UltrasonicsArrayOpenClean) {
+    ALOGI("Starting UltrasonicsArrayOpenClean test");
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // Open and close each ultrasonics array twice
+    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
+        for (int pass = 0; pass < 2; pass++) {
+            sp<IEvsUltrasonicsArray> pUltrasonicsArray =
+                    pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
+            ASSERT_NE(pUltrasonicsArray, nullptr);
+
+            // Verify that this ultrasonics array self-identifies correctly
+            pUltrasonicsArray->getUltrasonicArrayInfo([&ultraInfo](UltrasonicsArrayDesc desc) {
+                ALOGD("Found ultrasonics array %s", ultraInfo.ultrasonicsArrayId.c_str());
+                EXPECT_EQ(ultraInfo.ultrasonicsArrayId, desc.ultrasonicsArrayId);
+            });
+
+            // Explicitly close the ultrasonics array so resources are released right away
+            pEnumerator->closeUltrasonicsArray(pUltrasonicsArray);
+        }
+    }
 }
+
+
+// Starts a stream and verifies all data received is valid.
+TEST_P(EvsHidlTest, UltrasonicsVerifyStreamData) {
+    ALOGI("Starting UltrasonicsVerifyStreamData");
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // For each ultrasonics array.
+    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
+        ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str());
+
+        sp<IEvsUltrasonicsArray> pUltrasonicsArray =
+                pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
+        ASSERT_NE(pUltrasonicsArray, nullptr);
+
+        sp<FrameHandlerUltrasonics> frameHandler = new FrameHandlerUltrasonics(pUltrasonicsArray);
+
+        // Start stream.
+        EvsResult result = pUltrasonicsArray->startStream(frameHandler);
+        ASSERT_EQ(result, EvsResult::OK);
+
+        // Wait 5 seconds to receive frames.
+        sleep(5);
+
+        // Stop stream.
+        pUltrasonicsArray->stopStream();
+
+        EXPECT_GT(frameHandler->getReceiveFramesCount(), 0);
+        EXPECT_TRUE(frameHandler->areAllFramesValid());
+
+        // Explicitly close the ultrasonics array so resources are released right away
+        pEnumerator->closeUltrasonicsArray(pUltrasonicsArray);
+    }
+}
+
+
+// Sets frames in flight before and after start of stream and verfies success.
+TEST_P(EvsHidlTest, UltrasonicsSetFramesInFlight) {
+    ALOGI("Starting UltrasonicsSetFramesInFlight");
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // For each ultrasonics array.
+    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
+        ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str());
+
+        sp<IEvsUltrasonicsArray> pUltrasonicsArray =
+                pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
+        ASSERT_NE(pUltrasonicsArray, nullptr);
+
+        EvsResult result = pUltrasonicsArray->setMaxFramesInFlight(10);
+        EXPECT_EQ(result, EvsResult::OK);
+
+        sp<FrameHandlerUltrasonics> frameHandler = new FrameHandlerUltrasonics(pUltrasonicsArray);
+
+        // Start stream.
+        result = pUltrasonicsArray->startStream(frameHandler);
+        ASSERT_EQ(result, EvsResult::OK);
+
+        result = pUltrasonicsArray->setMaxFramesInFlight(5);
+        EXPECT_EQ(result, EvsResult::OK);
+
+        // Stop stream.
+        pUltrasonicsArray->stopStream();
+
+        // Explicitly close the ultrasonics array so resources are released right away
+        pEnumerator->closeUltrasonicsArray(pUltrasonicsArray);
+    }
+}
+
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance,
+    EvsHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEvsEnumerator::descriptor)),
+    android::hardware::PrintInstanceNameToString);
+
diff --git a/automotive/sv/1.0/Android.bp b/automotive/sv/1.0/Android.bp
new file mode 100644
index 0000000..769bdc6
--- /dev/null
+++ b/automotive/sv/1.0/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.sv@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ISurroundViewStream.hal",
+        "ISurroundViewSession.hal",
+        "ISurroundView2dSession.hal",
+        "ISurroundView3dSession.hal",
+        "ISurroundViewService.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+    ],
+    gen_java: true,
+}
diff --git a/automotive/sv/1.0/ISurroundView2dSession.hal b/automotive/sv/1.0/ISurroundView2dSession.hal
new file mode 100644
index 0000000..fa49674
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundView2dSession.hal
@@ -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.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import ISurroundViewSession;
+
+/**
+ * Interface representing a surround view 2d session.
+ *
+ * Surround view 2d provides a top/bird's eye view of the car and its surroundings.
+ */
+interface ISurroundView2dSession extends ISurroundViewSession {
+
+    /**
+     * Gets mapping information for 2d surround view.
+     *
+     * Mapping information maps the output frame of 2d surround view to actual dimensions
+     * covered on the ground. Mapping information is fixed for a car and is based upon its camera
+     * coverage. Mapping information can be used for doing overlays of objects in 3d space
+     * onto the surround view 2d output frame.
+     *
+     * @param sv2dConfig Configuration to set.
+     * @return sv2dMappingInfo mapping information of the 2d surround view.
+     */
+    get2dMappingInfo() generates (Sv2dMappingInfo sv2dMappingInfo);
+
+    /**
+     * Sets the configuration of 2d surround view.
+     *
+     * Configuration is used for supported different target use-cases of the surround view eg.
+     * fullscreen or preview. Default configuration is FULLSCREEN.
+     * A set config call can be performed at any time (before or after startStream) of the session.
+     * Once config change is complete, a CONFIG_CHANGED event is sent, after which
+     * all frames received will be of the updated config.
+     *
+     * @param sv2dConfig Configuration to set.
+     * @return svResult  Returns OK if successful, appropriate error result otherwise.
+     */
+    set2dConfig(Sv2dConfig sv2dConfig) generates (SvResult svResult);
+
+    /**
+     * Gets the current configuration of the 2d surround view.
+     *
+     * Configuration is used for supported different target use-cases of the surround view eg.
+     * fullscreen view or preview. Use setConfig call to set a configuration.
+     *
+     * @return sv2dConfig the active current configuration of the 2d session.
+     */
+    get2dConfig() generates (Sv2dConfig sv2dConfig);
+
+    /**
+     * Projects points on camera image to surround view 2d image.
+     *
+     * Useful for mapping points detected on individual camera frames onto the surround view 2d
+     * output frame.
+     *
+     * @param cameraPoints  List of camera pixel points to be projected in range including (0, 0)
+     *                      and (width - 1, height -1) of camera frame. If point is outside camera
+                            frame INVALID_ARG error is returned.
+     * @param cameraId      Id of the EvsCamera to use for projecting points. Id must be one of the
+     *                      cameras as returned by getCameraIds() else INVALID_ARG error is returned
+     * @return points2d     Returns a list of 2d pixel points projecting into surround view 2d
+     *                      frame in the same order as cameraPoints. Point projected maybe outside
+     *                      surround view frame i.e. outside (0, 0) and
+     *                      (sv_width - 1, sv_height - 1). Points that do not project to ground
+     *                      plane are set with inValid true.
+     */
+    projectCameraPoints(vec<Point2dInt> cameraPoints, string cameraId) generates (
+            vec<Point2dFloat> points2d);
+};
diff --git a/automotive/sv/1.0/ISurroundView3dSession.hal b/automotive/sv/1.0/ISurroundView3dSession.hal
new file mode 100644
index 0000000..d2b0c53
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundView3dSession.hal
@@ -0,0 +1,113 @@
+/*
+ * 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.sv@1.0;
+
+import ISurroundViewSession;
+
+/**
+ * Interface representing a surround view 3d session.
+ *
+ * Surround view 3d provides a virtual view from any desired position in the 3d space around the
+ * car. Surround view 3d creates an approximate 3d surface around the car to match the surrounds
+ * and provides a virtual view as seen on this surface.
+ */
+interface ISurroundView3dSession extends ISurroundViewSession {
+
+    /**
+     * Sets the desired views of surround view 3d.
+     *
+     * Surround view 3d takes a list of desired virtual view points and provides an output frame
+     * for each view. Default view list is a single view from behind the car front facing in the
+     * front direction.
+     * A call to setViews() results in the views set by a previous call to be discarded.
+     * Each view set is identified by an Id which is returned with the corresponding output frame
+     * of that view.
+     * Clients can call setViews() at any stage of the session (before/after startStream). Client
+     * may continue to receive frames of previous views after setViews() call for a while and can
+     * identify updated set of views once effective using the view Id provided in the updated
+     * views frames.
+     *
+     * @param views     List of desired views to generate output frames.
+     * @return svResult Returns OK if successful, appropriate error result otherwise.
+     */
+    setViews(vec<View3d> views) generates (SvResult svResult);
+
+    /**
+     * Sets the configuration of 3d surround view.
+     *
+     * Configuration is used for supported different target use-cases of the surround view eg.
+     * fullscreen view or preview. A set config call can be performed at anytime (before or after
+     * startStream) of the session.
+     * Once config change is complete, a CONFIG_CHANGED event is sent, after which
+     * all frames received will be of the updated config.
+     *
+     * @param sv3dConfig Configuration to set.
+     * @return svResult  Returns OK if successful, appropriate error result otherwise.
+     */
+    set3dConfig(Sv3dConfig sv3dConfig) generates (SvResult svResult);
+
+    /**
+     * Gets the current configuration of the 3d surround view.
+     *
+     * Configuration is used for supported different target use-cases of the surround view eg.
+     * fullscreen view or preview. Use setConfig call to set a configuration.
+     *
+     * @return sv3dConfig The current active configuration of the 3d session.
+     */
+    get3dConfig() generates (Sv3dConfig sv3dConfig);
+
+    /**
+     * Updates 3d overlays in scene.
+     *
+     * updateOverlays() provides a way to set a 3d overlay object in the scene. An overlay is an
+     * 3d object in the scene which can be a visual indicator to provide additional information eg.
+     * parking sensor distance indicators or overlays for objects in scene.
+     *
+     * An overlay object is defined by a set of points (forming triangles) with some color and
+     * transparency values and each overlay is identified by an overlay Id.
+     * When an overlay with a new Id is passed, a new overlay is added to the scene.
+     * When an overlay with previous id is passed, its vertices/color are updated with passed data.
+     * If the overlay data is empty, the overlay is removed from the scene.
+     *
+     * @param overlaysData   Object with shared memory containing overlays to add/update in the
+     *                       scene. Refer to OverlaysData structure for layout in shared memory.
+     * @return svResult      Returns OK if successful, appropriate error result otherwise.
+     */
+    updateOverlays(OverlaysData overlaysData) generates (SvResult svResult);
+
+    /**
+     * Projects points on camera image to surround view 3D surface.
+     *
+     * Useful for mapping points detected on individual camera frames onto the surround view 3D
+     * surface, these 3d points can then be used to set overlays using the updateOverlays() for
+     * the detected objects in the scene.
+     * Note:
+     * 3d points returned are projected on an approximate 3d surface and do not provide the exact
+     * 3d location.
+     *
+     * @param cameraPoints  List of camera pixel points to be projected in range including (0, 0)
+     *                      and (width - 1, height -1) of camera frame. If point is outside camera
+                            frame INVALID_ARG error is returned.
+     * @param cameraId      Id of the EvsCamera to use for projecting points. Id must be one of the
+     *                      cameras as returned by getCameraIds() else INVALID_ARG error is returned
+     * @return points3d     Returns a list of 3d points on the approximate 3d surface in the
+     *                      automotive coordinate system in the same order as cameraPoints.
+     *                      Points that do not project to 3d surface are set with inValid true.
+     */
+    projectCameraPointsTo3dSurface(vec<Point2dInt> cameraPoints, string cameraId) generates (
+            vec<Point3dFloat> points3d);
+};
diff --git a/automotive/sv/1.0/ISurroundViewService.hal b/automotive/sv/1.0/ISurroundViewService.hal
new file mode 100644
index 0000000..7de0bd1
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundViewService.hal
@@ -0,0 +1,71 @@
+/*
+ * 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.sv@1.0;
+
+import ISurroundView2dSession;
+import ISurroundView3dSession;
+
+/**
+ * Interface representing entry point for surround view.
+ *
+ * Surround view service has two types of sessions 2d and 3d. Refer to their respective interface
+ * for more details.
+ */
+interface ISurroundViewService {
+
+    /**
+     * Gets a list of camera ids that are used for generating surround view.
+     * For 4 camera configuration, the cameras ids are ordered in clockwise direction
+     * when viewed from top of the car starting with the front camera. i.e. FRONT, RIGHT, REAR and
+     * LEFT. All other configurations must follow clockwise order.
+     *
+     * @result cameraIds List of camera ids that matching the Id of EVS Cameras used by service.
+     */
+    getCameraIds() generates (vec<string> cameraIds);
+
+    /**
+     * Starts a surround view 2d session.
+     *
+     * @result sv2dSession Returns a new 2d session that was created.
+     *         result      Returns OK if successful, appropriate error result otherwise.
+     */
+    start2dSession() generates (ISurroundView2dSession sv2dSession, SvResult result);
+
+    /**
+     * Stops a surround view 2d session.
+     *
+     * @param sv2dSession Valid 2d session to be stopped.
+     * @return svResult   Returns OK if successful, appropriate error result otherwise.
+     */
+    stop2dSession(ISurroundView2dSession sv2dSession) generates (SvResult result);
+
+    /**
+     * Starts a surround view 3d session.
+     *
+     * @result sv3dSession Returns a new 3d session that was created.
+     *         result      Returns OK if successful, appropriate error result otherwise.
+     */
+    start3dSession() generates (ISurroundView3dSession sv3dSession, SvResult result);
+
+    /**
+     * Stops a surround view 2d session.
+     *
+     * @param sv2dSession Valid 2d session to be stopped.
+     * @return svResult  Returns OK if successful, appropriate error result otherwise.
+     */
+    stop3dSession(ISurroundView3dSession sv3dSession) generates (SvResult result);
+};
diff --git a/automotive/sv/1.0/ISurroundViewSession.hal b/automotive/sv/1.0/ISurroundViewSession.hal
new file mode 100644
index 0000000..62cfac0
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundViewSession.hal
@@ -0,0 +1,51 @@
+/*
+ * 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.sv@1.0;
+
+import ISurroundViewStream;
+
+/**
+ * Common interface for surround view session extended by surround view 2d and 3d
+ * session.
+ */
+interface ISurroundViewSession {
+    /**
+     * Requests to start receiving surround view frames.
+     *
+     * For surround view 3d, setViews() must be set before calling startStream().
+     *
+     * @param stream     Stream to receiving callbacks for the session.
+     * @return svResult  Returns OK if successful, returns VIEW_NOT_SET if setViews() is not
+     *                   called for surround view 3d, appropriate error results otherwise.
+     */
+    startStream(ISurroundViewStream stream) generates (SvResult svResult);
+
+    /**
+     * Requests to stop stream.
+     *
+     * Frames may continue to arrive after call returns. Each must be returned until
+     * the closure of the stream is signaled by the ISurroundViewStream.
+     */
+    stopStream();
+
+    /**
+     * Signal from client that a frame, which was delivered by the stream, has been consumed.
+     *
+     * @param  svFramesDesc Descriptor to signal done with frame.
+     */
+    oneway doneWithFrames(SvFramesDesc svFramesDesc);
+};
diff --git a/automotive/sv/1.0/ISurroundViewStream.hal b/automotive/sv/1.0/ISurroundViewStream.hal
new file mode 100644
index 0000000..22d610f
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundViewStream.hal
@@ -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.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+/**
+ * Interface representing a surround view stream.
+ *
+ * This interface is to be implemented by client to receive callback for output frames and events.
+ */
+interface ISurroundViewStream {
+    /**
+     * Receives callback of surround view 2d/3d frames.
+     *
+     * @param svFramesDesc Frames descriptor containing the output frames.
+     */
+    oneway receiveFrames(SvFramesDesc svFramesDesc);
+
+    /**
+     * Receives callback for surround view events.
+     *
+     * @param svEvent Surround view event.
+    */
+    oneway notify(SvEvent svEvent);
+};
diff --git a/automotive/sv/1.0/default/Android.bp b/automotive/sv/1.0/default/Android.bp
new file mode 100644
index 0000000..8417949
--- /dev/null
+++ b/automotive/sv/1.0/default/Android.bp
@@ -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.
+//
+
+cc_binary {
+    name: "android.hardware.automotive.sv@1.0-service",
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "service.cpp",
+        "SurroundViewService.cpp",
+        "SurroundView2dSession.cpp",
+        "SurroundView3dSession.cpp",
+    ],
+    init_rc: ["android.hardware.automotive.sv@1.0-service.rc"],
+    vintf_fragments: ["android.hardware.automotive.sv@1.0-service.xml"],
+    shared_libs: [
+        "android.hardware.automotive.sv@1.0",
+        "android.hidl.memory@1.0",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libui",
+        "libutils",
+        "libhidlmemory",
+    ],
+
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/automotive/sv/1.0/default/SurroundView2dSession.cpp b/automotive/sv/1.0/default/SurroundView2dSession.cpp
new file mode 100644
index 0000000..4f97598
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView2dSession.cpp
@@ -0,0 +1,240 @@
+/*
+ * 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 "SurroundView2dSession.h"
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+SurroundView2dSession::SurroundView2dSession() :
+    mStreamState(STOPPED) {
+    mEvsCameraIds = {"0" , "1", "2", "3"};
+
+    mConfig.width = 640;
+    mConfig.blending = SvQuality::HIGH;
+
+    framesRecord.frames.svBuffers.resize(1);
+    framesRecord.frames.svBuffers[0].viewId = 0;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle =
+        new native_handle_t();
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
+        mConfig.width;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
+        mConfig.width * 3 / 4;
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
+Return<SvResult> SurroundView2dSession::startStream(
+    const sp<ISurroundViewStream>& stream) {
+    ALOGD("SurroundView2dSession::startStream");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    if (mStreamState != STOPPED) {
+        ALOGE("ignoring startVideoStream call"
+              "when a stream is already running.");
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    mStream = stream;
+
+    ALOGD("Notify SvEvent::STREAM_STARTED");
+    mStream->notify(SvEvent::STREAM_STARTED);
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = std::thread([this](){ generateFrames(); });
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::stopStream() {
+    ALOGD("SurroundView2dSession::stopStream");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    if (mStreamState == RUNNING) {
+        // Tell the GenerateFrames loop we want it to stop
+        mStreamState = STOPPING;
+
+        // Block outside the mutex until the "stop" flag has been acknowledged
+        // We won't send any more frames, but the client might still get some
+        // already in flight
+        ALOGD("Waiting for stream thread to end...");
+        lock.unlock();
+        mCaptureThread.join();
+        lock.lock();
+
+        mStreamState = STOPPED;
+        mStream = nullptr;
+        ALOGD("Stream marked STOPPED.");
+    }
+
+    return android::hardware::Void();
+}
+
+Return<void> SurroundView2dSession::doneWithFrames(
+    const SvFramesDesc& svFramesDesc){
+    ALOGD("SurroundView2dSession::doneWithFrames");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    framesRecord.inUse = false;
+
+    (void)svFramesDesc;
+    return android::hardware::Void();
+}
+
+// Methods from ISurroundView2dSession follow.
+Return<void> SurroundView2dSession::get2dMappingInfo(
+    get2dMappingInfo_cb _hidl_cb) {
+    ALOGD("SurroundView2dSession::get2dMappingInfo");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    Sv2dMappingInfo info;
+    info.width = 8; // keeps ratio to 4:3
+    info.height = 6;
+    info.center.isValid = true;
+    info.center.x = 0;
+    info.center.y = 0;
+    _hidl_cb(info);
+    return android::hardware::Void();
+}
+
+Return<SvResult> SurroundView2dSession::set2dConfig(
+    const Sv2dConfig& sv2dConfig) {
+    ALOGD("SurroundView2dSession::setConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    mConfig.width = sv2dConfig.width;
+    mConfig.blending = sv2dConfig.blending;
+    ALOGD("Notify SvEvent::CONFIG_UPDATED");
+    mStream->notify(SvEvent::CONFIG_UPDATED);
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) {
+    ALOGD("SurroundView2dSession::getConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    _hidl_cb(mConfig);
+    return android::hardware::Void();
+}
+
+Return<void> SurroundView2dSession::projectCameraPoints(
+        const hidl_vec<Point2dInt>& points2dCamera,
+        const hidl_string& cameraId,
+        projectCameraPoints_cb _hidl_cb) {
+    ALOGD("SurroundView2dSession::projectCameraPoints");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    bool cameraIdFound = false;
+    for (auto evsCameraId : mEvsCameraIds) {
+      if (cameraId == evsCameraId) {
+          cameraIdFound = true;
+          ALOGI("Camera id found.");
+          break;
+      }
+    }
+
+    if (!cameraIdFound) {
+        ALOGE("Camera id not found.");
+        _hidl_cb(hidl_vec<Point2dFloat>());
+        return android::hardware::Void();
+    }
+
+    hidl_vec<Point2dFloat> outPoints;
+    outPoints.resize(points2dCamera.size());
+
+    int width = mConfig.width;
+    int height = mConfig.width * 3 / 4;
+    for (int i=0; i<points2dCamera.size(); i++) {
+        // Assuming all the points in the image frame can be projected into 2d
+        // Surround View space. Otherwise cannot.
+        if (points2dCamera[i].x < 0 || points2dCamera[i].y > width-1 ||
+            points2dCamera[i].x < 0 || points2dCamera[i].y > height-1) {
+            ALOGW("SurroundView2dSession::projectCameraPoints "
+                  "gets invalid 2d camera points. Ignored");
+            outPoints[i].isValid = false;
+            outPoints[i].x = 10000;
+            outPoints[i].y = 10000;
+        } else {
+            outPoints[i].isValid = true;
+            outPoints[i].x = 0;
+            outPoints[i].y = 0;
+        }
+    }
+
+    _hidl_cb(outPoints);
+    return android::hardware::Void();
+}
+
+void SurroundView2dSession::generateFrames() {
+    ALOGD("SurroundView2dSession::generateFrames");
+
+    int sequenceId = 0;
+
+    while(true) {
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (mStreamState != RUNNING) {
+                // Break out of our main thread loop
+                break;
+            }
+
+            framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
+                mConfig.width;
+            framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
+                mConfig.width * 3 / 4;
+        }
+
+        usleep(100 * 1000);
+
+        framesRecord.frames.timestampNs = elapsedRealtimeNano();
+        framesRecord.frames.sequenceId = sequenceId++;
+
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (framesRecord.inUse) {
+                ALOGD("Notify SvEvent::FRAME_DROPPED");
+                mStream->notify(SvEvent::FRAME_DROPPED);
+            } else {
+                framesRecord.inUse = true;
+                mStream->receiveFrames(framesRecord.frames);
+            }
+        }
+    }
+
+    // If we've been asked to stop, send an event to signal the actual
+    // end of stream
+    ALOGD("Notify SvEvent::STREAM_STOPPED");
+    mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView2dSession.h b/automotive/sv/1.0/default/SurroundView2dSession.h
new file mode 100644
index 0000000..ee751e7
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView2dSession.h
@@ -0,0 +1,98 @@
+/*
+ * 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/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::mutex;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView2dSession : public ISurroundView2dSession {
+public:
+    SurroundView2dSession();
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+    Return<SvResult> startStream(
+        const sp<ISurroundViewStream>& stream) override;
+    Return<void> stopStream() override;
+    Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+    // Methods from ISurroundView2dSession follow.
+    Return<void> get2dMappingInfo(get2dMappingInfo_cb _hidl_cb) override;
+    Return<SvResult> set2dConfig(const Sv2dConfig& sv2dConfig) override;
+    Return<void> get2dConfig(get2dConfig_cb _hidl_cb) override;
+    Return<void> projectCameraPoints(
+        const hidl_vec<Point2dInt>& points2dCamera,
+        const hidl_string& cameraId,
+        projectCameraPoints_cb _hidl_cb) override;
+
+    // TODO(tanmayp): Make private and add set/get method.
+    // Stream subscribed for the session.
+    sp<ISurroundViewStream> mStream;
+
+private:
+    void generateFrames();
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+    StreamStateValues mStreamState;
+
+    Sv2dConfig mConfig;
+
+    std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+    struct FramesRecord {
+        SvFramesDesc frames;
+        bool inUse = false;
+    };
+
+    FramesRecord framesRecord;
+
+    // Synchronization necessary to deconflict mCaptureThread from the main service thread
+    std::mutex mAccessLock;
+
+    std::vector<std::string> mEvsCameraIds;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView3dSession.cpp b/automotive/sv/1.0/default/SurroundView3dSession.cpp
new file mode 100644
index 0000000..da36f32
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView3dSession.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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 "SurroundView3dSession.h"
+
+#include <set>
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::hidl_memory;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+SurroundView3dSession::SurroundView3dSession() :
+    mStreamState(STOPPED){
+
+    mEvsCameraIds = {"0" , "1", "2", "3"};
+
+    mConfig.width = 640;
+    mConfig.height = 480;
+    mConfig.carDetails = SvQuality::HIGH;
+
+    framesRecord.frames.svBuffers.resize(1);
+    framesRecord.frames.svBuffers[0].viewId = 0;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle = new native_handle_t();
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] = mConfig.width;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] = mConfig.height;
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+Return<SvResult> SurroundView3dSession::startStream(
+    const sp<ISurroundViewStream>& stream) {
+    ALOGD("SurroundView3dSession::startStream");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    if (mStreamState != STOPPED) {
+        ALOGE("ignoring startVideoStream call when a stream is already running.");
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (mViews.empty()) {
+        ALOGE("No views have been set for current Surround View 3d Session. "
+              "Please call setViews before starting the stream.");
+        return SvResult::VIEW_NOT_SET;
+    }
+
+    mStream = stream;
+
+    ALOGD("Notify SvEvent::STREAM_STARTED");
+    mStream->notify(SvEvent::STREAM_STARTED);
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = std::thread([this](){ generateFrames(); });
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::stopStream() {
+    ALOGD("SurroundView3dSession::stopStream");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    if (mStreamState == RUNNING) {
+        // Tell the GenerateFrames loop we want it to stop
+        mStreamState = STOPPING;
+
+        // Block outside the mutex until the "stop" flag has been acknowledged
+        // We won't send any more frames, but the client might still get some already in flight
+        ALOGD("Waiting for stream thread to end...");
+        lock.unlock();
+        mCaptureThread.join();
+        lock.lock();
+
+        mStreamState = STOPPED;
+        mStream = nullptr;
+        ALOGD("Stream marked STOPPED.");
+    }
+
+    return android::hardware::Void();
+}
+
+Return<void> SurroundView3dSession::doneWithFrames(
+    const SvFramesDesc& svFramesDesc){
+    ALOGD("SurroundView3dSession::doneWithFrames");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    framesRecord.inUse = false;
+
+    (void)svFramesDesc;
+    return android::hardware::Void();
+}
+
+// Methods from ISurroundView3dSession follow.
+Return<SvResult> SurroundView3dSession::setViews(const hidl_vec<View3d>& views) {
+    ALOGD("SurroundView3dSession::stopStream");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    mViews.resize(views.size());
+    for (int i=0; i<views.size(); i++) {
+        mViews[i] = views[i];
+    }
+
+    return SvResult::OK;
+}
+
+Return<SvResult> SurroundView3dSession::set3dConfig(const Sv3dConfig& sv3dConfig) {
+    ALOGD("SurroundView3dSession::set3dConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    mConfig.width = sv3dConfig.width;
+    mConfig.height = sv3dConfig.height;
+    mConfig.carDetails = sv3dConfig.carDetails;
+    ALOGD("Notify SvEvent::CONFIG_UPDATED");
+    mStream->notify(SvEvent::CONFIG_UPDATED);
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::get3dConfig(get3dConfig_cb _hidl_cb) {
+    ALOGD("SurroundView3dSession::get3dConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    _hidl_cb(mConfig);
+    return android::hardware::Void();
+}
+
+bool VerifyOverlayData(const OverlaysData& overlaysData) {
+    // Check size of shared memory matches overlaysMemoryDesc.
+    const int kVertexSize = 16;
+    const int kIdSize = 2;
+    int memDescSize = 0;
+    for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+        memDescSize += kIdSize + kVertexSize * overlayMemDesc.verticesCount;
+    }
+    if (memDescSize != overlaysData.overlaysMemory.size()) {
+        ALOGE("shared memory and overlaysMemoryDesc size mismatch.");
+        return false;
+    }
+
+    // Map memory.
+    sp<IMemory> pSharedMemory = mapMemory(overlaysData.overlaysMemory);
+    if(pSharedMemory.get() == nullptr) {
+        ALOGE("mapMemory failed.");
+        return false;
+    }
+
+    // Get Data pointer.
+    uint8_t* pData = (uint8_t*)((void*)pSharedMemory->getPointer());
+    if (pData == nullptr) {
+        ALOGE("Shared memory getPointer() failed.");
+        return false;
+    }
+
+    int idOffset = 0;
+    std::set<uint16_t> overlayIdSet;
+    for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+
+        if (overlayIdSet.find(overlayMemDesc.id) != overlayIdSet.end()) {
+            ALOGE("Duplicate id within memory descriptor.");
+            return false;
+        }
+        overlayIdSet.insert(overlayMemDesc.id);
+
+        if(overlayMemDesc.verticesCount < 3) {
+            ALOGE("Less than 3 vertices.");
+            return false;
+        }
+
+        if (overlayMemDesc.overlayPrimitive == OverlayPrimitive::TRIANGLES &&
+                overlayMemDesc.verticesCount % 3 != 0) {
+            ALOGE("Triangles primitive does not have vertices multiple of 3.");
+            return false;
+        }
+
+        uint16_t overlayId = *((uint16_t*)(pData + idOffset));
+
+        if (overlayId != overlayMemDesc.id) {
+            ALOGE("Overlay id mismatch %d , %d", overlayId, overlayMemDesc.id);
+            return false;
+        }
+
+        idOffset += kIdSize + (kVertexSize * overlayMemDesc.verticesCount);
+    }
+
+    return true;
+}
+
+Return<SvResult>  SurroundView3dSession::updateOverlays(
+        const OverlaysData& overlaysData) {
+
+    if(!VerifyOverlayData(overlaysData)) {
+        ALOGE("VerifyOverlayData failed.");
+        return SvResult::INVALID_ARG;
+    }
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::projectCameraPointsTo3dSurface(
+    const hidl_vec<Point2dInt>& cameraPoints,
+    const hidl_string& cameraId,
+    projectCameraPointsTo3dSurface_cb _hidl_cb) {
+
+    std::vector<Point3dFloat> points3d;
+    bool cameraIdFound = false;
+    for (auto evsCameraId : mEvsCameraIds) {
+      if (cameraId == evsCameraId) {
+          cameraIdFound = true;
+          ALOGI("Camera id found.");
+          break;
+      }
+    }
+
+    if (!cameraIdFound) {
+        ALOGE("Camera id not found.");
+        _hidl_cb(points3d);
+        return android::hardware::Void();
+    }
+
+    for (const auto cameraPoint : cameraPoints) {
+        Point3dFloat point3d;
+        point3d.isValid = true;
+
+        if (cameraPoint.x < 0 || cameraPoint.x >= mConfig.width-1 ||
+                cameraPoint.y < 0 || cameraPoint.y >= mConfig.height-1) {
+            ALOGE("Camera point out of bounds.");
+            point3d.isValid = false;
+        }
+        points3d.push_back(point3d);
+    }
+    _hidl_cb(points3d);
+    return android::hardware::Void();
+}
+
+void SurroundView3dSession::generateFrames() {
+    ALOGD("SurroundView3dSession::generateFrames");
+
+    int sequenceId = 0;
+
+    while(true) {
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (mStreamState != RUNNING) {
+                // Break out of our main thread loop
+                break;
+            }
+        }
+
+        usleep(100 * 1000);
+
+        framesRecord.frames.timestampNs = elapsedRealtimeNano();
+        framesRecord.frames.sequenceId = sequenceId++;
+
+        framesRecord.frames.svBuffers.resize(mViews.size());
+        for (int i=0; i<mViews.size(); i++) {
+            framesRecord.frames.svBuffers[i].viewId = mViews[i].viewId;
+            framesRecord.frames.svBuffers[i].hardwareBuffer.nativeHandle = new native_handle_t();
+            framesRecord.frames.svBuffers[i].hardwareBuffer.description[0] = mConfig.width; // width
+            framesRecord.frames.svBuffers[i].hardwareBuffer.description[1] = mConfig.height; // height
+        }
+
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (framesRecord.inUse) {
+                ALOGD("Notify SvEvent::FRAME_DROPPED");
+                mStream->notify(SvEvent::FRAME_DROPPED);
+            } else {
+                framesRecord.inUse = true;
+                mStream->receiveFrames(framesRecord.frames);
+            }
+        }
+    }
+
+    // If we've been asked to stop, send an event to signal the actual end of stream
+    ALOGD("Notify SvEvent::STREAM_STOPPED");
+    mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView3dSession.h b/automotive/sv/1.0/default/SurroundView3dSession.h
new file mode 100644
index 0000000..5c638db
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView3dSession.h
@@ -0,0 +1,100 @@
+/*
+ * 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/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::mutex;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView3dSession : public ISurroundView3dSession {
+public:
+    SurroundView3dSession();
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+    Return<SvResult> startStream(
+        const sp<ISurroundViewStream>& stream) override;
+    Return<void> stopStream() override;
+    Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+    // Methods from ISurroundView3dSession follow.
+    Return<SvResult> setViews(const hidl_vec<View3d>& views) override;
+    Return<SvResult> set3dConfig(const Sv3dConfig& sv3dConfig) override;
+    Return<void> get3dConfig(get3dConfig_cb _hidl_cb) override;
+    Return<SvResult>  updateOverlays(const OverlaysData& overlaysData);
+    Return<void> projectCameraPointsTo3dSurface(
+        const hidl_vec<Point2dInt>& cameraPoints,
+        const hidl_string& cameraId,
+        projectCameraPointsTo3dSurface_cb _hidl_cb);
+
+    // Stream subscribed for the session.
+    // TODO(tanmayp): Make private and add set/get method.
+    sp<ISurroundViewStream> mStream;
+
+private:
+    void generateFrames();
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+    StreamStateValues mStreamState;
+
+    std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+    struct FramesRecord {
+        SvFramesDesc frames;
+        bool inUse = false;
+    };
+
+    FramesRecord framesRecord;
+
+    // Synchronization necessary to deconflict mCaptureThread from the main service thread
+    std::mutex mAccessLock;
+
+    std::vector<View3d> mViews;
+
+    Sv3dConfig mConfig;
+
+    std::vector<std::string> mEvsCameraIds;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/sv/1.0/default/SurroundViewService.cpp b/automotive/sv/1.0/default/SurroundViewService.cpp
new file mode 100644
index 0000000..fe89dd5
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundViewService.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.
+ */
+
+#include "SurroundViewService.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+const std::string kCameraIds[] = {"0", "1", "2", "3"};
+
+Return<void> SurroundViewService::getCameraIds(getCameraIds_cb _hidl_cb) {
+  std::vector<hidl_string> cameraIds = {kCameraIds[0], kCameraIds[1],
+          kCameraIds[2], kCameraIds[3]};
+  _hidl_cb(cameraIds);
+  return android::hardware::Void();
+}
+
+Return<void> SurroundViewService::start2dSession(start2dSession_cb _hidl_cb) {
+    ALOGD("SurroundViewService::start2dSession");
+    if (mSurroundView2dSession != nullptr) {
+        ALOGW("Only one 2d session is supported at the same time");
+        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+    } else {
+        mSurroundView2dSession = new SurroundView2dSession();
+        _hidl_cb(mSurroundView2dSession, SvResult::OK);
+    }
+    return android::hardware::Void();
+}
+
+Return<SvResult> SurroundViewService::stop2dSession(
+    const sp<ISurroundView2dSession>& sv2dSession) {
+    ALOGD("SurroundViewService::stop2dSession");
+    if (sv2dSession != nullptr && sv2dSession == mSurroundView2dSession) {
+        mSurroundView2dSession = nullptr;
+        return SvResult::OK;
+    } else {
+        ALOGE("Invalid arg for stop2dSession");
+        return SvResult::INVALID_ARG;
+    }
+}
+
+Return<void> SurroundViewService::start3dSession(start3dSession_cb _hidl_cb) {
+    ALOGD("SurroundViewService::start3dSession");
+    if (mSurroundView3dSession != nullptr) {
+        ALOGW("Only one 3d session is supported at the same time");
+        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+    } else {
+        mSurroundView3dSession = new SurroundView3dSession();
+        _hidl_cb(mSurroundView3dSession, SvResult::OK);
+    }
+    return android::hardware::Void();
+}
+
+Return<SvResult> SurroundViewService::stop3dSession(
+    const sp<ISurroundView3dSession>& sv3dSession) {
+    ALOGD("SurroundViewService::stop3dSession");
+    if (sv3dSession != nullptr && sv3dSession == mSurroundView3dSession) {
+        mSurroundView3dSession = nullptr;
+        return SvResult::OK;
+    } else {
+        ALOGE("Invalid arg for stop3dSession");
+        return SvResult::INVALID_ARG;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundViewService.h b/automotive/sv/1.0/default/SurroundViewService.h
new file mode 100644
index 0000000..9e0e151
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundViewService.h
@@ -0,0 +1,64 @@
+/*
+ * 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 "SurroundView2dSession.h"
+#include "SurroundView3dSession.h"
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundViewService : public ISurroundViewService {
+public:
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewService follow.
+    Return<void> getCameraIds(getCameraIds_cb _hidl_cb) override;
+    Return<void> start2dSession(start2dSession_cb _hidl_cb) override;
+    Return<SvResult> stop2dSession(
+        const sp<ISurroundView2dSession>& sv2dSession) override;
+
+    Return<void> start3dSession(start3dSession_cb _hidl_cb) override;
+    Return<SvResult> stop3dSession(
+        const sp<ISurroundView3dSession>& sv3dSession) override;
+
+private:
+    sp<SurroundView2dSession> mSurroundView2dSession;
+    sp<SurroundView3dSession> mSurroundView3dSession;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc
new file mode 100644
index 0000000..e822017
--- /dev/null
+++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc
@@ -0,0 +1,5 @@
+service sv_service /vendor/bin/hw/android.hardware.automotive.sv@1.0-service
+    class hal
+    user automotive_evs
+    group automotive_evs
+    disabled
diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml
new file mode 100644
index 0000000..ba8e5ac
--- /dev/null
+++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.automotive.sv</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ISurroundViewService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/automotive/sv/1.0/default/service.cpp b/automotive/sv/1.0/default/service.cpp
new file mode 100644
index 0000000..fae7425
--- /dev/null
+++ b/automotive/sv/1.0/default/service.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.automotive.sv@1.0-service"
+
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware_buffer.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <thread>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/SystemClock.h>
+
+#include "SurroundViewService.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// implementation:
+using android::hardware::automotive::sv::V1_0::implementation::SurroundViewService;
+
+int main() {
+    ALOGI("ISurroundViewService default implementation is starting");
+    android::sp<ISurroundViewService> service = new SurroundViewService();
+
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    // Register our service -- if somebody is already registered by our name,
+    // they will be killed (their thread pool will throw an exception).
+    android::status_t status = service->registerAsService();
+
+    LOG_ALWAYS_FATAL_IF(status != android::OK,
+                        "Could not register default Surround View Service (%d)",
+                        status);
+
+    joinRpcThreadpool();
+
+    // In normal operation, we don't expect the thread pool to exit
+    ALOGE("Surround View Service is shutting down");
+    return 1;
+}
diff --git a/automotive/sv/1.0/types.hal b/automotive/sv/1.0/types.hal
new file mode 100644
index 0000000..573bf11
--- /dev/null
+++ b/automotive/sv/1.0/types.hal
@@ -0,0 +1,351 @@
+/*
+ * 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.sv@1.0;
+
+import android.hardware.graphics.common@1.2::HardwareBuffer;
+
+/** Structure for translation with x, y and z units. */
+struct Translation {
+    float x;
+    float y;
+    float z;
+};
+
+/**
+ * Structure for rotation expressed as quaternions.
+ * Convention used: Unit quaternion with hamilton convention.
+ */
+struct RotationQuat {
+    float x;
+    float y;
+    float z;
+    float w;
+};
+
+/** Structure representing a 2D point with integers. Units are pixels. */
+struct Point2dInt {
+    uint32_t x;
+    uint32_t y;
+};
+
+/** Structure representing a 2D point with floats. */
+struct Point2dFloat {
+    /** Boolean flag to indicate the (x, y) data is valid. */
+    bool isValid;
+
+    /** (x, y) data is only valid if isValid is true. Units are pixels or milli-meters. */
+    float x;
+    float y;
+};
+
+/** Structure representing a 3D point with floats. */
+struct Point3dFloat {
+    /** Boolean flag to indicate the (x, y, z) data is valid. */
+    bool isValid;
+
+    /**
+     * (x, y, z) data is only valid if isValid is true. Units are milli-meters.
+     */
+    float x;
+    float y;
+    float z;
+};
+
+/**
+ * Structure defining the pose in 3D space.
+ */
+struct Pose {
+    /**
+     * Rotation part of the pose, expressed as a unit quaternion.
+     */
+    RotationQuat rotation;
+
+    /**
+     * Translation part of the pose, in (x, y, z) format with milli-meter units.
+     */
+    Translation translation;
+};
+
+/**
+ * Struct defining a virtual view in the 3d space around the car.
+ */
+struct View3d {
+    /**
+     * Id to identify each custom view, this is passed along in each result SvBuffer.
+     * Recommend client to have a unique id for each different view.
+     */
+    uint32_t viewId;
+
+    /**
+     * Pose of the view. Describes the orientation and location of a virtual view relative to the
+     * android automotive coordinate system:
+     * https://source.android.com/devices/sensors/sensor-types#auto_axes
+     * The virtual view axes are defined as +Y as look-at direction, +X as right direction and
+     * +Z as up direction.
+     * The rotation and translation of the virtual view axes w.r.t the android automotive axes is
+     * specified by the rotation and tranlation component of the pose respectively.
+     * Example: A virtual view points to the right face of the car, located on right side of
+     * the car at (4, 2, 0) and is upright w.r.t the ground :
+     *         ______
+     *  front |      |
+     *        | car  |    ↑X
+     *        |  ↑Y  |  Y←∘  view
+     *  rear  |  ∘→X |  (4,2)
+     *        |(0,0) |
+     *        |______|
+     *
+     * Here the view axes are rotated by 90 counter-clockwise w.r.t android automotive axes.
+     * For this example the rotation and translation will be:
+     * Rotation = + 90 degrees around Z axis = (0.7071, 0, 0, 0.7071) as a unit quaternion.
+     * Translation = (4, 2, 0) in meters = (2000, 4000, 0) in milli-meters.
+     */
+    Pose pose;
+
+    /**
+     * Horizontal field of view of the virtual view in degrees. Vertical fov is scaled accordingly
+     * to maintain the aspect ratio of the output frame. Must be in range (20,
+     */
+    float horizontalFov;
+};
+
+/**
+ * Memory Buffer that stores the output of a single view from 2d/3d surround view.
+ */
+struct SvBuffer {
+    /**
+     * viewId identifying the view as passed by the client in setViews() call for
+     * surround view 3d. Id value is 0 for 2d surround view frame.
+     */
+    uint32_t viewId;
+
+    /** Hardware buffer containing the surround view 2d/3d result. */
+    HardwareBuffer hardwareBuffer;
+};
+
+/**
+ * Structure describing a set of frames to be returned as output from 2d/3d surround view.
+ */
+struct SvFramesDesc {
+    /**
+     * Elapsed real-time nanoseconds of earliest camera frame from the set of camera
+     * frames used to generate the view.
+     */
+    uint64_t timestampNs;
+
+    /**
+     * Incremental counter for client to keep track of frames.
+     */
+    uint32_t sequenceId;
+
+    /**
+     * Frames generated with different views.
+     * 2d surround view has only a single svBuffer with Id 0.
+     */
+    vec<SvBuffer> svBuffers;
+};
+
+/**
+ * Enumerator for list of result returns by surround view .
+ */
+enum SvResult : uint32_t {
+    /** Operation was successful. */
+    OK = 0,
+
+    /** Invalid argument to function was provided. */
+    INVALID_ARG,
+
+    /** Error indicating the particular operation is not supported. */
+    NOT_SUPPORTED,
+
+    /** Error indicating view not set before starting stream. */
+    VIEW_NOT_SET,
+
+    /**
+     * Error indicating system does not currently have enough resources to
+     * allocate for a new requested session.
+     * Clients may retry request for session if resources become available.
+     */
+    NO_RESOURCE,
+
+    /** Internal error in surround view service. */
+    INTERNAL_ERROR,
+};
+
+/**
+ * Enumerator listing events for surround view.
+ */
+enum SvEvent : uint32_t {
+    STREAM_STARTED = 1,
+
+    STREAM_STOPPED,
+
+    /**
+     * Event sent after service switches to an updated config, all frames
+     * streamed after this event are of the updated config.
+     */
+    CONFIG_UPDATED,
+
+    /** Each frame dropped will be notified with this event. */
+    FRAME_DROPPED,
+
+    /**
+     * Timeout event occurs if any individual camera stream has a timeout.
+     * Frames will not be delivered and clients must stop the stream.
+     */
+    TIMEOUT,
+};
+
+/**
+ * Structure defining the mapping information for 2d surround view.
+ *
+ * Mapping information provides the area on ground (width and height) and
+ * position w.r.t the car that the surround view 2d covers. This can be used for
+ * mapping (linear transformation) with other sensors whose data is available in
+ * the car coordinate system (eg. Ultrasonics).
+ * Axes and origin are as per the android automotive axes:
+ * https://source.android.com/devices/sensors/sensor-types#auto_axes
+ */
+struct Sv2dMappingInfo {
+    /** Width in milli-meters of the 2d surround view along the ground plane. */
+    float width;
+
+    /** Height in milli-meters of the 2d surround view along the ground plane. */
+    float height;
+
+    /**
+     * Coordinates (x, y) of the center of the view in android automotive coordinate system on the
+     * ground plane. Units are milli-meters.
+     */
+    Point2dFloat center;
+};
+
+/**
+ * Enumerator for quality presets for 2d/3d surround view.
+ * Details of each preset are specified in the respective 2d/3d config structures.
+ */
+enum SvQuality : uint32_t {
+    HIGH = 0,
+    LOW,
+};
+
+/** Structure for surround view 2d configuration. */
+struct Sv2dConfig {
+    /**
+     * Desired output width in pixels. Must be in range (0, 4096].
+     * Height is computed keeping the aspect ratio of the mapping info,
+     * Example: If width = 1080 px and mapping_width = 5000 mm, mapping_height = 10000 mm.
+     *          then, height = width * (mapping_height / mapping_width) = 2160 px.
+     * Height is set to the floor value in case of (mapping_height / mapping_width) is not integer.
+     * Mapping width, height is fixed for a car and is based on camera parameters and their ground
+     * coverage.
+     */
+    uint32_t width;
+
+    /**
+     * Blending quality preset to use.
+     * HIGH: High quality blending (eg. multiband blending) that consumes more resources.
+     * LOW: Low quality blending (eg. alpha blending) that consumes less resources.
+     */
+    SvQuality blending;
+};
+
+/** Structure for surround view 3d configuration. */
+struct Sv3dConfig {
+    /** Desired output width in pixels. Must be in range (0, 4096]. */
+    uint32_t width;
+
+    /** Desired output height in pixels. Must be in range (0, 4096]. */
+    uint32_t height;
+
+    /**
+     * Car model rendering details level.
+     * HIGH: Rendering includes shadows and reflections. Default option.
+     * LOW: Rendering with no shadows and reflections.
+     */
+    SvQuality carDetails;
+};
+
+/**
+ * Enumerator for a list of overlay primitives.
+ *
+ * Given a list of vertices for an overlay, a primitive type defines which vertices are used to form
+ * the surfaces of the overlay object.
+ */
+enum OverlayPrimitive : uint32_t {
+    /**
+     * Consecutive vertices picked in order 3 at a time form a triangle.
+     * Eg: In a list of vertices (V1, V2, V3, V4, V5, V6)
+     * (V1, V2, V3) form a triangle and (V4, V5, V6) form a triangle.
+     */
+    TRIANGLES = 0,
+
+    /**
+     * Every 3 consecutive vertices form a triangle.
+     * Example in a list of vertices V1, V2, V3, V4, V5, V6
+     * (V1, V2, V3), (V2, V3, V4), (V3, V4, V5) and (V4, V5, V6) form triangles.
+     */
+    TRIANGLES_STRIP,
+};
+
+/**
+ * Structure identifying an overlay and describing the size and arrangement of its data in
+ * shared memory.
+ */
+struct OverlayMemoryDesc {
+    /** Identifier of the overlay. */
+    uint16_t id;
+
+    /** Number of vertices in the overlay. */
+    uint32_t verticesCount;
+
+    /** Primitive for the overlay. */
+    OverlayPrimitive overlayPrimitive;
+};
+
+/**
+ *  Structure containing the overlays data in shared memory.
+ */
+struct OverlaysData {
+    /** List of overlay memory descriptors, describing the data in the shared memory */
+    vec<OverlayMemoryDesc> overlaysMemoryDesc;
+
+    /**
+     * Shared memory object containing a list of vertices for each overlay as described by
+     * overlaysMemoryDesc.
+     *
+     * Each vertex comprises of:
+     * | PositionX | PositionY | PositionZ |   RGBA       |
+     * |   float   |   float   |   float   |  4 * uint8_t |
+     *
+     * Each vertex is of 3 floats and 4 bytes = 16 bytes.
+     *
+     * Layout of vertices in shared memory is in order:
+     *
+     * Bytes: | 0-1 | 2-18 | 19-34 | 35-50 | 51-66 | 67-68 | 69-84 | 85-100 | 101-116  |...
+     * Data:  | id1 |  V1  |  V2   |   V3  |   V4  |  id2  |   V1  |   V2   |  V3      |...
+     *        |           overlay1                 |          overlay 2                |
+     *
+     * The order of overlays must match the order as specified in the overlaysMemoryDesc.
+     * The number of vertices each overlay has must match the verticesCount in overlaysMemoryDesc.
+     * The id must match the id specificed in the OverlayMemoryDesc. This is used for verification.
+     * For each overlay the number of vertices must be 3 or greater.
+     * For TRIANGLES primitive the number of vertices must be a multiple of 3.
+     * The overlay vertices are grouped as per the overlayPrimitive specified in overlaysMemoryDesc,
+     * eg: If primitive is TRIANGLES, (V1, V2, V3) and (V4, V5, V6) form a triangle.
+     */
+    memory overlaysMemory;
+};
diff --git a/automotive/sv/1.0/vts/functional/Android.bp b/automotive/sv/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..0e5d3df
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/Android.bp
@@ -0,0 +1,41 @@
+//
+// 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_test {
+    name: "VtsHalSurroundViewV1_0TargetTest",
+    srcs: [
+        "VtsHalSurroundViewV1_0TargetTest.cpp",
+        "SurroundViewStreamHandler.cpp",
+    ],
+    defaults: ["VtsHalTargetTestDefaults"],
+    static_libs: [
+        "libnativewindow",
+        "android.hardware.automotive.sv@1.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+    ],
+    shared_libs: [
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+    ],
+    test_suites: ["general-tests", "vts-core"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp
new file mode 100644
index 0000000..cb45caa
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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 "SurroundViewStreamHandler.h"
+
+#include <utils/Log.h>
+
+using std::lock_guard;
+
+SurroundViewServiceHandler::SurroundViewServiceHandler(sp<ISurroundViewSession> pSession) :
+    mSession(pSession),
+    mReceiveFramesCount(0),
+    mDoNotReturnFrames(false) {
+    // Nothing but member initialization
+}
+
+Return<void> SurroundViewServiceHandler::notify(SvEvent svEvent) {
+    ALOGD("SurroundViewServiceHandler::notify %d", svEvent);
+
+    lock_guard<mutex> lock(mLock);
+    switch (svEvent) {
+        case SvEvent::STREAM_STARTED:
+        case SvEvent::CONFIG_UPDATED:
+        case SvEvent::STREAM_STOPPED:
+        case SvEvent::FRAME_DROPPED:
+        case SvEvent::TIMEOUT:
+            mReceivedEvents.emplace_back(svEvent);
+            break;
+        default:
+            ALOGI("[SurroundViewLog] Received other event");
+    }
+
+    return android::hardware::Void();
+}
+
+Return<void> SurroundViewServiceHandler::receiveFrames(const SvFramesDesc& svFramesDesc) {
+    ALOGD("SurroundViewServiceHandler::receiveFrames");
+
+    lock_guard<mutex> lock(mLock);
+    unsigned long timestampNs = svFramesDesc.timestampNs;
+    unsigned sequenceId = svFramesDesc.sequenceId;
+    ALOGD("receiveFrames count: %d", mReceiveFramesCount);
+    ALOGD("timestampNs: %lu, sequenceId: %u", timestampNs, sequenceId);
+    if (mReceiveFramesCount != 0
+        && (mLastReceivedFrames.timestampNs >= svFramesDesc.timestampNs
+            || mLastReceivedFrames.sequenceId >= svFramesDesc.sequenceId)) {
+        mAllFramesValid = false;
+        ALOGD("The incoming frames are with invalid timestamp or sequenceId!");
+    }
+
+    for (int i=0; i<svFramesDesc.svBuffers.size(); i++) {
+        if (svFramesDesc.svBuffers[i].hardwareBuffer.nativeHandle == nullptr) {
+            mAllFramesValid = false;
+            ALOGD("The incoming frames are with invalid nativeHandle!");
+            break;
+        }
+    }
+
+    mReceiveFramesCount++;
+
+    // Store all the information except for the handle
+    mLastReceivedFrames.timestampNs = svFramesDesc.timestampNs;
+    mLastReceivedFrames.sequenceId = svFramesDesc.sequenceId;
+    mLastReceivedFrames.svBuffers.resize(svFramesDesc.svBuffers.size());
+    for (int i=0; i<svFramesDesc.svBuffers.size(); i++) {
+        mLastReceivedFrames.svBuffers[i].viewId = svFramesDesc.svBuffers[i].viewId;
+        mLastReceivedFrames.svBuffers[i].hardwareBuffer.description =
+            svFramesDesc.svBuffers[i].hardwareBuffer.description;
+    }
+
+    if (!mDoNotReturnFrames) {
+        mSession->doneWithFrames(svFramesDesc);
+    }
+
+    return android::hardware::Void();
+}
+
+bool SurroundViewServiceHandler::checkEventReceived(SvEvent svEvent) {
+    ALOGD("SurroundViewServiceHandler::checkEventReceived");
+    int size = mReceivedEvents.size(); // work around
+    ALOGD("Received event number: %d", size);
+    auto iter = find(mReceivedEvents.begin(), mReceivedEvents.end(), svEvent);
+    return iter != mReceivedEvents.end();
+}
+
+SvFramesDesc SurroundViewServiceHandler::getLastReceivedFrames() {
+    return mLastReceivedFrames;
+}
+
+int SurroundViewServiceHandler::getReceiveFramesCount() {
+    return mReceiveFramesCount;
+}
+
+bool SurroundViewServiceHandler::areAllFramesValid() {
+    return mAllFramesValid;
+}
+
+void SurroundViewServiceHandler::setDoNotReturnFrames(bool flag) {
+    mDoNotReturnFrames = flag;
+}
diff --git a/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h
new file mode 100644
index 0000000..7d3f61d
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h
@@ -0,0 +1,57 @@
+/*
+ * 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 SURROUND_VIEW_STREAM_HANDLER_H
+#define SURROUND_VIEW_STREAM_HANDLER_H
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewSession.h>
+
+#include <thread>
+#include <vector>
+
+using std::vector;
+using std::mutex;
+using android::hardware::Return;
+using android::sp;
+using namespace ::android::hardware::automotive::sv::V1_0;
+
+class SurroundViewServiceHandler : public ISurroundViewStream {
+public:
+    SurroundViewServiceHandler(sp<ISurroundViewSession> session);
+
+    Return<void> notify(SvEvent svEvent) override;
+    Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
+
+    bool checkEventReceived(SvEvent svEvent);
+    SvFramesDesc getLastReceivedFrames();
+    int getReceiveFramesCount();
+    bool areAllFramesValid();
+    void setDoNotReturnFrames(bool flag);
+
+private:
+    mutex mLock;
+
+    vector<SvEvent> mReceivedEvents;
+    sp<ISurroundViewSession> mSession;
+    SvFramesDesc mLastReceivedFrames; // only use timestampNs and sequenceId
+    int mReceiveFramesCount; // TODO(haoxiangl): figure out a better name
+    bool mAllFramesValid = true;
+    bool mDoNotReturnFrames;
+};
+
+#endif //SURROUND_VIEW_STREAM_HANDLER_H
diff --git a/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
new file mode 100644
index 0000000..b1b9d16
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
@@ -0,0 +1,1137 @@
+//
+// 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 "VtsHalSurroundViewTest"
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <android/hardware_buffer.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+#include <math.h>
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "SurroundViewStreamHandler.h"
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::hidl_memory;
+
+const int kVertexByteSize = (3 * sizeof(float)) + 4;
+const int kIdByteSize = 2;
+
+// The main test class for Surround View Service
+class SurroundViewHidlTest : public ::testing::TestWithParam<std::string> {
+public:
+    virtual void SetUp() override {
+        mSurroundViewService = ISurroundViewService::getService(GetParam());
+        ASSERT_NE(mSurroundViewService.get(), nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+    sp<ISurroundViewService> mSurroundViewService;    // Every test needs access to the service
+};
+
+TEST_P(SurroundViewHidlTest, startAndStop2dSession) {
+    ALOGD("SurroundViewHidlTest::startAndStop2dSession");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    SvResult result = mSurroundViewService->stop2dSession(surroundView2dSession);
+    ASSERT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, stopInvalid2dSession) {
+    ALOGD("SurroundViewHidlTest::stopInvalid2dSession");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    SvResult result = mSurroundViewService->stop2dSession(surroundView2dSession);
+    ASSERT_NE(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, startAndStop2dStream) {
+    ALOGD("SurroundViewHidlTest::startAndStop2dStream");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+    surroundView2dSession->stopStream();
+
+    sleep(1);
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+    result = mSurroundViewService->stop2dSession(surroundView2dSession);
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, start2dStreamWithoutReturningFrames) {
+    ALOGD("SurroundViewHidlTest::start2dStreamWithoutReturningFrames");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+    handler->setDoNotReturnFrames(true);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::FRAME_DROPPED));
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+    surroundView2dSession->stopStream();
+
+    sleep(1);
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+    result = mSurroundViewService->stop2dSession(surroundView2dSession);
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, duplicateStart2dStream) {
+    ALOGD("SurroundViewHidlTest, duplicateStart2dStream");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    result = surroundView2dSession->startStream(handler);
+    EXPECT_NE(result, SvResult::OK);
+
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, stopInvalid2dStream) {
+    ALOGD("SurroundViewHidlTest, stopInvalid2dStream");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, validate2dSvFramesDesc) {
+    ALOGD("SurroundViewHidlTest, validate2dSvFramesDesc");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    // Validate timestampNs and sequenceId
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+    EXPECT_TRUE(handler->areAllFramesValid());
+
+    // Validate 2d SvFramesDesc. Do not compare nativeHandle since it is not
+    // stored and already verified on the fly.
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+
+    SvBuffer svBuffer2d = frames.svBuffers[0];
+    EXPECT_EQ(svBuffer2d.viewId, 0);
+
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+    float mapWidth, mapHeight;
+    surroundView2dSession->get2dMappingInfo([&mapWidth, &mapHeight] (Sv2dMappingInfo info) {
+        mapWidth = info.width;
+        mapHeight = info.height;
+    });
+    EXPECT_EQ(pDesc->height, floor(pDesc->width * (mapHeight / mapWidth)));
+
+    // Clean up
+    surroundView2dSession->stopStream();
+    result = mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, get2dMappingInfo) {
+    ALOGD("SurroundViewHidlTest, get2dMappingInfo");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    surroundView2dSession->get2dMappingInfo([] (Sv2dMappingInfo info) {
+        EXPECT_GT(info.width, 0);
+        EXPECT_GT(info.height, 0);
+    });
+
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set2dConfigResolution) {
+    ALOGD("SurroundViewHidlTest, set2dConfigResolution");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Change config
+    Sv2dConfig config;
+    config.width = 1920;
+    config.blending = SvQuality::HIGH;
+    surroundView2dSession->set2dConfig(config);
+
+    sleep(1);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+    // Check width has been changed but not the ratio
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer2d = frames.svBuffers[0];
+    EXPECT_EQ(svBuffer2d.viewId, 0);
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+    EXPECT_EQ(pDesc->width, config.width);
+
+    float mapWidth, mapHeight;
+    surroundView2dSession->get2dMappingInfo([&mapWidth, &mapHeight] (Sv2dMappingInfo info) {
+        mapWidth = info.width;
+        mapHeight = info.height;
+    });
+    EXPECT_EQ(pDesc->height, floor (pDesc->width * (mapHeight / mapWidth)));
+
+    // Clean up
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set2dConfigBlending) {
+    ALOGD("SurroundViewHidlTest, set2dConfigBlending");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Get the width before config changed
+    int oldWidth;
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer2d = frames.svBuffers[0];
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+    oldWidth = pDesc->width;
+
+    // Change config
+    Sv2dConfig config;
+    config.width = oldWidth;
+    config.blending = SvQuality::LOW;
+    surroundView2dSession->set2dConfig(config);
+
+    sleep(1);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+    Sv2dConfig retConfig;
+    surroundView2dSession->get2dConfig([&retConfig] (Sv2dConfig config) {
+        retConfig.width = config.width;
+        retConfig.blending = config.blending;
+    });
+
+    // Check config blending has been changed but not the width
+    EXPECT_EQ(retConfig.blending, config.blending);
+    EXPECT_EQ(retConfig.width, oldWidth);
+
+    // Clean up
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectCameraPointsWithValidCameraId) {
+    ALOGD("SurroundViewHidlTest, projectCameraPointsWithValidCameraId");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    hidl_vec<hidl_string> cameraIds;
+    mSurroundViewService->getCameraIds([&cameraIds](
+            const hidl_vec<hidl_string>& camIds) {
+        cameraIds = camIds;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Get the width and height of the frame
+    int width, height;
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer2d = frames.svBuffers[0];
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+    width = pDesc->width;
+    height = pDesc->height;
+
+    float mapWidth, mapHeight, mapCenter[2];
+    surroundView2dSession->get2dMappingInfo(
+        [&mapWidth, &mapHeight, &mapCenter] (Sv2dMappingInfo info) {
+        mapWidth = info.width;
+        mapHeight = info.height;
+        mapCenter[0] = info.center.x;
+        mapCenter[1] = info.center.y;
+    });
+
+    // Set one valid point and one invalid point
+    hidl_vec<Point2dInt> points2dCamera;
+    points2dCamera.resize(2);
+    points2dCamera[0].x = 0;
+    points2dCamera[0].y = 0;
+    points2dCamera[1].x = width * 2;
+    points2dCamera[1].y = height * 2;
+
+    surroundView2dSession->projectCameraPoints(
+        points2dCamera,
+        cameraIds[0],
+        [&mapWidth, &mapHeight, &mapCenter] (
+            const hidl_vec<Point2dFloat>& outPoints) {
+            // Make sure point[0] is valid.
+            EXPECT_TRUE(outPoints[0].isValid);
+            EXPECT_GE(outPoints[0].x, mapCenter[0] - mapWidth);
+            EXPECT_LE(outPoints[0].x, mapCenter[0] + mapWidth);
+            EXPECT_GE(outPoints[0].y, mapCenter[1] - mapHeight);
+            EXPECT_LE(outPoints[0].y, mapCenter[1] + mapHeight);
+
+            // Make sure point[1] is invalid.
+            EXPECT_FALSE(outPoints[1].isValid);
+        });
+
+    // Clean up
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectCameraPointsWithInvalidCameraId) {
+    ALOGD("SurroundViewHidlTest, projectCameraPointsWithInvalidCameraId");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    hidl_vec<hidl_string> cameraIds;
+    mSurroundViewService->getCameraIds([&cameraIds](
+            const hidl_vec<hidl_string>& camIds) {
+        cameraIds = camIds;
+    });
+
+    hidl_string invalidCameraId = "INVALID_CAMERA_ID";
+
+    // In case one of the camera id happens to be identical to
+    // the invalid camera id.
+    for (auto cameraId : cameraIds) {
+        ASSERT_NE(cameraId, invalidCameraId);
+    }
+
+    // Set one valid point
+    hidl_vec<Point2dInt> points2dCamera;
+    points2dCamera.resize(1);
+    points2dCamera[0].x = 0;
+    points2dCamera[0].y = 0;
+
+    surroundView2dSession->projectCameraPoints(
+        points2dCamera,
+        invalidCameraId,
+        [] (const hidl_vec<Point2dFloat>& outPoints) {
+            // No points are return due to invalid camera id
+            EXPECT_EQ(outPoints.size(), 0);
+        });
+
+    // Clean up
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, startAndStop3dSession) {
+    ALOGD("SurroundViewHidlTest, startAndStop3dSession");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    SvResult result = mSurroundViewService->stop3dSession(surroundView3dSession);
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, stopInvalid3dSession) {
+    ALOGD("SurroundViewHidlTest, stopInvalid3dSession");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    SvResult result = mSurroundViewService->stop3dSession(surroundView3dSession);
+    EXPECT_NE(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, startAndStop3dStream) {
+    ALOGD("SurroundViewHidlTest::startAndStop3dStream");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::vector<View3d> views(1);
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+    surroundView3dSession->stopStream();
+
+    sleep(1);
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+    result = mSurroundViewService->stop3dSession(surroundView3dSession);
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, start3dStreamWithoutReturningFrames) {
+    ALOGD("SurroundViewHidlTest::start3dStreamWithoutReturningFrames");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::vector<View3d> views(1);
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+    handler->setDoNotReturnFrames(true);
+
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::FRAME_DROPPED));
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+    surroundView3dSession->stopStream();
+
+    sleep(1);
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+    result = mSurroundViewService->stop3dSession(surroundView3dSession);
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, duplicateStart3dStream) {
+    ALOGD("SurroundViewHidlTest, duplicateStart3dStream");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::vector<View3d> views(1);
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    result = surroundView3dSession->startStream(handler);
+    EXPECT_NE(result, SvResult::OK);
+
+    surroundView3dSession->stopStream();
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, start3dStreamNoViewSetFail) {
+    ALOGD("SurroundViewHidlTest, start3dStreamNoViewSetFail");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::VIEW_NOT_SET);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, validate3dSvFramesDesc) {
+    ALOGD("SurroundViewHidlTest, validate3dSvFramesDesc");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    std::vector<View3d> views(1);
+    views[0].viewId = 0;
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+    EXPECT_TRUE(handler->areAllFramesValid());
+
+    // Validate 3d SvFramesDesc when only one view is set.
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    EXPECT_EQ(frames.svBuffers[0].viewId, 0);
+
+    views.resize(3);
+    views[0].viewId = 0;
+    views[1].viewId = 1;
+    views[2].viewId = 2;
+    setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+
+    sleep(1);
+
+    // Validate 3d SvFramesDesc when multiple views are set.
+    EXPECT_TRUE(handler->areAllFramesValid());
+    frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 3);
+    EXPECT_EQ(frames.svBuffers[0].viewId, 0);
+    EXPECT_EQ(frames.svBuffers[1].viewId, 1);
+    EXPECT_EQ(frames.svBuffers[2].viewId, 2);
+    EXPECT_EQ(frames.svBuffers[0].hardwareBuffer.description[0],
+              frames.svBuffers[1].hardwareBuffer.description[0]);
+    EXPECT_EQ(frames.svBuffers[0].hardwareBuffer.description[1],
+              frames.svBuffers[1].hardwareBuffer.description[1]);
+    EXPECT_EQ(frames.svBuffers[1].hardwareBuffer.description[0],
+              frames.svBuffers[2].hardwareBuffer.description[0]);
+    EXPECT_EQ(frames.svBuffers[1].hardwareBuffer.description[1],
+              frames.svBuffers[2].hardwareBuffer.description[1]);
+
+    // Clean up
+    surroundView3dSession->stopStream();
+    result = mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set3dConfigResolution) {
+    ALOGD("SurroundViewHidlTest, set3dConfigResolution");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    std::vector<View3d> views(1);
+    views[0].viewId = 0;
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Change config
+    Sv3dConfig config;
+    config.width = 1920;
+    config.height = 1080;
+    config.carDetails = SvQuality::HIGH;
+    surroundView3dSession->set3dConfig(config);
+
+    sleep(1);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+    // Check width has been changed but not the ratio
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer3d = frames.svBuffers[0];
+    EXPECT_EQ(svBuffer3d.viewId, 0);
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer3d.hardwareBuffer.description);
+    EXPECT_EQ(pDesc->width, config.width);
+    EXPECT_EQ(pDesc->height, config.height);
+
+    // Clean up
+    surroundView3dSession->stopStream();
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set3dConfigCarDetails) {
+    ALOGD("SurroundViewHidlTest, set3dConfigCarDetails");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    std::vector<View3d> views(1);
+    views[0].viewId = 0;
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Get the width before config changed
+    int oldWidth, oldHeight;
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer3d = frames.svBuffers[0];
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer3d.hardwareBuffer.description);
+    oldWidth = pDesc->width;
+    oldHeight = pDesc->height;
+
+    // Change config
+    Sv3dConfig config;
+    config.width = oldWidth;
+    config.height = oldHeight;
+    config.carDetails = SvQuality::LOW;
+    surroundView3dSession->set3dConfig(config);
+
+    sleep(1);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+    Sv3dConfig retConfig;
+    surroundView3dSession->get3dConfig([&retConfig] (Sv3dConfig config) {
+        retConfig.width = config.width;
+        retConfig.height = config.height;
+        retConfig.carDetails = config.carDetails;
+    });
+
+    // Check config blending has been changed but not the width
+    EXPECT_EQ(retConfig.carDetails, config.carDetails);
+    EXPECT_EQ(retConfig.width, oldWidth);
+    EXPECT_EQ(retConfig.height, oldHeight);
+
+    // Clean up
+    surroundView3dSession->stopStream();
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+std::pair<hidl_memory, sp<IMemory>> GetMappedSharedMemory(int bytesSize) {
+
+    const auto nullResult = std::make_pair(hidl_memory(), nullptr);
+
+    sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
+    if (ashmemAllocator.get() == nullptr) {
+        ALOGE("SurroundViewHidlTest getService ashmem failed");
+        return nullResult;
+    }
+
+    // Allocate shared memory.
+    hidl_memory hidlMemory;
+    bool allocateSuccess = false;
+    Return<void> result = ashmemAllocator->allocate(bytesSize,
+            [&](bool success, const hidl_memory& hidlMem) {
+                if (!success) {
+                    return;
+                }
+                allocateSuccess = success;
+                hidlMemory = hidlMem;
+            });
+
+    // Check result of allocated memory.
+    if (!result.isOk() || !allocateSuccess) {
+        ALOGE("SurroundViewHidlTest allocate shared memory failed");
+        return nullResult;
+    }
+
+    // Map shared memory.
+    sp<IMemory> pIMemory = mapMemory(hidlMemory);
+    if (pIMemory.get() == nullptr) {
+        ALOGE("SurroundViewHidlTest map shared memory failed");
+        return nullResult;
+    }
+
+    return std::make_pair(hidlMemory, pIMemory);
+}
+
+void SetIndexOfOverlaysMemory(
+        const std::vector<OverlayMemoryDesc>& overlaysMemDesc,
+        sp<IMemory> pIMemory, int indexPosition, uint16_t indexValue) {
+
+    // Count the number of vertices until the index.
+    int totalVerticesCount = 0;
+    for (int i = 0; i < indexPosition; i++) {
+        totalVerticesCount += overlaysMemDesc[i].verticesCount;
+    }
+
+    const int indexBytePosition = (indexPosition * kIdByteSize) +
+            (kVertexByteSize * totalVerticesCount);
+
+    uint8_t* pSharedMemoryData = (uint8_t*)((void*)pIMemory->getPointer());
+    pSharedMemoryData += indexBytePosition;
+    uint16_t* pIndex16bit = (uint16_t*)pSharedMemoryData;
+
+    ALOGD("Setting index at pos %d", indexBytePosition);
+
+    // Modify shared memory.
+    pIMemory->update();
+    *pIndex16bit = indexValue;
+    pIMemory->commit();
+}
+
+std::pair<OverlaysData, sp<IMemory>> GetSampleOverlaysData() {
+    OverlaysData overlaysData;
+    overlaysData.overlaysMemoryDesc.resize(2);
+
+    int sharedMemBytesSize = 0;
+    OverlayMemoryDesc overlayMemDesc1, overlayMemDesc2;
+    overlayMemDesc1.id = 0;
+    overlayMemDesc1.verticesCount = 6;
+    overlayMemDesc1.overlayPrimitive = OverlayPrimitive::TRIANGLES;
+    overlaysData.overlaysMemoryDesc[0] = overlayMemDesc1;
+    sharedMemBytesSize += kIdByteSize +
+            kVertexByteSize * overlayMemDesc1.verticesCount;
+
+    overlayMemDesc2.id = 1;
+    overlayMemDesc2.verticesCount = 4;
+    overlayMemDesc2.overlayPrimitive = OverlayPrimitive::TRIANGLES_STRIP;
+    overlaysData.overlaysMemoryDesc[1] = overlayMemDesc2;
+    sharedMemBytesSize += kIdByteSize +
+            kVertexByteSize * overlayMemDesc2.verticesCount;
+
+    std::pair<hidl_memory, sp<IMemory>> sharedMem =
+            GetMappedSharedMemory(sharedMemBytesSize);
+    sp<IMemory> pIMemory = sharedMem.second;
+    if (pIMemory.get() == nullptr) {
+        return std::make_pair(OverlaysData(), nullptr);
+    }
+
+    // Get pointer to shared memory data and set all bytes to 0.
+    uint8_t* pSharedMemoryData = (uint8_t*)((void*)pIMemory->getPointer());
+    pIMemory->update();
+    memset(pSharedMemoryData, 0, sharedMemBytesSize);
+    pIMemory->commit();
+
+    std::vector<OverlayMemoryDesc> overlaysDesc = {overlayMemDesc1,
+            overlayMemDesc2};
+
+    // Set indexes in shared memory.
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 0, overlayMemDesc1.id);
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, overlayMemDesc2.id);
+
+    overlaysData.overlaysMemoryDesc = overlaysDesc;
+    overlaysData.overlaysMemory = sharedMem.first;
+
+    return std::make_pair(overlaysData, pIMemory);
+}
+
+TEST_P(SurroundViewHidlTest, updateOverlaysSuccess) {
+    ALOGD("SurroundViewHidlTest, updateOverlaysSuccess");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::pair<OverlaysData, sp<IMemory>> overlaysData = GetSampleOverlaysData();
+    ASSERT_NE(overlaysData.second, nullptr);
+
+    SvResult result = surroundView3dSession->updateOverlays(overlaysData.first);
+    EXPECT_EQ(result, SvResult::OK);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataMismatchIdFail) {
+    ALOGD("SurroundViewHidlTest, overlaysDataMismatchIdFail");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::pair<OverlaysData, sp<IMemory>> overlaysDataMismatchId
+            = GetSampleOverlaysData();
+    ASSERT_NE(overlaysDataMismatchId.second, nullptr);
+
+    // Set id of second overlay in shared memory to 2 (expected is 1).
+    auto& overlaysDesc = overlaysDataMismatchId.first.overlaysMemoryDesc;
+    auto& pIMemory = overlaysDataMismatchId.second;
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, 2);
+
+    SvResult result = surroundView3dSession->updateOverlays(
+            overlaysDataMismatchId.first);
+    EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataNullMemoryFail) {
+    ALOGD("SurroundViewHidlTest, overlaysDataNullMemoryFail");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::pair<OverlaysData, sp<IMemory>> overlaysDataNullMemory
+            = GetSampleOverlaysData();
+
+    // Set shared memory to null.
+    overlaysDataNullMemory.first.overlaysMemory = hidl_memory();
+
+    SvResult result = surroundView3dSession->updateOverlays(
+            overlaysDataNullMemory.first);
+    EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataLessThan3VerticesFail) {
+    ALOGD("SurroundViewHidlTest, overlaysDataLessThan3VerticesFail");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::pair<OverlaysData, sp<IMemory>> overlaysData2Vertices
+            = GetSampleOverlaysData();
+
+    // Set vertices count of second overlay to 2.
+    overlaysData2Vertices.first.overlaysMemoryDesc[1].verticesCount = 2;
+
+    SvResult result = surroundView3dSession->updateOverlays(
+            overlaysData2Vertices.first);
+    EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataVerticesCountFail) {
+    ALOGD("SurroundViewHidlTest, overlaysDataVerticesNotMultipleOf3Fail");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    OverlaysData overlaysData;
+    overlaysData.overlaysMemoryDesc.resize(1);
+
+    OverlayMemoryDesc overlayMemDesc1;
+    overlayMemDesc1.id = 0;
+    overlayMemDesc1.verticesCount = 4; // Invalid count for TRIANGLES primitive.
+    overlayMemDesc1.overlayPrimitive = OverlayPrimitive::TRIANGLES;
+    overlaysData.overlaysMemoryDesc[0] = overlayMemDesc1;
+
+    const int sharedMemBytesSize =
+            2 + sizeof(float) * overlayMemDesc1.verticesCount;
+    auto sharedMem = GetMappedSharedMemory(sharedMemBytesSize);
+
+    // Set index in shared memory.
+    auto& overlaysDesc = overlaysData.overlaysMemoryDesc;
+    auto& pIMemory = sharedMem.second;
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 0, overlayMemDesc1.id);
+
+    SvResult result = surroundView3dSession->updateOverlays(overlaysData);
+    EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataSameIdFail) {
+    ALOGD("SurroundViewHidlTest, overlaysDataSameIdFail");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::pair<OverlaysData, sp<IMemory>> overlaysDataSameId
+            = GetSampleOverlaysData();
+    ASSERT_NE(overlaysDataSameId.second, nullptr);
+
+    // Set id of second overlay as id of first.
+    auto& overlaysDesc = overlaysDataSameId.first.overlaysMemoryDesc;
+        auto& pIMemory = overlaysDataSameId.second;
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, overlaysDesc[0].id);
+
+    SvResult result = surroundView3dSession->updateOverlays(
+            overlaysDataSameId.first);
+    EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectPointsIncorrectCameraIdFail) {
+    ALOGD("SurroundViewHidlTest, projectPointsIncorrectCameraIdFail");
+
+    hidl_vec<hidl_string> cameraIds;
+    mSurroundViewService->getCameraIds([&cameraIds](
+            const hidl_vec<hidl_string>& camIds) {
+        cameraIds = camIds;
+    });
+    EXPECT_GT(cameraIds.size(), 0);
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    Point2dInt cameraPoint;
+    cameraPoint.x = 0;
+    cameraPoint.y = 0;
+    std::vector<Point2dInt> cameraPoints = {cameraPoint};
+
+    hidl_string invalidCameraId = "INVALID_CAMERA_ID";
+
+    std::vector<Point3dFloat> points3d;
+    surroundView3dSession->projectCameraPointsTo3dSurface(
+        cameraPoints, invalidCameraId,
+        [&points3d](const hidl_vec<Point3dFloat>& points3dproj) {
+                points3d = points3dproj;
+            });
+
+    EXPECT_TRUE(points3d.empty());
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectPointsInvalidPointsFail) {
+    ALOGD("SurroundViewHidlTest, projectPointsInvalidPointsFail");
+
+    hidl_vec<hidl_string> cameraIds;
+    mSurroundViewService->getCameraIds([&cameraIds](
+            const hidl_vec<hidl_string>& camIds) {
+        cameraIds = camIds;
+    });
+
+    EXPECT_GT(cameraIds.size(), 0);
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    std::vector<View3d> views(1);
+    views[0].viewId = 0;
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Get the width and height of the frame
+    int width, height;
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer2d = frames.svBuffers[0];
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+    width = pDesc->width;
+    height = pDesc->height;
+
+    Point2dInt cameraPoint;
+    cameraPoint.x = width * 2;
+    cameraPoint.y = height * 2;
+    std::vector<Point2dInt> cameraPoints = {cameraPoint};
+
+    std::vector<Point3dFloat> points3d;
+    surroundView3dSession->projectCameraPointsTo3dSurface(
+              cameraPoints, cameraIds[0],
+        [&points3d](const hidl_vec<Point3dFloat>& points3dproj) {
+                points3d = points3dproj;
+            });
+
+    EXPECT_FALSE(points3d[0].isValid);
+
+    surroundView3dSession->stopStream();
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance,
+    SurroundViewHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(ISurroundViewService::descriptor)
+    ),
+    android::hardware::PrintInstanceNameToString
+);
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index e325889..8e57901 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -85,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,
@@ -153,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 fb02c58..0000000
--- a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <android-base/logging.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;
-
-    auto serverInfo = vhal_impl::VsockServerInfo::fromCommandLine(argc, argv);
-    CHECK(serverInfo.has_value()) << "Invalid server CID/port combination";
-
-    auto server = vhal_impl::makeGrpcVehicleServer(serverInfo->toUri());
-    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 68813c9..0000000
--- a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp
+++ /dev/null
@@ -1,56 +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 <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[]) {
-    namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl;
-
-    auto serverInfo = vhal_impl::VsockServerInfo::fromRoPropertyStore();
-    CHECK(serverInfo.has_value()) << "Invalid server CID/port combination";
-
-    auto store = std::make_unique<VehiclePropertyStore>();
-    auto connector = impl::makeGrpcVehicleClient(serverInfo->toUri());
-    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 1101b08..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:-pleaseconfigurethis} \
-        -server_port ${ro.vendor.vehiclehal.server.port:-pleaseconfigurethis}
-    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/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 785f0e0..4b94800 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
@@ -70,6 +70,7 @@
     (int)(0x104 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::STRING | VehicleArea::GLOBAL);
 constexpr int FUEL_DOOR_REAR_LEFT = (int)PortLocationType::REAR_LEFT;
 constexpr int CHARGE_PORT_FRONT_LEFT = (int)PortLocationType::FRONT_LEFT;
+constexpr int CHARGE_PORT_REAR_LEFT = (int)PortLocationType::REAR_LEFT;
 constexpr int LIGHT_STATE_ON = (int)VehicleLightState::ON;
 constexpr int LIGHT_SWITCH_AUTO = (int)VehicleLightSwitch::AUTOMATIC;
 constexpr int WHEEL_FRONT_LEFT = (int)VehicleAreaWheel::LEFT_FRONT;
@@ -249,6 +250,14 @@
 
         {.config =
                  {
+                         .prop = toInt(VehicleProperty::INFO_MULTI_EV_PORT_LOCATIONS),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                 },
+         .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT, CHARGE_PORT_REAR_LEFT}}},
+
+        {.config =
+                 {
                          .prop = toInt(VehicleProperty::INFO_MAKE),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
@@ -457,6 +466,14 @@
                  },
          .initialValue = {.int32Values = {0, 0, 0}}},
 
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::HW_ROTARY_INPUT),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.int32Values = {0, 0, 0}}},
+
         {.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON),
                     .access = VehiclePropertyAccess::READ_WRITE,
                     .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
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 63ad93c..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
@@ -311,6 +311,11 @@
     // (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));
@@ -318,10 +323,6 @@
     }
     LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value);
 
-    if (value.value.int32Values.size() == 0) {
-        LOG(ERROR) << "invalid request (no requestId): " << toString(value);
-        return StatusCode::INVALID_ARG;
-    }
     int32_t requestId = value.value.int32Values[0];
 
     // Create the update property and set common values
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 184d8a4..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp
+++ /dev/null
@@ -1,115 +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 <cutils/properties.h>
-
-#include <getopt.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sstream>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-namespace impl {
-
-std::string VsockServerInfo::toUri() {
-    std::stringstream uri_stream;
-    uri_stream << "vsock:" << serverCid << ":" << serverPort;
-    return uri_stream.str();
-}
-
-static std::optional<unsigned> parseUnsignedIntFromString(const char* optarg, const char* name) {
-    auto v = strtoul(optarg, nullptr, 0);
-    if (((v == ULONG_MAX) && (errno == ERANGE)) || (v > UINT_MAX)) {
-        LOG(WARNING) << name << " value is out of range: " << optarg;
-    } else if (v != 0) {
-        return v;
-    } else {
-        LOG(WARNING) << name << " value is invalid or missing: " << optarg;
-    }
-
-    return std::nullopt;
-}
-
-static std::optional<unsigned> getNumberFromProperty(const char* key) {
-    auto value = property_get_int64(key, -1);
-    if ((value <= 0) || (value > UINT_MAX)) {
-        LOG(WARNING) << key << " is missing or out of bounds";
-        return std::nullopt;
-    }
-
-    return static_cast<unsigned int>(value);
-};
-
-std::optional<VsockServerInfo> VsockServerInfo::fromCommandLine(int argc, char* argv[]) {
-    std::optional<unsigned int> cid;
-    std::optional<unsigned int> port;
-
-    // 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},
-            {},
-    };
-
-    int optValue;
-    while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) {
-        switch (optValue) {
-            case OPT_VHAL_SERVER_CID:
-                cid = parseUnsignedIntFromString(optarg, "cid");
-                break;
-            case OPT_VHAL_SERVER_PORT_NUMBER:
-                port = parseUnsignedIntFromString(optarg, "port");
-                break;
-            default:
-                // ignore other options
-                break;
-        }
-    }
-
-    if (cid && port) {
-        return VsockServerInfo{*cid, *port};
-    }
-    return std::nullopt;
-}
-
-std::optional<VsockServerInfo> VsockServerInfo::fromRoPropertyStore() {
-    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";
-
-    const auto cid = getNumberFromProperty(VHAL_SERVER_CID_PROPERTY_KEY);
-    const auto port = getNumberFromProperty(VHAL_SERVER_PORT_PROPERTY_KEY);
-
-    if (cid && port) {
-        return VsockServerInfo{*cid, *port};
-    }
-    return std::nullopt;
-}
-
-}  // 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 8a8bce7..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.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_virtualization_Utils_H_
-#define android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
-
-#include <optional>
-#include <string>
-
-#include <android-base/logging.h>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-namespace impl {
-
-struct VsockServerInfo {
-    unsigned int serverCid{0};
-    unsigned int serverPort{0};
-
-    static std::optional<VsockServerInfo> fromCommandLine(int argc, char* argv[]);
-    static std::optional<VsockServerInfo> fromRoPropertyStore();
-
-    std::string toUri();
-};
-
-}  // 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 7a5f2d2..23f9135 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:
@@ -320,6 +320,25 @@
         | VehicleArea:GLOBAL),
 
     /**
+     * Multiple EV port locations
+     *
+     * Implement this property if the vehicle has multiple EV ports.
+     * Port locations are defined in PortLocationType.
+     * For example, a car has one port in front left and one port in rear left:
+     *   int32Values[0] = PortLocationType::FRONT_LEFT
+     *   int32Values[0] = PortLocationType::REAR_LEFT
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     * @data_enum PortLocationType
+     */
+    INFO_MULTI_EV_PORT_LOCATIONS = (
+        0x010C
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:INT32_VEC
+        | VehicleArea:GLOBAL),
+
+    /**
      * Current odometer value of the vehicle
      *
      * @change_mode VehiclePropertyChangeMode:CONTINUOUS
@@ -1413,6 +1432,33 @@
         | VehiclePropertyType:INT32_VEC
         | VehicleArea:GLOBAL),
 
+    /**
+     * Property to feed H/W rotary events to android
+     *
+     * int32Values[0] : RotaryInputType identifying which rotary knob rotated
+     * int32Values[1] : number of detents (clicks), positive for clockwise,
+     *                  negative for counterclockwise
+     * int32Values[2] : target display defined in VehicleDisplay. Events not
+     *                  tied to specific display must be sent to
+     *                  VehicleDisplay#MAIN.
+     * int32values[3 .. 3 + abs(number of detents) - 2]:
+     *                  nanosecond deltas between pairs of consecutive detents,
+     *                  if the number of detents is > 1 or < -1
+     *
+     * VehiclePropValue.timestamp: when the rotation occurred. If the number of
+     *                             detents is > 1 or < -1, this is when the
+     *                             first detent of rotation occurred.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @data_enum RotaryInputType
+     * @access VehiclePropertyAccess:READ
+     */
+    HW_ROTARY_INPUT = (
+        0x0A20
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:INT32_VEC
+        | VehicleArea:GLOBAL),
+
     /***************************************************************************
      * Most Car Cabin properties have both a POSition and MOVE parameter.  These
      * are used to control the various movements for seats, doors, and windows
@@ -3041,26 +3087,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,
 };
 
@@ -3092,61 +3164,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,
 };
@@ -4114,7 +4205,8 @@
 /**
  * Id of an Android user.
  *
- * Must be > 0 for valid ids, or -1 when it's not used.
+ * 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;
 
@@ -4605,3 +4697,18 @@
 
     UserIdentificationAssociationSetValue value;
 };
+
+/**
+ * A rotary control which can rotate without limits. These controls use HW_ROTARY_INPUT to report
+ * relative clockwise or counterclockwise motion. They have no absolute position.
+ */
+enum RotaryInputType : int32_t {
+    /**
+      * Main rotary control, typically in the center console, used to navigate the user interface.
+      */
+    ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION = 0,
+
+    /** Volume control for adjusting audio volume. */
+    ROTARY_INPUT_TYPE_AUDIO_VOLUME = 1,
+};
+
diff --git a/camera/device/3.6/types.hal b/camera/device/3.6/types.hal
index 743b139..f4c50ed 100644
--- a/camera/device/3.6/types.hal
+++ b/camera/device/3.6/types.hal
@@ -119,14 +119,20 @@
      * For devices that does not support the OFFLINE_PROCESSING capability, this
      * fields will always be false.
      *
-     * For devices support the OFFLINE_PROCESSING capability: any input stream
-     * and any output stream that can be output of the input stream must set
-     * this field to true. Also any stream of YUV420_888 format or JPEG format,
-     * with CPU_READ usage flag, must set this field to true. All other streams
-     * are up to camera HAL to advertise support or not, though it is not
-     * recommended to list support for streams with hardware composer or video
-     * encoder usage flags as these streams tend to be targeted continuously and
-     * can lead to long latency when trying to switch to offline.
+     * For backward compatible camera devices that support the
+     * OFFLINE_PROCESSING capability: any input stream and any output stream
+     * that can be output of the input stream must set this field to true. Also
+     * any stream of YUV420_888 format or JPEG format, with CPU_READ usage flag,
+     * must set this field to true.
+     *
+     * For depth only camera devices that support the OFFLINE_PROCESSING
+     * capability: any DEPTH16 output stream must set this field to true.
+     *
+     * All other streams are up to camera HAL to advertise support or not,
+     * though it is not recommended to list support for streams with
+     * hardware composer or video encoder usage flags as these streams tend
+     * to be targeted continuously and can lead to long latency when trying to
+     * switch to offline.
      *
      */
     bool supportOffline;
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/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 8eb7587..de1ee84 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -56,6 +56,14 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.sv</name>
+        <version>1.0</version>
+        <interface>
+            <name>ISurroundView</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.automotive.vehicle</name>
         <version>2.0</version>
         <interface>
@@ -153,7 +161,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>
@@ -280,14 +288,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>
@@ -348,7 +348,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>
@@ -383,7 +383,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>
@@ -416,7 +419,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>
diff --git a/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp b/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp
index 278d1f4..fb01ad0 100644
--- a/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp
+++ b/confirmationui/1.0/vts/functional/VtsHalConfirmationUIV1_0TargetTest.cpp
@@ -336,7 +336,7 @@
     ASSERT_EQ(0U, result.args->formattedMessage_.size());
 }
 
-// Simulates the framework candelling an ongoing prompt
+// Simulates the framework cancelling an ongoing prompt
 TEST_F(ConfirmationUIHidlTest, AbortTest) {
     static constexpr char test_prompt[] = "Me first, gimme gimme!";
     static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
@@ -354,6 +354,92 @@
     ASSERT_EQ(0U, result.args->formattedMessage_.size());
 }
 
+// Tests if the confirmation dialog can successfully render 100 'W' characters as required by
+// the design guidelines.
+TEST_F(ConfirmationUIHidlTest, PortableMessageTest1) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+            "WWWWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+    hidl_string prompt_text(test_prompt);
+    hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_HAL_CALL(ResponseCode::OK,
+                    confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+
+    confirmator().abort();
+
+    auto result = conf_cb->WaitForCallback();
+    ASSERT_EQ(ResponseCode::Aborted, result.args->error_);
+    ASSERT_EQ(0U, result.args->confirmationToken_.size());
+    ASSERT_EQ(0U, result.args->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 100 'W' characters as required by
+// the design guidelines in magnified mode.
+TEST_F(ConfirmationUIHidlTest, PortableMessageTest1Magnified) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+            "WWWWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+    hidl_string prompt_text(test_prompt);
+    hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_HAL_CALL(ResponseCode::OK,
+                    confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en",
+                                                         {UIOption::AccessibilityMagnified}));
+
+    confirmator().abort();
+
+    auto result = conf_cb->WaitForCallback();
+    ASSERT_EQ(ResponseCode::Aborted, result.args->error_);
+    ASSERT_EQ(0U, result.args->confirmationToken_.size());
+    ASSERT_EQ(0U, result.args->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as
+// required by the design guidelines.
+TEST_F(ConfirmationUIHidlTest, PortableMessageTest2) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW "
+            "WWWWWWWWWWWW WWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+    hidl_string prompt_text(test_prompt);
+    hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_HAL_CALL(ResponseCode::OK,
+                    confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}));
+
+    confirmator().abort();
+
+    auto result = conf_cb->WaitForCallback();
+    ASSERT_EQ(ResponseCode::Aborted, result.args->error_);
+    ASSERT_EQ(0U, result.args->confirmationToken_.size());
+    ASSERT_EQ(0U, result.args->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as
+// required by the design guidelines in magnified mode.
+TEST_F(ConfirmationUIHidlTest, PortableMessageTest2Magnified) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW "
+            "WWWWWWWWWWWW WWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    sp<ConfirmationTestCallback> conf_cb = new ConfirmationTestCallback;
+    hidl_string prompt_text(test_prompt);
+    hidl_vec<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_HAL_CALL(ResponseCode::OK,
+                    confirmator().promptUserConfirmation(conf_cb, prompt_text, extra, "en",
+                                                         {UIOption::AccessibilityMagnified}));
+
+    confirmator().abort();
+
+    auto result = conf_cb->WaitForCallback();
+    ASSERT_EQ(ResponseCode::Aborted, result.args->error_);
+    ASSERT_EQ(0U, result.args->confirmationToken_.size());
+    ASSERT_EQ(0U, result.args->formattedMessage_.size());
+}
+
 // Passing malformed UTF-8 to the confirmation UI
 // This test passes a string that ends in the middle of a multibyte character
 TEST_F(ConfirmationUIHidlTest, MalformedUTF8Test1) {
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 62b9877..01e6a57 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,7 +597,7 @@
 5f6d3097ba84cb63c430787123f4de1b31c11f90b531b98eae9a8623a5ae962a android.hardware.neuralnetworks@1.1::types
 fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice
 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel
-6c29d6fdd5445911df5456b3b84b949cdd59fca0c0b5507662f26a5cac0cf5e5 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
@@ -604,15 +605,15 @@
 5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface
 
 # HALs released in Android R
-e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types
+822369cf4dc16a6f6b9622bcf86cbdc0b692dc82193fc15e967767175cbfdd8f android.hardware.audio@6.0::types
 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
+e6cd2b7c1a86b6ca683c0224ffde3b73aa14f6487de9f46833e539d26d1b3b5c android.hardware.audio@6.0::IStreamOut
 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback
-167ed5cfb7d91db2e2bf20f1320c1a9004eeb768e26f535e0f7db94a21867d21 android.hardware.audio.common@6.0::types
+bee662c62d997d8065e2bcb5c1e7a9578931f22ce28fd02c219fdb4d0630abf7 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
@@ -637,27 +638,32 @@
 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
 b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice
-e88840e0558439cb54837514ddccd43877094951758f367e9c638084eb7455a6 android.hardware.camera.provider@2.6::ICameraProvider
+daad72a2f482d8a1f660d0e99ac1b78fedb414a4cfbe3fa56b2cd480e5d6f0cb android.hardware.camera.provider@2.6::ICameraProvider
 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
+a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types
 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
-446287268831f4ddfac4a51bb1c32ae1e48e47bccd535fccc2c4546d0e7c4013 android.hardware.dumpstate@1.1::types
-f284ffde7cadf5a1364b75ab313baf22401eeca289bdde2a2dc7a27ea4ab98d7 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
@@ -668,28 +674,44 @@
 df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
 a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer
-9db064ee44268a876be0367ff771e618362d39ec603b6ecab17e1575725fcd87 android.hardware.neuralnetworks@1.3::IDevice
-4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback
-2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
-237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel
-0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-abbc4e1a969881c9f8ab587add5b5e75b08df834c9c969c013ae38cb4bb16f6a 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
+c9320b04ec302624985180a02d591bea5e435601fc411a6cabb58878e4e1ad68 android.hardware.neuralnetworks@1.3::types
+b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types
+adab52e647d1a1ccfbdabdfc9c73352f8e834b61322e505bc6e3d3a0d3acc259 android.hardware.tv.tuner@1.0::IDemux
+548e1a16fc4f779346e14968a63cd6f160e1e2c8b8c99256b2bac24a24b52a9a android.hardware.tv.tuner@1.0::IDescrambler
+b84597d59f0f1d03c9997d60eb15280f3950c287d46016240d89859789db4d47 android.hardware.tv.tuner@1.0::IDvr
+e512a8b4ddef0d0c29d9f68101363dca7616033a24bab86bfca0829661e7484c android.hardware.tv.tuner@1.0::IDvrCallback
+c113b5bed45b3a67ee3f15de1482742a8fd8d96e45ec72e628ee9be6301d51d7 android.hardware.tv.tuner@1.0::IFilter
+8bbc6bde44573edf800cda2b457852175786a3c73f36666bfb2d3afdce3d0dfa android.hardware.tv.tuner@1.0::IFilterCallback
+ccd985e820ed92a5cb55f524b3549462483d21824ca2df0276f5bc2f42878ea3 android.hardware.tv.tuner@1.0::IFrontend
+818587bab10f2534b5a1ef70ed9bae99019f7d453b2fcb2dda01c6db91c3a805 android.hardware.tv.tuner@1.0::IFrontendCallback
+83de3964a800a0e707731adcbcbfbaa56868549233e4c8dcccc8969fab727d38 android.hardware.tv.tuner@1.0::ILnb
+b2310785bdb55f97bbbb2176e2ee73ed8d2a7ce5895bd20c997b90c5f2868ad8 android.hardware.tv.tuner@1.0::ILnbCallback
+4788787e662293d526ff7789fc24e82533e7f6ff99a967ebc3e3ec6b17628796 android.hardware.tv.tuner@1.0::ITimeFilter
+c350c7783843e0c7cf30f90c918770b0d3c09fc0fe5e532e2f2e7210fcfe71c9 android.hardware.tv.tuner@1.0::ITuner
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
 c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
 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
-e1d34b83188a8ef3c507ec53c0ebcf714863c746da7f4a05460453f7c4c09389 android.hardware.radio@1.5::types
-8062d0a1a03594dd8b448adcf6f08856b5720f7e33f9b785a21d3ef74a4f211d android.hardware.radio@1.5::IRadio
+99f5c26b952271d1246c957e1d0271fa39445ee65cc93aa7c187834f98914a33 android.hardware.radio@1.5::types
+890ecacaaa6660802bac01bbbe5f16b1eb1d6a3a3f0e5b398be5cec76a5ab673 android.hardware.radio@1.5::IRadio
 e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication
-c8a8e4c3998ebdf1c71ece2d3ecb033ae17798830bed4b30a53e5991aa219e3a android.hardware.radio@1.5::IRadioResponse
-dcc8872337f0135e81970e1d8d5fd7139160dc80e9be76f0ae05290fa7e472b8 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
+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
-12d7533ff0754f45bf59ab300799074570a99a676545652c2c23abc73cb4515d android.hardware.soundtrigger@2.3::ISoundTriggerHw
+b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw
 7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
diff --git a/dumpstate/1.1/IDumpstateDevice.hal b/dumpstate/1.1/IDumpstateDevice.hal
index 502c460..183404d 100644
--- a/dumpstate/1.1/IDumpstateDevice.hal
+++ b/dumpstate/1.1/IDumpstateDevice.hal
@@ -29,8 +29,9 @@
      * 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 getDeviceLoggingEnabled
-     * returns false. In this case, it must return DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED.
+     * 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.
@@ -44,7 +45,7 @@
         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
@@ -52,20 +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.
      *
-     * Even if device logging has been disabled, dumpstateBoard may still be called by the dumpstate
-     * routine. In this case, it must return DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED.
+     * 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 device vendor logging.
+     * @param enable Whether to enable or disable verbose vendor logging.
      */
-    setDeviceLoggingEnabled(bool enable);
+    setVerboseLoggingEnabled(bool enable);
 
     /**
-     * Queries the current state of device logging. Primarily for UI and informative purposes.
+     * Queries the current state of verbose device logging. Primarily for UI and informative
+     * purposes.
      *
-     * Even if device logging has been disabled, dumpstateBoard may still be called by the dumpstate
-     * routine. In this case, it must return DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED.
+     * 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 vendor logging is currently enabled.
+     * @return enabled Whether or not verbose vendor logging is currently enabled.
      */
-    getDeviceLoggingEnabled() generates (bool enabled);
+    getVerboseLoggingEnabled() generates (bool enabled);
 };
diff --git a/dumpstate/1.1/types.hal b/dumpstate/1.1/types.hal
index f5cbade..c522f7c 100644
--- a/dumpstate/1.1/types.hal
+++ b/dumpstate/1.1/types.hal
@@ -55,6 +55,13 @@
      * This mode MUST be supported if the dumpstate HAL is implemented.
      */
     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,
 };
 
 /**
diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
index 089b039..1bef663 100644
--- a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
+++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
@@ -20,6 +20,7 @@
 #include <unistd.h>
 
 #include <functional>
+#include <tuple>
 #include <vector>
 
 #include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
@@ -27,6 +28,7 @@
 #include <cutils/native_handle.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
 #include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
@@ -39,17 +41,22 @@
 using ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
 using ::android::hardware::dumpstate::V1_1::toString;
 
-class DumpstateHidl1_1Test : public ::testing::TestWithParam<std::string> {
+// Base class common to all dumpstate HAL v1.1 tests.
+template <typename T>
+class DumpstateHidl1_1TestBase : public ::testing::TestWithParam<T> {
   protected:
     virtual void SetUp() override { GetService(); }
 
+    virtual std::string GetInstanceName() = 0;
+
     void GetService() {
-        dumpstate = IDumpstateDevice::getService(GetParam());
-        ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance";
+        const std::string instance_name = GetInstanceName();
+        dumpstate = IDumpstateDevice::getService(instance_name);
+        ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance " << instance_name;
     }
 
-    void ToggleDeviceLogging(bool enable) {
-        Return<void> status = dumpstate->setDeviceLoggingEnabled(enable);
+    void ToggleVerboseLogging(bool enable) {
+        Return<void> status = dumpstate->setVerboseLoggingEnabled(enable);
         ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
 
         if (!dumpstate->ping().isOk()) {
@@ -58,11 +65,11 @@
             GetService();
         }
 
-        Return<bool> logging_enabled = dumpstate->getDeviceLoggingEnabled();
+        Return<bool> logging_enabled = dumpstate->getVerboseLoggingEnabled();
         ASSERT_TRUE(logging_enabled.isOk())
                 << "Status should be ok: " << logging_enabled.description();
         ASSERT_EQ(logging_enabled, enable)
-                << "Device logging should now be " << (enable ? "enabled" : "disabled");
+                << "Verbose logging should now be " << (enable ? "enabled" : "disabled");
 
         if (!dumpstate->ping().isOk()) {
             ALOGW("IDumpstateDevice service appears to have exited lazily, attempting to get "
@@ -71,84 +78,84 @@
         }
     }
 
-    void EnableDeviceLogging() { ToggleDeviceLogging(true); }
+    void EnableVerboseLogging() { ToggleVerboseLogging(true); }
 
-    void DisableDeviceLogging() { ToggleDeviceLogging(false); }
+    void DisableVerboseLogging() { ToggleVerboseLogging(false); }
 
     sp<IDumpstateDevice> dumpstate;
 };
 
-#define TEST_FOR_DUMPSTATE_MODE(name, body, mode) \
-    TEST_P(DumpstateHidl1_1Test, name##_##mode) { body(DumpstateMode::mode); }
+// Tests that don't need to iterate every single DumpstateMode value for dumpstateBoard_1_1.
+class DumpstateHidl1_1GeneralTest : public DumpstateHidl1_1TestBase<std::string> {
+  protected:
+    virtual std::string GetInstanceName() override { return GetParam(); }
+};
 
-// 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);  \
-    TEST_FOR_DUMPSTATE_MODE(name, body, REMOTE);       \
-    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);
+// Tests that iterate every single DumpstateMode value for dumpstateBoard_1_1.
+class DumpstateHidl1_1PerModeTest
+    : public DumpstateHidl1_1TestBase<std::tuple<std::string, DumpstateMode>> {
+  protected:
+    virtual std::string GetInstanceName() override { return std::get<0>(GetParam()); }
+
+    DumpstateMode GetMode() { return std::get<1>(GetParam()); }
+
+    // Will only execute additional_assertions when status == expected.
+    void AssertStatusForMode(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 (GetMode() == DumpstateMode::DEFAULT) {
+            ASSERT_EQ(expected, status)
+                    << "Required mode (DumpstateMode::" << toString(GetMode())
+                    << "): 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(GetMode())
+                    << "): status should be DumpstateStatus::" << toString(expected)
+                    << " or DumpstateStatus::UNSUPPORTED_MODE, but got DumpstateStatus::"
+                    << toString(status);
+        }
+        if (status == expected && additional_assertions != nullptr) {
+            additional_assertions();
+        }
+    }
+};
 
 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) {
-    EnableDeviceLogging();
+TEST_P(DumpstateHidl1_1PerModeTest, TestNullHandle) {
+    EnableVerboseLogging();
 
     Return<DumpstateStatus> status =
-            dumpstate->dumpstateBoard_1_1(nullptr, mode, kDefaultTimeoutMillis);
+            dumpstate->dumpstateBoard_1_1(nullptr, GetMode(), kDefaultTimeoutMillis);
 
-    AssertStatusForMode(mode, status, DumpstateStatus::ILLEGAL_ARGUMENT);
-});
+    AssertStatusForMode(status, DumpstateStatus::ILLEGAL_ARGUMENT);
+}
 
 // Negative test: make sure dumpstateBoard() ignores a handle with no FD.
-TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithNoFd, [this](DumpstateMode mode) {
-    EnableDeviceLogging();
+TEST_P(DumpstateHidl1_1PerModeTest, TestHandleWithNoFd) {
+    EnableVerboseLogging();
 
     native_handle_t* handle = native_handle_create(0, 0);
     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
 
     Return<DumpstateStatus> status =
-            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+            dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
 
-    AssertStatusForMode(mode, status, DumpstateStatus::ILLEGAL_ARGUMENT);
+    AssertStatusForMode(status, DumpstateStatus::ILLEGAL_ARGUMENT);
 
     native_handle_close(handle);
     native_handle_delete(handle);
-});
+}
 
 // Positive test: make sure dumpstateBoard() writes something to the FD.
-TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) {
-    EnableDeviceLogging();
+TEST_P(DumpstateHidl1_1PerModeTest, TestOk) {
+    EnableVerboseLogging();
 
     // Index 0 corresponds to the read end of the pipe; 1 to the write end.
     int fds[2];
@@ -159,9 +166,9 @@
     handle->data[0] = fds[1];
 
     Return<DumpstateStatus> status =
-            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+            dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
 
-    AssertStatusForMode(mode, status, DumpstateStatus::OK, [&fds]() {
+    AssertStatusForMode(status, DumpstateStatus::OK, [&fds]() {
         // Check that at least one byte was written.
         char buff;
         ASSERT_EQ(1, read(fds[0], &buff, 1)) << "Dumped nothing";
@@ -169,11 +176,11 @@
 
     native_handle_close(handle);
     native_handle_delete(handle);
-});
+}
 
 // Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
-TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) {
-    EnableDeviceLogging();
+TEST_P(DumpstateHidl1_1PerModeTest, TestHandleWithTwoFds) {
+    EnableVerboseLogging();
 
     int fds1[2];
     int fds2[2];
@@ -186,9 +193,9 @@
     handle->data[1] = fds2[1];
 
     Return<DumpstateStatus> status =
-            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+            dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
 
-    AssertStatusForMode(mode, status, DumpstateStatus::OK, [&fds1, &fds2]() {
+    AssertStatusForMode(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);
@@ -199,11 +206,11 @@
 
     native_handle_close(handle);
     native_handle_delete(handle);
-});
+}
 
 // Make sure dumpstateBoard_1_1 actually validates its arguments.
-TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Negative) {
-    EnableDeviceLogging();
+TEST_P(DumpstateHidl1_1GeneralTest, TestInvalidModeArgument_Negative) {
+    EnableVerboseLogging();
 
     int fds[2];
     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
@@ -224,8 +231,8 @@
     native_handle_delete(handle);
 }
 
-TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Undefined) {
-    EnableDeviceLogging();
+TEST_P(DumpstateHidl1_1GeneralTest, TestInvalidModeArgument_Undefined) {
+    EnableVerboseLogging();
 
     int fds[2];
     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
@@ -247,8 +254,8 @@
 }
 
 // Positive test: make sure dumpstateBoard() from 1.0 doesn't fail.
-TEST_P(DumpstateHidl1_1Test, Test1_0MethodOk) {
-    EnableDeviceLogging();
+TEST_P(DumpstateHidl1_1GeneralTest, Test1_0MethodOk) {
+    EnableVerboseLogging();
 
     int fds[2];
     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
@@ -269,9 +276,10 @@
     native_handle_delete(handle);
 }
 
-// Make sure disabling device logging behaves correctly.
-TEST_FOR_ALL_DUMPSTATE_MODES(TestDeviceLoggingDisabled, [this](DumpstateMode mode) {
-    DisableDeviceLogging();
+// 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_P(DumpstateHidl1_1PerModeTest, TestDeviceLoggingDisabled) {
+    DisableVerboseLogging();
 
     // Index 0 corresponds to the read end of the pipe; 1 to the write end.
     int fds[2];
@@ -282,41 +290,55 @@
     handle->data[0] = fds[1];
 
     Return<DumpstateStatus> status =
-            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+            dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
 
-    AssertStatusForMode(mode, status, DumpstateStatus::DEVICE_LOGGING_NOT_ENABLED, [&fds]() {
-        // Check that nothing was written. Could return 0 or -1.
-        char buff;
-        ASSERT_NE(1, read(fds[0], &buff, 1)) << "Dumped something when device logging is disabled";
-    });
+    // 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(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) {
-    EnableDeviceLogging();
-    EnableDeviceLogging();
+TEST_P(DumpstateHidl1_1GeneralTest, TestRepeatedEnable) {
+    EnableVerboseLogging();
+    EnableVerboseLogging();
 }
 
 // Double-disable is perfectly valid, but the second call shouldn't do anything.
-TEST_P(DumpstateHidl1_1Test, TestRepeatedDisable) {
-    DisableDeviceLogging();
-    DisableDeviceLogging();
+TEST_P(DumpstateHidl1_1GeneralTest, TestRepeatedDisable) {
+    DisableVerboseLogging();
+    DisableVerboseLogging();
 }
 
 // Toggling in short order is perfectly valid.
-TEST_P(DumpstateHidl1_1Test, TestRepeatedToggle) {
-    EnableDeviceLogging();
-    DisableDeviceLogging();
-    EnableDeviceLogging();
-    DisableDeviceLogging();
+TEST_P(DumpstateHidl1_1GeneralTest, TestRepeatedToggle) {
+    EnableVerboseLogging();
+    DisableVerboseLogging();
+    EnableVerboseLogging();
+    DisableVerboseLogging();
 }
 
 INSTANTIATE_TEST_SUITE_P(
-        PerInstance, DumpstateHidl1_1Test,
+        PerInstance, DumpstateHidl1_1GeneralTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)),
         android::hardware::PrintInstanceNameToString);
 
+// Includes the mode's name as part of the description string.
+static inline std::string PrintInstanceNameToStringWithMode(
+        const testing::TestParamInfo<std::tuple<std::string, DumpstateMode>>& info) {
+    return android::hardware::PrintInstanceNameToString(
+                   testing::TestParamInfo(std::get<0>(info.param), info.index)) +
+           "_" + toString(std::get<1>(info.param));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstanceAndMode, DumpstateHidl1_1PerModeTest,
+        testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IDumpstateDevice::descriptor)),
+                         testing::ValuesIn(android::hardware::hidl_enum_range<DumpstateMode>())),
+        PrintInstanceNameToStringWithMode);
+
 }  // namespace
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/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
index 168028d..ccb0690 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
@@ -107,19 +107,4 @@
      */
     long horizontalSubsampling;
     long verticalSubsampling;
-
-    /**
-     * Some buffer producers require extra padding to their output buffer; therefore the
-     * physical size of the native buffer will be larger than its logical size.
-     * The crop rectangle determines the offset and logical size of the buffer that should be
-     * read by consumers.
-     *
-     * The crop rectangle is measured in samples and is relative to the offset of the
-     * plane. Valid crop rectangles are within the boundaries of the plane:
-     * [0, 0, widthInSamples, heightInSamples].
-     *
-     * The default crop rectangle is a rectangle the same size as the plane:
-     * [0, 0, widthInSamples, heightInSamples].
-     */
-    Rect crop;
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 7b46688..af6045e 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -260,6 +260,32 @@
     PLANE_LAYOUTS = 15,
 
     /**
+     * Can be used to get the crop of the buffer.
+     *
+     * Some buffer producers require extra padding to their output buffer; therefore the
+     * physical size of the native buffer will be larger than its logical size.
+     * The crop rectangle(s) determine the offset and logical size of the buffer that should be
+     * read by consumers.
+     *
+     * The crop is defined per plane. The crop(s) are represented by an array of
+     * android.hardware.graphics.common.Rects. The array must be the same length and in the same
+     * order as the array of PlaneLayouts. Eg. the first crop in the array is the crop for the
+     * first PlaneLayout in the PlaneLayout array.
+     *
+     * Each crop Rect is measured in samples and is relative to the offset of the plane. Valid crop
+     * rectangles are within the boundaries of the plane: [0, 0, widthInSamples, heightInSamples].
+     * The default crop rectangle of each plane is a rectangle the same size as the plane:
+     * [0, 0, widthInSamples, heightInSamples].
+     *
+     * When it is encoded into a byte stream, the total number of Rects is written using
+     * 8 bytes in little endian. It is followed by each Rect.
+     *
+     * To encode a Rect, write the following fields in this order each as 8 bytes in little endian:
+     * left, top, right and bottom.
+     */
+    CROP = 16,
+
+    /**
      * Can be used to get or set the dataspace of the buffer. The framework may attempt to set
      * this value.
      *
@@ -273,7 +299,7 @@
      * When it is encoded into a byte stream, it is first cast to a int32_t and then represented in
      * the byte stream by 4 bytes written in little endian.
      */
-    DATASPACE = 16,
+    DATASPACE = 17,
 
     /**
      * Can be used to get or set the BlendMode. The framework may attempt to set this value.
@@ -287,7 +313,7 @@
      * When it is encoded into a byte stream, it is first cast to a int32_t and then represented by
      * 4 bytes written in little endian.
      */
-    BLEND_MODE = 17,
+    BLEND_MODE = 18,
 
     /**
      * Can be used to get or set static HDR metadata specified by SMPTE ST 2086.
@@ -300,7 +326,7 @@
      * little endian. The ordering of float values follows the definition of Smpte2086 and XyColor.
      * If this is unset when encoded into a byte stream, the byte stream is empty.
      */
-    SMPTE2086 = 18,
+    SMPTE2086 = 19,
 
     /**
      * Can be used to get or set static HDR metadata specified by CTA 861.3.
@@ -313,7 +339,7 @@
      * little endian. The ordering of float values follows the definition of Cta861_3.
      * If this is unset when encoded into a byte stream, the byte stream is empty.
      */
-    CTA861_3 = 19,
+    CTA861_3 = 20,
 
     /**
      * Can be used to get or set dynamic HDR metadata specified by SMPTE ST 2094-40:2016.
@@ -326,5 +352,5 @@
      * using 8 bytes in little endian. It is followed by the uint8_t byte array.
      * If this is unset when encoded into a byte stream, the byte stream is empty.
      */
-    SMPTE2094_40 = 20,
+    SMPTE2094_40 = 21,
 }
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/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
index 4eb4bb7..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
@@ -41,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/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/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 2aad242..1416fcc 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -97,6 +97,7 @@
         Error err = mGralloc->set(bufferHandle, metadataType, metadata);
         if (err == Error::UNSUPPORTED) {
             GTEST_SUCCEED() << "setting this metadata is unsupported";
+            return;
         }
         ASSERT_EQ(err, Error::NONE);
 
@@ -143,7 +144,7 @@
         EXPECT_EQ(24, offsetInBitsA);
 
         EXPECT_EQ(0, planeLayout.offsetInBytes);
-        EXPECT_EQ(8, planeLayout.sampleIncrementInBits);
+        EXPECT_EQ(32, planeLayout.sampleIncrementInBits);
         // Skip testing stride because any stride is valid
         EXPECT_EQ(mDummyDescriptorInfo.width, planeLayout.widthInSamples);
         EXPECT_EQ(mDummyDescriptorInfo.height, planeLayout.heightInSamples);
@@ -151,11 +152,6 @@
                   planeLayout.totalSizeInBytes);
         EXPECT_EQ(1, planeLayout.horizontalSubsampling);
         EXPECT_EQ(1, planeLayout.verticalSubsampling);
-
-        EXPECT_EQ(0, planeLayout.crop.left);
-        EXPECT_EQ(0, planeLayout.crop.top);
-        EXPECT_EQ(planeLayout.widthInSamples, planeLayout.crop.right);
-        EXPECT_EQ(planeLayout.heightInSamples, planeLayout.crop.bottom);
     }
 
     void verifyBufferDump(const IMapper::BufferDump& bufferDump,
@@ -925,6 +921,7 @@
     bufferHandle = mGralloc->allocate(info, true, true);
     if (bufferHandle) {
         GTEST_SUCCEED() << "unable to allocate protected content";
+        return;
     }
 
     hidl_vec<uint8_t> vec;
@@ -998,6 +995,22 @@
 }
 
 /**
+ * Test IMapper::get(Crop)
+ */
+TEST_P(GraphicsMapperHidlTest, GetCrop) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::RGBA_8888;
+    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+    testGet(info, gralloc4::MetadataType_Crop,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::vector<aidl::android::hardware::graphics::common::Rect> crops;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeCrop(vec, &crops));
+                EXPECT_EQ(1, crops.size());
+            });
+}
+
+/**
  * Test IMapper::get(Dataspace)
  */
 TEST_P(GraphicsMapperHidlTest, GetDataspace) {
@@ -1104,6 +1117,8 @@
     ASSERT_EQ(Error::BAD_BUFFER,
               mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
     ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Crop, &vec));
+    ASSERT_EQ(0, vec.size());
     ASSERT_EQ(Error::BAD_BUFFER,
               mGralloc->get(bufferHandle, gralloc4::MetadataType_Dataspace, &vec));
     ASSERT_EQ(0, vec.size());
@@ -1183,64 +1198,6 @@
 }
 
 /**
- * Test IMapper::set(Usage) remove flag
- */
-TEST_P(GraphicsMapperHidlTest, SetUsageRemoveBit) {
-    uint64_t usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN);
-    hidl_vec<uint8_t> vec;
-    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
-
-    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec,
-            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
-                uint64_t realUsage = 0;
-                ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
-                EXPECT_EQ(usage, realUsage);
-            });
-}
-/**
- * Test IMapper::set(Usage) add flag
- */
-TEST_P(GraphicsMapperHidlTest, SetUsageAddBit) {
-    uint64_t usage = mDummyDescriptorInfo.usage | static_cast<uint64_t>(BufferUsage::GPU_TEXTURE);
-    hidl_vec<uint8_t> vec;
-    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
-
-    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec,
-            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
-                uint64_t realUsage = 0;
-                ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
-                EXPECT_EQ(usage, realUsage);
-            });
-}
-
-/**
- * Test IMapper::set(Usage) to test protected content
- */
-TEST_P(GraphicsMapperHidlTest, SetUsageProtected) {
-    const native_handle_t* bufferHandle = nullptr;
-    auto info = mDummyDescriptorInfo;
-    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
-
-    bufferHandle = mGralloc->allocate(info, true, true);
-    if (bufferHandle) {
-        GTEST_SUCCEED() << "unable to allocate protected content";
-    }
-
-    uint64_t usage = static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY);
-    hidl_vec<uint8_t> vec;
-    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
-
-    Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec);
-    ASSERT_EQ(err, Error::UNSUPPORTED);
-    vec.resize(0);
-
-    uint64_t realUsage = 0;
-    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_Usage, &vec));
-    ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
-    EXPECT_EQ(info.usage, realUsage);
-}
-
-/**
  * Test IMapper::set(AllocationSize)
  */
 TEST_P(GraphicsMapperHidlTest, SetAllocationSize) {
@@ -1267,6 +1224,7 @@
     bufferHandle = mGralloc->allocate(info, true, true);
     if (bufferHandle) {
         GTEST_SUCCEED() << "unable to allocate protected content";
+        return;
     }
 
     uint64_t protectedContent = 0;
@@ -1362,10 +1320,6 @@
     planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * info.height;
     planeLayoutA.horizontalSubsampling = 1;
     planeLayoutA.verticalSubsampling = 1;
-    planeLayoutA.crop.left = 0;
-    planeLayoutA.crop.top = 0;
-    planeLayoutA.crop.right = info.width;
-    planeLayoutA.crop.bottom = info.height;
 
     component.type = gralloc4::PlaneLayoutComponentType_A;
     component.offsetInBits = 0;
@@ -1375,17 +1329,13 @@
     planeLayouts.push_back(planeLayoutA);
 
     planeLayoutRGB.offsetInBytes = 0;
-    planeLayoutRGB.sampleIncrementInBits = 32;
+    planeLayoutRGB.sampleIncrementInBits = 24;
     planeLayoutRGB.strideInBytes = info.width + 20;
     planeLayoutRGB.widthInSamples = info.width;
     planeLayoutRGB.heightInSamples = info.height;
     planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * info.height;
     planeLayoutRGB.horizontalSubsampling = 1;
     planeLayoutRGB.verticalSubsampling = 1;
-    planeLayoutRGB.crop.left = 0;
-    planeLayoutRGB.crop.top = 0;
-    planeLayoutRGB.crop.right = info.width;
-    planeLayoutRGB.crop.bottom = info.height;
 
     component.type = gralloc4::PlaneLayoutComponentType_R;
     planeLayoutRGB.components.push_back(component);
@@ -1402,6 +1352,7 @@
     Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec);
     if (err == Error::UNSUPPORTED) {
         GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
     }
     ASSERT_EQ(err, Error::NONE);
 
@@ -1423,11 +1374,6 @@
         EXPECT_EQ(planeLayout.horizontalSubsampling, realPlaneLayout.horizontalSubsampling);
         EXPECT_EQ(planeLayout.verticalSubsampling, realPlaneLayout.verticalSubsampling);
 
-        EXPECT_EQ(planeLayout.crop.left, realPlaneLayout.crop.left);
-        EXPECT_EQ(planeLayout.crop.top, realPlaneLayout.crop.top);
-        EXPECT_EQ(planeLayout.crop.right, realPlaneLayout.crop.right);
-        EXPECT_EQ(planeLayout.crop.bottom, realPlaneLayout.crop.bottom);
-
         ASSERT_EQ(planeLayout.components.size(), realPlaneLayout.components.size());
 
         for (int j = 0; j < realPlaneLayout.components.size(); j++) {
@@ -1443,6 +1389,26 @@
 }
 
 /**
+ * Test IMapper::set(Crop)
+ */
+TEST_P(GraphicsMapperHidlTest, SetCrop) {
+    std::vector<aidl::android::hardware::graphics::common::Rect> crops{{0, 0, 32, 32}};
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeCrop(crops, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Crop, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::vector<aidl::android::hardware::graphics::common::Rect> realCrops;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeCrop(vec, &realCrops));
+                ASSERT_EQ(1, realCrops.size());
+                ASSERT_EQ(crops.front().left, realCrops.front().left);
+                ASSERT_EQ(crops.front().top, realCrops.front().top);
+                ASSERT_EQ(crops.front().right, realCrops.front().right);
+                ASSERT_EQ(crops.front().bottom, realCrops.front().bottom);
+            });
+}
+
+/**
  * Test IMapper::set(Dataspace)
  */
 TEST_P(GraphicsMapperHidlTest, SetDataspace) {
@@ -1589,6 +1555,7 @@
               mGralloc->set(bufferHandle, gralloc4::MetadataType_ChromaSiting, vec));
     ASSERT_EQ(Error::BAD_BUFFER,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec));
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Crop, vec));
     ASSERT_EQ(Error::BAD_BUFFER,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
     ASSERT_EQ(Error::BAD_BUFFER,
@@ -1607,16 +1574,48 @@
     const native_handle_t* bufferHandle = nullptr;
     ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
 
-    hidl_vec<uint8_t> vec;
-    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec));
-    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
-    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
-    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
+    uint64_t bufferId = 2;
+    hidl_vec<uint8_t> bufferIdVec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeBufferId(bufferId, &bufferIdVec));
     ASSERT_EQ(Error::BAD_VALUE,
-              mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, bufferIdVec));
+
+    std::string name{"new name"};
+    hidl_vec<uint8_t> nameVec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeName(name, &nameVec));
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, nameVec));
+
+    uint64_t width = 32;
+    hidl_vec<uint8_t> widthVec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeWidth(width, &widthVec));
     ASSERT_EQ(Error::BAD_VALUE,
-              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec));
-    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec));
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, widthVec));
+
+    uint64_t height = 32;
+    hidl_vec<uint8_t> heightVec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeHeight(height, &heightVec));
+    ASSERT_EQ(Error::BAD_VALUE,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, heightVec));
+
+    uint64_t layerCount = 2;
+    hidl_vec<uint8_t> layerCountVec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeLayerCount(layerCount, &layerCountVec));
+    ASSERT_EQ(Error::BAD_VALUE,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, layerCountVec));
+
+    hardware::graphics::common::V1_2::PixelFormat pixelFormatRequested = PixelFormat::BLOB;
+    hidl_vec<uint8_t> pixelFormatRequestedVec;
+    ASSERT_EQ(NO_ERROR,
+              gralloc4::encodePixelFormatRequested(pixelFormatRequested, &pixelFormatRequestedVec));
+    ASSERT_EQ(Error::BAD_VALUE,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested,
+                            pixelFormatRequestedVec));
+
+    uint64_t usage = 0;
+    hidl_vec<uint8_t> usageVec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &usageVec));
+    ASSERT_EQ(Error::BAD_VALUE,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, usageVec));
 }
 
 /**
@@ -1628,19 +1627,9 @@
 
     hidl_vec<uint8_t> vec;
     ASSERT_EQ(Error::UNSUPPORTED,
-              mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec));
-    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
-    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
-    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
-    ASSERT_EQ(Error::UNSUPPORTED,
-              mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
-    ASSERT_EQ(Error::UNSUPPORTED,
-              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec));
-    ASSERT_EQ(Error::UNSUPPORTED,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, vec));
     ASSERT_EQ(Error::UNSUPPORTED,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, vec));
-    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec));
     ASSERT_EQ(Error::UNSUPPORTED,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_AllocationSize, vec));
     ASSERT_EQ(Error::UNSUPPORTED,
@@ -1653,6 +1642,7 @@
               mGralloc->set(bufferHandle, gralloc4::MetadataType_ChromaSiting, vec));
     ASSERT_EQ(Error::UNSUPPORTED,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_PlaneLayouts, vec));
+    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Crop, vec));
     ASSERT_EQ(Error::UNSUPPORTED,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
     ASSERT_EQ(Error::UNSUPPORTED,
@@ -1735,6 +1725,7 @@
             mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, &vec);
     if (err == Error::UNSUPPORTED) {
         GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
     }
     ASSERT_EQ(err, Error::NONE);
 
@@ -1751,6 +1742,7 @@
             mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, &vec);
     if (err == Error::UNSUPPORTED) {
         GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
     }
     ASSERT_EQ(err, Error::NONE);
 
@@ -1780,6 +1772,7 @@
                                                       gralloc4::MetadataType_AllocationSize, &vec);
     if (err == Error::UNSUPPORTED) {
         GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
     }
     ASSERT_EQ(err, Error::NONE);
 
@@ -1867,6 +1860,23 @@
 }
 
 /**
+ * Test IMapper::getFromBufferDescriptorInfo(Crop)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCrop) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::RGBA_8888;
+    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getFromBufferDescriptorInfo(info, gralloc4::MetadataType_Crop, &vec));
+
+    std::vector<aidl::android::hardware::graphics::common::Rect> crops;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeCrop(vec, &crops));
+    EXPECT_EQ(1, crops.size());
+}
+
+/**
  * Test IMapper::getFromBufferDescriptorInfo(Dataspace)
  */
 TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) {
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.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/VtsHalHealthV2_1TargetTest.cpp b/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
index e75b299..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,18 +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 should not be negative";
+        EXPECT_GE(value.batteryFullChargeDesignCapacityUah, 0)
+                << "batteryFullChargeDesignCapacityUah should not be negative";
 
-        if (value.batteryFullCapacityUah > 0) {
-            EXPECT_GE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 0.50);
-            EXPECT_LE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 1.20);
-        }
+        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/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.h b/identity/1.0/default/WritableIdentityCredential.h
deleted file mode 100644
index b1deb16..0000000
--- a/identity/1.0/default/WritableIdentityCredential.h
+++ /dev/null
@@ -1,106 +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>& attestationApplicationId,
-                                           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 88b06df..0000000
--- a/identity/1.0/vts/functional/VtsHalIdentityCredentialTargetTest.cpp
+++ /dev/null
@@ -1,532 +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";
-    // 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<uint8_t> attestationCertificate;
-    writableCredential->getAttestationCertificate(
-            attestationApplicationId, attestationChallenge,
-            [&](const Result& _result, const hidl_vec<hidl_vec<uint8_t>>& _splitCertChain) {
-                result = _result;
-                vector<vector<uint8_t>> splitCerts;
-                std::copy(_splitCertChain.begin(), _splitCertChain.end(),
-                          std::back_inserter(splitCerts));
-                attestationCertificate = support::certificateChainJoin(splitCerts);
-            });
-    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 75%
rename from identity/1.0/IWritableIdentityCredential.hal
rename to identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
index f26f763..483b0c7 100644
--- a/identity/1.0/IWritableIdentityCredential.hal
+++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -14,12 +14,16 @@
  * 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
@@ -69,31 +73,23 @@
      *
      * @param attestationChallenge a challenge set by the issuer to ensure freshness.
      *
-     * @return result is OK on success, FAILED if an error occurred.
-     *
-     * @return certificateChain is the X.509 certificate chain for the credentialKey
+     * @return the X.509 certificate chain for the credentialKey
      */
-    getAttestationCertificate(vec<uint8_t> attestationApplicationId,
-                              vec<uint8_t> attestationChallenge)
-        generates(Result result, vec<vec<uint8_t>> certificateChain);
+    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
@@ -103,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
@@ -121,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
@@ -145,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.
@@ -155,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.
@@ -171,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)
      *
@@ -196,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
@@ -230,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 = [
@@ -266,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/1.0/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp
similarity index 61%
rename from identity/1.0/default/WritableIdentityCredential.cpp
rename to identity/aidl/default/WritableIdentityCredential.cpp
index 4c39f85..ba2062d 100644
--- a/identity/1.0/default/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/WritableIdentityCredential.cpp
@@ -16,9 +16,6 @@
 
 #define LOG_TAG "WritableIdentityCredential"
 
-#include "WritableIdentityCredential.h"
-#include "IdentityCredentialStore.h"
-
 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
 
 #include <android-base/logging.h>
@@ -26,12 +23,315 @@
 #include <cppbor/cppbor.h>
 #include <cppbor/cppbor_parse.h>
 
-namespace android {
-namespace hardware {
-namespace identity {
-namespace implementation {
+#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|.
@@ -77,325 +377,8 @@
     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;
-}
-
-// TODO: use |attestationApplicationId| and |attestationChallenge| and also
-//       ensure the returned certificate chain satisfy the requirements listed in
-//       the docs for IWritableIdentityCredential::getAttestationCertificate()
-//
-Return<void> WritableIdentityCredential::getAttestationCertificate(
-        const hidl_vec<uint8_t>& /* attestationApplicationId */,
-        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());
-
-    optional<vector<vector<uint8_t>>> splitCertChain =
-            support::certificateChainSplit(certificateChain);
-    if (!splitCertChain) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error splitting certificate chain"), {});
-        return Void();
-    }
-    hidl_vec<hidl_vec<uint8_t>> ret;
-    ret.resize(splitCertChain.value().size());
-    std::copy(splitCertChain.value().begin(), splitCertChain.value().end(), ret.begin());
-    _hidl_cb(support::resultOK(), ret);
-    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) {
+ndk::ScopedAStatus WritableIdentityCredential::finishAddingEntries(
+        vector<int8_t>* outCredentialData, vector<int8_t>* outProofOfProvisioningSignature) {
     if (signedDataCurrentNamespace_.size() > 0) {
         signedDataNamespaces_.add(entryNameSpace_, std::move(signedDataCurrentNamespace_));
     }
@@ -412,29 +395,27 @@
                                                                  {},           // additionalData
                                                                  {});          // certificateChain
     if (!signature) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error signing data"), {}, {});
-        return Void();
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error signing data"));
     }
 
     vector<uint8_t> credentialKeys;
     if (!generateCredentialKeys(storageKey_, credentialPrivKey_, credentialKeys)) {
-        _hidl_cb(support::result(ResultCode::FAILED, "Error generating CredentialKeys"), {}, {});
-        return Void();
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error generating CredentialKeys"));
     }
 
     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();
+    if (!generateCredentialData(
+                testCredential_ ? support::getTestHardwareBoundKey() : getHardwareBoundKey(),
+                docType_, testCredential_, credentialKeys, credentialData)) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                IIdentityCredentialStore::STATUS_FAILED, "Error generating CredentialData"));
     }
 
-    _hidl_cb(support::resultOK(), credentialData, signature.value());
-    return Void();
+    *outCredentialData = byteStringToSigned(credentialData);
+    *outProofOfProvisioningSignature = byteStringToSigned(signature.value());
+    return ndk::ScopedAStatus::ok();
 }
 
-}  // namespace implementation
-}  // namespace identity
-}  // namespace hardware
-}  // namespace android
+}  // 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/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/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 993a105..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}
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 7886910..31a1a81 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -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/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 79f9c32..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,
@@ -262,14 +245,11 @@
      *
      * 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
@@ -279,9 +259,9 @@
      * used with different shapes of inputs on different (possibly concurrent)
      * executions.
      *
-     * @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.
@@ -307,8 +287,8 @@
      *     - 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(OptionalTimePoint deadline,
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 6030809..949438e 100644
--- a/neuralnetworks/1.3/IFencedExecutionCallback.hal
+++ b/neuralnetworks/1.3/IFencedExecutionCallback.hal
@@ -38,8 +38,8 @@
      *                - DEVICE_UNAVAILABLE if driver is offline or busy
      *                - GENERAL_FAILURE if the asynchronous task resulted in an
      *                  unspecified error
-     *                - 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 timingLaunched The duration starts when executeFenced is called and ends when
diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
index d645de7..a1814b5 100644
--- a/neuralnetworks/1.3/IPreparedModel.hal
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -70,14 +70,10 @@
      *
      * execute_1_3 can be called with an optional deadline. If the execution
      * is not able to be completed before the provided deadline, the execution
-     * must be aborted, and either {@link
+     * 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
@@ -89,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 the 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
@@ -105,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);
 
     /**
@@ -139,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
+     * 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 must be aborted, and either {@link
+     * 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
@@ -160,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 the 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
@@ -172,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.
@@ -187,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);
 
@@ -213,17 +228,13 @@
      * any data object referenced by 'request' (described by the
      * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}).
      *
-     * executeFenced can be called with an optional deadline and an optional duration.
+     * 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 must be aborted, and either
+     * signaled), whichever comes earlier, 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 executeFenced is called with a
-     * deadline or duration, then the argument is invalid, and
-     * {@link ErrorStatus::INVALID_ARGUMENT} must be returned.
      *
      * 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
@@ -240,21 +251,32 @@
      * @param waitFor A vector of sync fence file descriptors.
      *                Execution must not start until all sync fences have been signaled.
      * @param measure Specifies whether or not to measure duration of the execution.
-     * @param deadline The time by which the execution must complete. If the
-     *                 execution cannot be finished by the deadline, the
-     *                 execution must be aborted.
-     * @param duration The length of time within which the execution must
-     *                 complete after all sync fences in waitFor are signaled. If the
-     *                 execution cannot be finished within the duration, 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}.
+     * @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.
-     *                - 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 syncFence The sync fence that will be signaled when the task is completed.
@@ -264,6 +286,7 @@
      *                  and error status when the execution is completed.
      */
     executeFenced(Request request, vec<handle> waitFor, MeasureTiming measure,
-                  OptionalTimePoint deadline, OptionalTimeoutDuration duration)
+                  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 c5dc08c..daaf22e 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -1584,6 +1584,17 @@
      * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
      *      Available since HAL version 1.2.
+     * * 4: Align corners. An optional {@link OperandType::BOOL}
+     *      scalar, default to false.  If True, the centers of the 4 corner
+     *      pixels of the input and output tensors are aligned, preserving the
+     *      values at the corner pixels.
+     *      Available since HAL version 1.3.
+     * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+     *      scalar, default to false. If True, the pixel centers are assumed to
+     *      be at (0.5, 0.5). This is the default behavior of image.resize in
+     *      TF 2.0. If this parameter is True, then align_corners parameter
+     *      must be False.
+     *      Available since HAL version 1.3.
      *
      * Inputs (resizing by scale, since HAL version 1.2):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
@@ -1602,6 +1613,17 @@
      *      {@link OperandType::FLOAT32} otherwise.
      * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
+     * * 4: Align corners. An optional {@link OperandType::BOOL}
+     *      scalar, default to false.  If True, the centers of the 4 corner
+     *      pixels of the input and output tensors are aligned, preserving the
+     *      values at the corner pixels.
+     *      Available since HAL version 1.3.
+     * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+     *      scalar, default to false. If True, the pixel centers are assumed to
+     *      be at (0.5, 0.5). This is the default behavior of image.resize in
+     *      TF 2.0. If this parameter is True, then align_corners parameter
+     *      must be False.
+     *      Available since HAL version 1.3.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
@@ -2364,7 +2386,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 +2443,6 @@
      *
      * All input and output tensors must be of the same type.
      *
-     *
      * Inputs:
      * * 0: The input.
      *      A 3-D tensor of shape:
@@ -2466,25 +2534,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 +2633,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 +2684,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 +2695,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 +2709,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 +2761,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 +2797,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,
 
@@ -4656,6 +4792,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 +4856,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,
 
@@ -4743,6 +4892,17 @@
      *      height of the output tensor.
      * * 3: An {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
+     * * 4: Align corners. An optional {@link OperandType::BOOL}
+     *      scalar, default to false.  If True, the centers of the 4 corner
+     *      pixels of the input and output tensors are aligned, preserving the
+     *      values at the corner pixels.
+     *      Available since HAL version 1.3.
+     * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+     *      scalar, default to false. If True, the pixel centers are assumed to
+     *      be at (0.5, 0.5). This is the default behavior of image.resize in
+     *      TF 2.0. If this parameter is True, then align_corners parameter
+     *      must be False.
+     *      Available since HAL version 1.3.
      *
      * Inputs (resizing by scale):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
@@ -4761,6 +4921,17 @@
      *      {@link OperandType::FLOAT32} otherwise.
      * * 3: An {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
+     * * 4: Align corners. An optional {@link OperandType::BOOL}
+     *      scalar, default to false.  If True, the centers of the 4 corner
+     *      pixels of the input and output tensors are aligned, preserving the
+     *      values at the corner pixels.
+     *      Available since HAL version 1.3.
+     * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+     *      scalar, default to false. If True, the pixel centers are assumed to
+     *      be at (0.5, 0.5). This is the default behavior of image.resize in
+     *      TF 2.0. If this parameter is True, then align_corners parameter
+     *      must be False.
+     *      Available since HAL version 1.3.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
@@ -5127,8 +5298,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 +5324,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;
 };
 
 /**
@@ -5599,3 +5793,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 3d0d02d..0a6e45e 100644
--- a/neuralnetworks/1.3/types.t
+++ b/neuralnetworks/1.3/types.t
@@ -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;
 };
 
 /**
@@ -575,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/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 0bd24da..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,
     };
 }
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 82f34ff..8c9393b 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -74,7 +74,7 @@
 
 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 };
 
@@ -169,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);
@@ -195,26 +196,42 @@
     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,
+            };
         }
 
         V1_2::Operand::ExtraParams extraParams;
@@ -233,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 = {};
@@ -266,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;
 }
 
@@ -320,10 +355,10 @@
     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};
@@ -350,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);
@@ -398,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);
@@ -443,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 {
@@ -460,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;
@@ -510,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;
@@ -519,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));
 
@@ -536,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);
 
@@ -577,7 +627,7 @@
             hidl_handle syncFenceHandle;
             sp<IFencedExecutionCallback> fencedCallback;
             Return<void> ret = preparedModel->executeFenced(
-                    request, {}, testConfig.measureTiming, {}, {},
+                    request, {}, testConfig.measureTiming, {}, loopTimeoutDuration, {},
                     [&result, &syncFenceHandle, &fencedCallback](
                             ErrorStatus error, const hidl_handle& handle,
                             const sp<IFencedExecutionCallback>& callback) {
@@ -638,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);
     }
@@ -701,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) {
@@ -759,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);
@@ -796,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) {
@@ -828,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,
@@ -862,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 2f1e05c..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.nanosecondsSinceEpoch(nanosecondsSinceEpoch);
-        } break;
-        case DeadlineBoundType::UNLIMITED: {
-            uint64_t unlimited = std::numeric_limits<uint64_t>::max();
-            deadline.nanosecondsSinceEpoch(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 0a35e2d..7da2da9 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.nanosecondsSinceEpoch(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) {
@@ -577,6 +578,8 @@
     // - CONV_2D, DEPTHWISE_CONV_2D, MAX_POOL_2D, AVERAGE_POOL_2D, L2_POOL_2D, RESIZE_BILINEAR,
     //   SPACE_TO_DEPTH, SPACE_TO_DEPTH, SPACE_TO_BATCH_ND, BATCH_TO_SPACE_ND can have an optional
     //   layout parameter.
+    //   RESIZE_BILINEAR and RESIZE_NEAREST_NEIGHBOR can have optional
+    //   align_corners and half_pixel_centers parameters.
     // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional axis
     //   parameter.
     switch (op.type) {
@@ -599,7 +602,12 @@
             }
         } break;
         case OperationType::RESIZE_BILINEAR: {
-            if (op.inputs.size() == 4 && input == 3) {
+            if (op.inputs.size() >= 4 && input >= 3) {
+                return true;
+            }
+        } break;
+        case OperationType::RESIZE_NEAREST_NEIGHBOR: {
+            if (op.inputs.size() >= 5 && input >= 3) {
                 return true;
             }
         } break;
@@ -685,7 +693,9 @@
     //   parameter.
     if ((op.type == OperationType::L2_NORMALIZATION && op.inputs.size() == 1) ||
         (op.type == OperationType::LOCAL_RESPONSE_NORMALIZATION && op.inputs.size() == 5) ||
-        (op.type == OperationType::SOFTMAX && op.inputs.size() == 2)) {
+        (op.type == OperationType::SOFTMAX && op.inputs.size() == 2) ||
+        (op.type == OperationType::RESIZE_BILINEAR && op.inputs.size() < 6) ||
+        (op.type == OperationType::RESIZE_NEAREST_NEIGHBOR && op.inputs.size() < 6)) {
         return true;
     }
     return false;
@@ -736,19 +746,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 +764,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 2a4269f..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.nanosecondsSinceEpoch(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));
@@ -143,7 +137,7 @@
     {
         SCOPED_TRACE(message + " [executeFenced]");
         Return<void> ret =
-                preparedModel->executeFenced(request, {}, MeasureTiming::NO, deadline, {},
+                preparedModel->executeFenced(request, {}, MeasureTiming::NO, {}, {}, {},
                                              [](ErrorStatus error, const hidl_handle& handle,
                                                 const sp<IFencedExecutionCallback>& callback) {
                                                  ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
@@ -174,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 9a87569..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
@@ -137,7 +135,7 @@
 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, {}, {},
+            request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, {}, {}, {},
             [](ErrorStatus error, const hidl_handle& handle,
                const sp<IFencedExecutionCallback>& callback) {
                 ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
@@ -147,17 +145,15 @@
     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.
@@ -166,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;
@@ -185,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.5/IRadio.hal b/radio/1.5/IRadio.hal
index 2ec92e5..87824e2 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -69,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.
@@ -209,7 +238,8 @@
      * 1) Emergency call is completed; or
      * 2) Another setRadioPower_1_5 is issued with forEmergencyCall being false or
      * preferredForEmergencyCall being false; or
-     * 3) Timeout after a long period of time.
+     * 3) Timeout after 30 seconds if dial or emergencyDial is not called.
+     * Once one of these conditions is reached, the modem should move into normal operation.
      *
      * @param serial Serial number of request.
      * @param powerOn To turn on radio -> on = true, to turn off radio -> on = false.
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index 543f9b5..e87cad2 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -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
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 448e5c8..4d3c2d5 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -156,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,
 };
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 621825f..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.
  */
@@ -1069,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 6f65cbb..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;
 
@@ -531,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);
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index 17b294b..e4f9ce8 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -894,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);
@@ -963,9 +970,11 @@
 
 Return<void> RadioResponse_v1_5::getBarringInfoResponse(
         const RadioResponseInfo& info,
-        const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
+        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();
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 aef0ff8..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            = 1 << 2,
-    /** GSM/EDGE capability. */
-    GERAN                     = 1 << 3,
-    /** UMTS capability. */
-    UTRAN                     = 1 << 4,
-    /** LTE capability. */
-    EUTRAN                    = 1 << 5,
-    /** 5G capability. */
-    NGRAN                     = 1 << 6,
-    /** 5G dual connectivity capability. */
-    EN_DC                     = 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_APP                  = 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/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/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 540529d..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 = std::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 54e899b..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,11 +19,15 @@
 
 #include "sensors-vts-utils/SensorEventsChecker.h"
 #include "sensors-vts-utils/SensorsHidlEnvironmentBase.h"
+#include "sensors-vts-utils/SensorsTestSharedMemory.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>
 
@@ -34,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 {
@@ -66,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;
@@ -83,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 |
@@ -97,32 +592,71 @@
                                         (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;
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/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/types.hal b/tv/tuner/1.0/types.hal
index e4874f4..dd2b48f 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -1924,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.
      */
@@ -1933,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,
 };
 
 /**
@@ -2151,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/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.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
index a040c89..f596195 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -831,6 +831,16 @@
         global_handle_, mode, completion_window);
 }
 
+wifi_error WifiLegacyHal::setDscpToAccessCategoryMapping(
+    uint32_t start, uint32_t end, uint32_t access_category) {
+    return global_func_table_.wifi_map_dscp_access_category(
+        global_handle_, start, end, access_category);
+}
+
+wifi_error WifiLegacyHal::resetDscpToAccessCategoryMapping() {
+    return global_func_table_.wifi_reset_dscp_mapping(global_handle_);
+}
+
 std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
     const std::string& iface_name) {
     uint32_t supported_feature_flags;
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h
index 72cf197..c21563e 100644
--- a/wifi/1.4/default/wifi_legacy_hal.h
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -261,6 +261,9 @@
                               wifi_latency_mode mode);
     wifi_error setThermalMitigationMode(wifi_thermal_mode mode,
                                         uint32_t completion_window);
+    wifi_error setDscpToAccessCategoryMapping(uint32_t start, uint32_t end,
+                                              uint32_t access_category);
+    wifi_error resetDscpToAccessCategoryMapping();
     // Logger/debug functions.
     std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(
         const std::string& iface_name);
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
index 6945b4c..153a685 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
@@ -141,6 +141,8 @@
     populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
     populateStubFor(&hal_fn->wifi_virtual_interface_create);
     populateStubFor(&hal_fn->wifi_virtual_interface_delete);
+    populateStubFor(&hal_fn->wifi_map_dscp_access_category);
+    populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
     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/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.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.