Merge "Update language in VtsHalPowerV1_0TargetTest to comply with Android’s inclusive language guidance" am: 2f13308369 am: 113dda058c

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1375192

Change-Id: I8d679947c596cfb51793811d8912fdf92255ac8e
diff --git a/Android.bp b/Android.bp
index f64968f..9e1df13 100644
--- a/Android.bp
+++ b/Android.bp
@@ -21,7 +21,7 @@
 
     // Lists all dependencies that can *not* be expected on the device.
     static_libs: [
-        "VtsHalHidlTargetTestBase",
+        "VtsHalHidlTestUtils",
         "libhidl-gen-utils",
     ],
 
@@ -47,3 +47,15 @@
 
     require_root: true,
 }
+
+// TODO: Remove this after all vts tests under vendor/qcom are converted to
+// parameterized gtest.
+cc_defaults {
+    name: "Vts10HalTargetTestDefaults",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetTestBase",
+    ],
+}
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 76594fb..1eca2a1 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -84,3 +84,4 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.cas@1.1*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.cas@1.1*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/vintf/manifest/android.hardware.cas@1.1*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/hardware/interfaces/wifi/1.4/android.hardware.wifi@1.4-adapter_genc++/)
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 543acf6..acae4f3 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -8,6 +8,9 @@
     },
     {
       "name": "hal_implementation_test"
+    },
+    {
+      "name": "VtsHalTvInputV1_0TargetTest"
     }
   ]
 }
diff --git a/audio/6.0/Android.bp b/audio/6.0/Android.bp
index 5a22f3b..d7880b6 100644
--- a/audio/6.0/Android.bp
+++ b/audio/6.0/Android.bp
@@ -12,6 +12,7 @@
         "IStreamIn.hal",
         "IStreamOut.hal",
         "IStreamOutCallback.hal",
+        "IStreamOutEventCallback.hal",
     ],
     interfaces: [
         "android.hardware.audio.common@6.0",
diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
index 2347696..2026d8f 100644
--- a/audio/6.0/IDevice.hal
+++ b/audio/6.0/IDevice.hal
@@ -149,7 +149,10 @@
                     AudioConfig suggestedConfig);
 
     /**
-     * Returns whether HAL supports audio patches.
+     * Returns whether HAL supports audio patches. Patch represents a connection
+     * between signal source(s) and signal sink(s). If HAL doesn't support
+     * patches natively (in hardware) then audio system will need to establish
+     * them in software.
      *
      * @return supports true if audio patches are supported.
      */
@@ -168,6 +171,25 @@
             generates (Result retval, AudioPatchHandle patch);
 
     /**
+     * Updates an audio patch.
+     *
+     * Use of this function is preferred to releasing and re-creating a patch
+     * as the HAL module can figure out a way of switching the route without
+     * causing audio disruption.
+     *
+     * @param previousPatch handle of the previous patch to update.
+     * @param sources new patch sources.
+     * @param sinks new patch sinks.
+     * @return retval operation completion status.
+     * @return patch updated patch handle.
+     */
+    updateAudioPatch(
+            AudioPatchHandle previousPatch,
+            vec<AudioPortConfig> sources,
+            vec<AudioPortConfig> sinks) generates (
+                    Result retval, AudioPatchHandle patch);
+
+    /**
      * Release an audio patch.
      *
      * @param patch patch handle.
@@ -297,7 +319,9 @@
     close() generates (Result retval);
 
     /**
-     * Applies an audio effect to an audio device.
+     * Applies an audio effect to an audio device. The effect is inserted
+     * according to its insertion preference specified by INSERT_... EffectFlags
+     * in the EffectDescriptor.
      *
      * @param device identifies the sink or source device this effect must be applied to.
      *               "device" is the AudioPortHandle indicated for the device when the audio
diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal
index d7d3c84..2ea1ab3 100644
--- a/audio/6.0/IStream.hal
+++ b/audio/6.0/IStream.hal
@@ -274,6 +274,7 @@
      *
      * @param minSizeFrames minimum buffer size requested. The actual buffer
      *                     size returned in struct MmapBufferInfo can be larger.
+     *                     The size must be a positive value.
      * @return retval OK in case the success.
      *                NOT_SUPPORTED on non mmap mode streams
      *                NOT_INITIALIZED in case of memory allocation error
diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal
index 941ba61..9da48fe 100644
--- a/audio/6.0/IStreamOut.hal
+++ b/audio/6.0/IStreamOut.hal
@@ -19,6 +19,7 @@
 import android.hardware.audio.common@6.0;
 import IStream;
 import IStreamOutCallback;
+import IStreamOutEventCallback;
 
 interface IStreamOut extends IStream {
     /**
@@ -168,6 +169,18 @@
     clearCallback() generates (Result retval);
 
     /**
+     * Set the callback interface for notifying about an output stream event.
+     *
+     * Calling this method with a null pointer will result in releasing
+     * the local callback proxy on the server side and thus dereference
+     * the callback implementation on the client side.
+     *
+     * @return retval operation completion status.
+     */
+    setEventCallback(IStreamOutEventCallback callback)
+            generates (Result retval);
+
+    /**
      * Returns whether HAL supports pausing and resuming of streams.
      *
      * @return supportsPause true if pausing is supported.
@@ -276,4 +289,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/IStreamOutEventCallback.hal b/audio/6.0/IStreamOutEventCallback.hal
new file mode 100644
index 0000000..9c88713
--- /dev/null
+++ b/audio/6.0/IStreamOutEventCallback.hal
@@ -0,0 +1,140 @@
+/*
+ * 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.audio@6.0;
+
+/**
+ * Asynchronous stream out event callback interface. The interface provides
+ * a way for the HAL to notify platform when there are changes, e.g. codec
+ * format change, from the lower layer.
+ */
+interface IStreamOutEventCallback {
+    /**
+     * Codec format changed.
+     *
+     * onCodecFormatChanged returns an AudioMetadata object in read-only ByteString format.
+     * It represents the most recent codec format decoded by a HW audio decoder.
+     *
+     * Codec format is an optional message from HW audio decoders. It serves to
+     * notify the application about the codec format and audio objects contained
+     * within the compressed audio stream for control, informational,
+     * and display purposes.
+     *
+     * audioMetadata ByteString is convertible to an AudioMetadata object through
+     * both a C++ and a C API present in Metadata.h [1], or through a Java API present
+     * in AudioMetadata.java [2].
+     *
+     * The ByteString format is a stable format used for parcelling (marshalling) across
+     * JNI, AIDL, and HIDL interfaces.  The test for R compatibility for native marshalling
+     * is TEST(metadata_tests, compatibility_R) [3].  The test for R compatibility for JNI
+     * marshalling is android.media.cts.AudioMetadataTest#testCompatibilityR [4].
+     *
+     * R (audio HAL 6.0) defined keys are as follows [2]:
+     * "bitrate", int32
+     * "channel-mask", int32
+     * "mime", string
+     * "sample-rate", int32
+     * "bit-width", int32
+     * "has-atmos", int32
+     * "audio-encoding", int32
+     *
+     * Parceling Format:
+     * All values are native endian order. [1]
+     *
+     * using type_size_t = uint32_t;
+     * using index_size_t = uint32_t;
+     * using datum_size_t = uint32_t;
+     *
+     * Permitted type indexes are
+     * TYPE_NONE = 0, // Reserved
+     * TYPE_INT32 = 1,
+     * TYPE_INT64 = 2,
+     * TYPE_FLOAT = 3,
+     * TYPE_DOUBLE = 4,
+     * TYPE_STRING = 5,
+     * TYPE_DATA = 6,  // A data table of <String, Datum>
+     *
+     * Datum = {
+     *           (type_size_t)  Type (the type index from type_as_value<T>.)
+     *           (datum_size_t) Size (size of the Payload)
+     *           (byte string)  Payload<Type>
+     *         }
+     *
+     * The data is specified in native endian order.
+     * Since the size of the Payload is always present, unknown types may be skipped.
+     *
+     * Payload<Fixed-size Primitive_Value>
+     * [ sizeof(Primitive_Value) in raw bytes ]
+     *
+     * Example of Payload<Int32> of 123:
+     * Payload<Int32>
+     * [ value of 123                   ] =  0x7b 0x00 0x00 0x00       123
+     *
+     * Payload<String>
+     * [ (index_size_t) length, not including zero terminator.]
+     * [ (length) raw bytes ]
+     *
+     * Example of Payload<String> of std::string("hi"):
+     * [ (index_size_t) length          ] = 0x02 0x00 0x00 0x00        2 strlen("hi")
+     * [ raw bytes "hi"                 ] = 0x68 0x69                  "hi"
+     *
+     * Payload<Data>
+     * [ (index_size_t) entries ]
+     * [ raw bytes   (entry 1) Key   (Payload<String>)
+     *                         Value (Datum)
+     *                ...  (until #entries) ]
+     *
+     * Example of Payload<Data> of {{"hello", "world"},
+     *                              {"value", (int32_t)1000}};
+     * [ (index_size_t) #entries        ] = 0x02 0x00 0x00 0x00        2 entries
+     *    Key (Payload<String>)
+     *    [ index_size_t length         ] = 0x05 0x00 0x00 0x00        5 strlen("hello")
+     *    [ raw bytes "hello"           ] = 0x68 0x65 0x6c 0x6c 0x6f   "hello"
+     *    Value (Datum)
+     *    [ (type_size_t) type          ] = 0x05 0x00 0x00 0x00        5 (TYPE_STRING)
+     *    [ (datum_size_t) size         ] = 0x09 0x00 0x00 0x00        sizeof(index_size_t) +
+     *                                                                 strlen("world")
+     *       Payload<String>
+     *       [ (index_size_t) length    ] = 0x05 0x00 0x00 0x00        5 strlen("world")
+     *       [ raw bytes "world"        ] = 0x77 0x6f 0x72 0x6c 0x64   "world"
+     *    Key (Payload<String>)
+     *    [ index_size_t length         ] = 0x05 0x00 0x00 0x00        5 strlen("value")
+     *    [ raw bytes "value"           ] = 0x76 0x61 0x6c 0x75 0x65   "value"
+     *    Value (Datum)
+     *    [ (type_size_t) type          ] = 0x01 0x00 0x00 0x00        1 (TYPE_INT32)
+     *    [ (datum_size_t) size         ] = 0x04 0x00 0x00 0x00        4 sizeof(int32_t)
+     *        Payload<Int32>
+     *        [ raw bytes 1000          ] = 0xe8 0x03 0x00 0x00        1000
+     *
+     * The contents of audioMetadata is a Payload<Data>.
+     * An implementation dependent detail is that the Keys are always
+     * stored sorted, so the byte string representation generated is unique.
+     *
+     * Vendor keys are allowed for informational and debugging purposes.
+     * Vendor keys should consist of the vendor company name followed
+     * by a dot; for example, "vendorCompany.someVolume" [2].
+     *
+     * [1] system/media/audio_utils/include/audio_utils/Metadata.h
+     * [2] frameworks/base/media/java/android/media/AudioMetadata.java
+     * [3] system/media/audio_utils/tests/metadata_tests.cpp
+     * [4] cts/tests/tests/media/src/android/media/cts/AudioMetadataTest.java
+     *
+     * @param audioMetadata is a buffer containing decoded format changes
+     *     reported by codec. The buffer contains data that can be transformed
+     *     to audio metadata, which is a C++ object based map.
+     */
+    oneway onCodecFormatChanged(vec<uint8_t> audioMetadata);
+};
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
index adab3d2..6b49e5e 100644
--- a/audio/6.0/config/api/current.txt
+++ b/audio/6.0/config/api/current.txt
@@ -258,8 +258,10 @@
 
   public class GlobalConfiguration {
     ctor public GlobalConfiguration();
+    method public boolean getCall_screen_mode_supported();
     method public audio.policy.configuration.V6_0.EngineSuffix getEngine_library();
     method public boolean getSpeaker_drc_enabled();
+    method public void setCall_screen_mode_supported(boolean);
     method public void setEngine_library(audio.policy.configuration.V6_0.EngineSuffix);
     method public void setSpeaker_drc_enabled(boolean);
   }
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
index 3fc60e2..341c6b3 100644
--- a/audio/6.0/config/audio_policy_configuration.xsd
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -66,6 +66,7 @@
     </xs:element>
     <xs:complexType name="globalConfiguration">
         <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+        <xs:attribute name="call_screen_mode_supported" type="xs:boolean" use="optional"/>
         <xs:attribute name="engine_library" type="engineSuffix" use="optional"/>
     </xs:complexType>
     <xs:complexType name="modules">
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/README b/audio/README
index abe979c..afafbe3 100644
--- a/audio/README
+++ b/audio/README
@@ -1,5 +1,8 @@
 Directory structure of the audio HIDL related code.
 
+Run `common/all-versions/copyHAL.sh` to create a new version of the audio HAL
+based on an existing one.
+
 audio
 |-- 2.0              <== core 2.0 HIDL API. .hal can not be moved into the core directory
 |                        because that would change its namespace and include path
@@ -11,13 +14,13 @@
 |   |-- 2.0          <== HIDL API of V2
 |   |-- 4.0
 |   |-- ...
-|   `-- all_versions <== code common to all version of both core and effect API
+|   `-- all-versions <== code common to all version of both core and effect API
 |       |-- default  <== implementation shared code between core and effect impl
 |       |-- test     <== utilities used by tests
 |       `-- util     <== utilities used by both implementation and tests
 |
 |-- core             <== VTS and default implementation of the core API (not HIDL, see /audio/2.0))
-|   `-- all_versions <== Code is version independent through #if and separate files
+|   `-- all-versions <== Code is version independent through #if and separate files
 |       |-- default  <== code that wraps the legacy API
 |       `-- vts      <== vts of core API
 |           |-- 2.0  <== 2.0 specific tests and helpers
@@ -28,6 +31,6 @@
     |-- 2.0
     |-- 4.0
     |-- ...
-    `-- all_versions
+    `-- all-versions
         |-- default
         `-- vts
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
index da506d6..67217ab 100644
--- a/audio/common/6.0/types.hal
+++ b/audio/common/6.0/types.hal
@@ -91,37 +91,76 @@
 enum AudioStreamType : int32_t {
     // These values must kept in sync with
     //  frameworks/base/media/java/android/media/AudioSystem.java
+    /** Used to identify the default audio stream volume. */
     DEFAULT          = -1,
+    /** Specifies the minimum value for use in checks and loops. */
     MIN              = 0,
+    /** Used to identify the volume of audio streams for phone calls. */
     VOICE_CALL       = 0,
+    /** Used to identify the volume of audio streams for system sounds. */
     SYSTEM           = 1,
+    /**
+     * Used to identify the volume of audio streams for the phone ring
+     * and message alerts.
+     */
     RING             = 2,
+    /** Used to identify the volume of audio streams for music playback. */
     MUSIC            = 3,
+    /** Used to identify the volume of audio streams for alarms. */
     ALARM            = 4,
+    /** Used to identify the volume of audio streams for notifications. */
     NOTIFICATION     = 5,
+    /**
+     * Used to identify the volume of audio streams for phone calls
+     * when connected on bluetooth.
+     */
     BLUETOOTH_SCO    = 6,
-    ENFORCED_AUDIBLE = 7,  // Sounds that cannot be muted by user and must be
-                           // routed to speaker
+    /**
+     * Used to identify the volume of audio streams for enforced system
+     * sounds in certain countries (e.g camera in Japan). */
+    ENFORCED_AUDIBLE = 7,
+    /** Used to identify the volume of audio streams for DTMF tones. */
     DTMF             = 8,
-    TTS              = 9,  // Transmitted Through Speaker.  Plays over speaker
-                           // only, silent on other devices
-    ACCESSIBILITY    = 10, // For accessibility talk back prompts
-    ASSISTANT        = 11, // For virtual assistant service
+    /**
+     * Used to identify the volume of audio streams exclusively transmitted
+     * through the speaker (TTS) of the device.
+     */
+    TTS              = 9,
+    /**
+     * Used to identify the volume of audio streams for accessibility prompts.
+     */
+    ACCESSIBILITY    = 10,
+    /** Used to identify the volume of audio streams for virtual assistant. */
+    ASSISTANT        = 11,
 };
 
 @export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
 enum AudioSource : int32_t {
     // These values must kept in sync with
     //  frameworks/base/media/java/android/media/MediaRecorder.java,
-    //  frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
     //  system/media/audio_effects/include/audio_effects/audio_effects_conf.h
+    /** Default audio source. */
     DEFAULT             = 0,
+    /** Microphone audio source. */
     MIC                 = 1,
+    /** Voice call uplink (Tx) audio source. */
     VOICE_UPLINK        = 2,
+    /** Voice call downlink (Rx) audio source. */
     VOICE_DOWNLINK      = 3,
+    /** Voice call uplink + downlink audio source. */
     VOICE_CALL          = 4,
+    /**
+     * Microphone audio source tuned for video recording, with the same
+     * orientation as the camera if available.
+     */
     CAMCORDER           = 5,
+    /** Microphone audio source tuned for voice recognition. */
     VOICE_RECOGNITION   = 6,
+    /**
+     * Microphone audio source tuned for voice communications such as VoIP. It
+     * will for instance take advantage of echo cancellation or automatic gain
+     * control if available.
+     */
     VOICE_COMMUNICATION = 7,
     /**
      * Source for the mix to be presented remotely. An example of remote
@@ -146,7 +185,9 @@
      * to include all post processing applied to the playback path.
      */
     ECHO_REFERENCE      = 1997,
+    /** Virtual source for the built-in FM tuner. */
     FM_TUNER            = 1998,
+    /** Virtual source for the last captured hotword. */
     HOTWORD             = 1999,
 };
 
@@ -562,6 +603,8 @@
     IN_CALL          = 2,
     /** Calls handled by apps (Eg: Hangout). */
     IN_COMMUNICATION = 3,
+    /** Call screening in progress. */
+    CALL_SCREEN      = 4,
 };
 
 @export(name="", value_prefix="AUDIO_DEVICE_")
@@ -738,6 +781,7 @@
     MMAP_NOIRQ   = 0x10, // input operates in MMAP no IRQ mode.
     VOIP_TX      = 0x20, // preferred input for VoIP calls.
     HW_AV_SYNC   = 0x40, // input connected to an output that uses a hardware A/V sync
+    DIRECT       = 0x80, // for acquiring encoded streams
 };
 
 @export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
@@ -745,19 +789,86 @@
     // These values must kept in sync with
     //  frameworks/base/media/java/android/media/AudioAttributes.java
     // Note that not all framework values are exposed
+    /**
+     * Usage value to use when the usage is unknown.
+     */
     UNKNOWN                            = 0,
+    /**
+     * Usage value to use when the usage is media, such as music, or movie
+     * soundtracks.
+     */
     MEDIA                              = 1,
+    /**
+     * Usage value to use when the usage is voice communications, such as
+     * telephony or VoIP.
+     */
     VOICE_COMMUNICATION                = 2,
+    /**
+     * Usage value to use when the usage is in-call signalling, such as with
+     * a "busy" beep, or DTMF tones.
+     */
     VOICE_COMMUNICATION_SIGNALLING     = 3,
+    /**
+     * Usage value to use when the usage is an alarm (e.g. wake-up alarm).
+     */
     ALARM                              = 4,
+    /**
+     * Usage value to use when the usage is a generic notification.
+     */
     NOTIFICATION                       = 5,
+    /**
+     * Usage value to use when the usage is telephony ringtone.
+     */
     NOTIFICATION_TELEPHONY_RINGTONE    = 6,
+    /**
+     * Usage value to use when the usage is for accessibility, such as with
+     * a screen reader.
+     */
     ASSISTANCE_ACCESSIBILITY           = 11,
+    /**
+     * Usage value to use when the usage is driving or navigation directions.
+     */
     ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
+    /**
+     * Usage value to use when the usage is sonification, such as  with user
+     * interface sounds.
+     */
     ASSISTANCE_SONIFICATION            = 13,
+    /**
+     * Usage value to use when the usage is for game audio.
+     */
     GAME                               = 14,
+    /**
+     * Usage value to use when feeding audio to the platform and replacing
+     * "traditional" audio source, such as audio capture devices.
+     */
     VIRTUAL_SOURCE                     = 15,
+    /**
+     * Usage value to use for audio responses to user queries, audio
+     * instructions or help utterances.
+     */
     ASSISTANT                          = 16,
+    /**
+     * Usage value to use for assistant voice interaction with remote caller
+     * on Cell and VoIP calls.
+     */
+    CALL_ASSISTANT                     = 17,
+    /**
+     * Usage value to use when the usage is an emergency.
+     */
+    EMERGENCY                          = 1000,
+    /**
+     * Usage value to use when the usage is a safety sound.
+     */
+    SAFETY                             = 1001,
+    /**
+     * Usage value to use when the usage is a vehicle status.
+     */
+    VEHICLE_STATUS                     = 1002,
+    /**
+     * Usage value to use when the usage is an announcement.
+     */
+    ANNOUNCEMENT                       = 1003,
 };
 
 /** Type of audio generated by an application. */
@@ -765,13 +876,52 @@
 enum AudioContentType : uint32_t {
     // Do not change these values without updating their counterparts
     // in frameworks/base/media/java/android/media/AudioAttributes.java
+    /**
+     * Content type value to use when the content type is unknown, or other than
+     * the ones defined.
+     */
     UNKNOWN      = 0,
+    /**
+     * Content type value to use when the content type is speech.
+     */
     SPEECH       = 1,
+    /**
+     * Content type value to use when the content type is music.
+     */
     MUSIC        = 2,
+    /**
+     * Content type value to use when the content type is a soundtrack,
+     * typically accompanying a movie or TV program.
+     */
     MOVIE        = 3,
+    /**
+     * Content type value to use when the content type is a sound used to
+     * accompany a user action, such as a beep or sound effect expressing a key
+     * click, or event, such as the type of a sound for a bonus being received
+     * in a game. These sounds are mostly synthesized or short Foley sounds.
+     */
     SONIFICATION = 4,
 };
 
+/** 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.
  */
@@ -787,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/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 7331b0a..147d062 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -80,6 +80,7 @@
     const std::vector<InterfacesList> optionalInterfaces = {
         {
             "Soundtrigger API",
+            "android.hardware.soundtrigger@2.3::ISoundTriggerHw",
             "android.hardware.soundtrigger@2.2::ISoundTriggerHw",
             "android.hardware.soundtrigger@2.1::ISoundTriggerHw",
             "android.hardware.soundtrigger@2.0::ISoundTriggerHw",
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index ad841ca..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};
 }
 
@@ -269,12 +271,21 @@
 Return<void> Device::createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
                                       const hidl_vec<AudioPortConfig>& sinks,
                                       createAudioPatch_cb _hidl_cb) {
+    auto [retval, patch] = createOrUpdateAudioPatch(
+            static_cast<AudioPatchHandle>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE), sources,
+            sinks);
+    _hidl_cb(retval, patch);
+    return Void();
+}
+
+std::tuple<Result, AudioPatchHandle> Device::createOrUpdateAudioPatch(
+        AudioPatchHandle patch, const hidl_vec<AudioPortConfig>& sources,
+        const hidl_vec<AudioPortConfig>& sinks) {
     Result retval(Result::NOT_SUPPORTED);
-    AudioPatchHandle patch = 0;
     if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
         std::unique_ptr<audio_port_config[]> halSources(HidlUtils::audioPortConfigsToHal(sources));
         std::unique_ptr<audio_port_config[]> halSinks(HidlUtils::audioPortConfigsToHal(sinks));
-        audio_patch_handle_t halPatch = AUDIO_PATCH_HANDLE_NONE;
+        audio_patch_handle_t halPatch = static_cast<audio_patch_handle_t>(patch);
         retval = analyzeStatus("create_audio_patch",
                                mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0],
                                                            sinks.size(), &halSinks[0], &halPatch));
@@ -282,8 +293,7 @@
             patch = static_cast<AudioPatchHandle>(halPatch);
         }
     }
-    _hidl_cb(retval, patch);
-    return Void();
+    return {retval, patch};
 }
 
 Return<Result> Device::releaseAudioPatch(int32_t patch) {
@@ -438,6 +448,19 @@
     }
 }
 
+Return<void> Device::updateAudioPatch(int32_t previousPatch,
+                                      const hidl_vec<AudioPortConfig>& sources,
+                                      const hidl_vec<AudioPortConfig>& sinks,
+                                      createAudioPatch_cb _hidl_cb) {
+    if (previousPatch != static_cast<int32_t>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE)) {
+        auto [retval, patch] = createOrUpdateAudioPatch(previousPatch, sources, sinks);
+        _hidl_cb(retval, patch);
+    } else {
+        _hidl_cb(Result::INVALID_ARGUMENTS, previousPatch);
+    }
+    return Void();
+}
+
 #endif
 
 }  // namespace implementation
diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp
index 0f1aba0..11c1c5a 100644
--- a/audio/core/all-versions/default/PrimaryDevice.cpp
+++ b/audio/core/all-versions/default/PrimaryDevice.cpp
@@ -176,6 +176,13 @@
 Return<Result> PrimaryDevice::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) {
     return mDevice->removeDeviceEffect(device, effectId);
 }
+
+Return<void> PrimaryDevice::updateAudioPatch(int32_t previousPatch,
+                                             const hidl_vec<AudioPortConfig>& sources,
+                                             const hidl_vec<AudioPortConfig>& sinks,
+                                             updateAudioPatch_cb _hidl_cb) {
+    return mDevice->updateAudioPatch(previousPatch, sources, sinks, _hidl_cb);
+}
 #endif
 
 // Methods from ::android::hardware::audio::CPP_VERSION::IPrimaryDevice follow.
@@ -196,6 +203,9 @@
         case AudioMode::RINGTONE:
         case AudioMode::IN_CALL:
         case AudioMode::IN_COMMUNICATION:
+#if MAJOR_VERSION >= 6
+        case AudioMode::CALL_SCREEN:
+#endif
             break;  // Valid values
         default:
             return Result::INVALID_ARGUMENTS;
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 1a2a764..1519c48 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -22,6 +22,8 @@
 //#define LOG_NDEBUG 0
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
+#include <string.h>
+
 #include <memory>
 
 #include <android/log.h>
@@ -453,20 +455,22 @@
     sp<IStreamOutCallback> callback = self->mCallback;
     if (callback.get() == nullptr) return 0;
     ALOGV("asyncCallback() event %d", event);
+    Return<void> result;
     switch (event) {
         case STREAM_CBK_EVENT_WRITE_READY:
-            callback->onWriteReady();
+            result = callback->onWriteReady();
             break;
         case STREAM_CBK_EVENT_DRAIN_READY:
-            callback->onDrainReady();
+            result = callback->onDrainReady();
             break;
         case STREAM_CBK_EVENT_ERROR:
-            callback->onError();
+            result = callback->onError();
             break;
         default:
             ALOGW("asyncCallback() unknown event %d", event);
             break;
     }
+    ALOGW_IF(!result.isOk(), "Client callback failed: %s", result.description().c_str());
     return 0;
 }
 
@@ -582,6 +586,67 @@
 }
 #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;
+}
+
+Return<Result> StreamOut::setEventCallback(const sp<IStreamOutEventCallback>& callback) {
+    if (mStream->set_event_callback == nullptr) return Result::NOT_SUPPORTED;
+    int result = mStream->set_event_callback(mStream, StreamOut::asyncEventCallback, this);
+    if (result == 0) {
+        mEventCallback = callback;
+    }
+    return Stream::analyzeStatus("set_stream_out_callback", result, {ENOSYS} /*ignore*/);
+}
+
+// static
+int StreamOut::asyncEventCallback(stream_event_callback_type_t event, void* param, void* cookie) {
+    StreamOut* self = reinterpret_cast<StreamOut*>(cookie);
+    sp<IStreamOutEventCallback> eventCallback = self->mEventCallback;
+    if (eventCallback.get() == nullptr) return 0;
+    ALOGV("%s event %d", __func__, event);
+    Return<void> result;
+    switch (event) {
+        case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED: {
+            hidl_vec<uint8_t> audioMetadata;
+            audioMetadata.setToExternal((uint8_t*)param, strlen((char*)param));
+            result = eventCallback->onCodecFormatChanged(audioMetadata);
+        } break;
+        default:
+            ALOGW("%s unknown event %d", __func__, event);
+            break;
+    }
+    ALOGW_IF(!result.isOk(), "Client callback failed: %s", result.description().c_str());
+    return 0;
+}
+#endif
+
 }  // namespace implementation
 }  // namespace CPP_VERSION
 }  // namespace audio
diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h
index 80a9638..b0e72d9 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -118,6 +118,9 @@
     Return<Result> close() override;
     Return<Result> addDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
     Return<Result> removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
+    Return<void> updateAudioPatch(int32_t previousPatch, const hidl_vec<AudioPortConfig>& sources,
+                                  const hidl_vec<AudioPortConfig>& sinks,
+                                  createAudioPatch_cb _hidl_cb) override;
 #endif
     Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
@@ -136,6 +139,9 @@
     virtual ~Device();
 
     Result doClose();
+    std::tuple<Result, AudioPatchHandle> createOrUpdateAudioPatch(
+            AudioPatchHandle patch, const hidl_vec<AudioPortConfig>& sources,
+            const hidl_vec<AudioPortConfig>& sinks);
 
     // Methods from ParametersUtil.
     char* halGetParameters(const char* keys) override;
diff --git a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
index 9fc90c3..ccdb7b2 100644
--- a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
+++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
@@ -100,6 +100,9 @@
     Return<Result> close() override;
     Return<Result> addDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
     Return<Result> removeDeviceEffect(AudioPortHandle device, uint64_t effectId) override;
+    Return<void> updateAudioPatch(int32_t previousPatch, const hidl_vec<AudioPortConfig>& sources,
+                                  const hidl_vec<AudioPortConfig>& sinks,
+                                  updateAudioPatch_cb _hidl_cb) override;
 #endif
 
     Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
diff --git a/audio/core/all-versions/default/include/core/default/Stream.h b/audio/core/all-versions/default/include/core/default/Stream.h
index 91df0c7..ce0003b 100644
--- a/audio/core/all-versions/default/include/core/default/Stream.h
+++ b/audio/core/all-versions/default/include/core/default/Stream.h
@@ -157,6 +157,10 @@
     native_handle_t* hidlHandle = nullptr;
 
     if (mStream->create_mmap_buffer != NULL) {
+        if (minSizeFrames <= 0) {
+            retval = Result::INVALID_ARGUMENTS;
+            goto exit;
+        }
         struct audio_mmap_buffer_info halInfo;
         retval = Stream::analyzeStatus(
             "create_mmap_buffer", mStream->create_mmap_buffer(mStream, minSizeFrames, &halInfo));
@@ -184,6 +188,7 @@
             info.burstSizeFrames = halInfo.burst_size_frames;
         }
     }
+exit:
     _hidl_cb(retval, info);
     if (hidlHandle != nullptr) {
         native_handle_delete(hidlHandle);
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..e647da9 100644
--- a/audio/core/all-versions/default/include/core/default/StreamOut.h
+++ b/audio/core/all-versions/default/include/core/default/StreamOut.h
@@ -121,16 +121,31 @@
     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);
 
-   private:
+#if MAJOR_VERSION >= 6
+    Return<Result> setEventCallback(const sp<IStreamOutEventCallback>& callback) override;
+#endif
+
+  private:
     const sp<Device> mDevice;
     audio_stream_out_t* mStream;
     const sp<Stream> mStreamCommon;
     const sp<StreamMmap<audio_stream_out_t>> mStreamMmap;
-    sp<IStreamOutCallback> mCallback;
+    sp<IStreamOutCallback> mCallback;  // Callback for non-blocking write and drain
+#if MAJOR_VERSION >= 6
+    sp<IStreamOutEventCallback> mEventCallback;
+#endif
     std::unique_ptr<CommandMQ> mCommandMQ;
     std::unique_ptr<DataMQ> mDataMQ;
     std::unique_ptr<StatusMQ> mStatusMQ;
@@ -141,6 +156,10 @@
     virtual ~StreamOut();
 
     static int asyncCallback(stream_callback_event_t event, void* param, void* cookie);
+
+#if MAJOR_VERSION >= 6
+    static int asyncEventCallback(stream_event_callback_type_t event, void* param, void* cookie);
+#endif
 };
 
 }  // namespace implementation
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index 709b7cd..b0eb2e0 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -244,7 +244,13 @@
 TEST_P(AudioPrimaryHidlTest, setMode) {
     doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
     // Test Invalid values
-    for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) {
+#if MAJOR_VERSION >= 6
+    int maxMode = int(AudioMode::CALL_SCREEN);
+#else
+    int maxMode = int(AudioMode::IN_COMMUNICATION);
+#endif
+
+    for (int mode : {-2, -1, maxMode + 1}) {
         ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
                 << "mode=" << mode;
     }
@@ -253,6 +259,10 @@
                            AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
         ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
     }
+    // AudioMode::CALL_SCREEN as support is optional
+#if MAJOR_VERSION >= 6
+    ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setMode(AudioMode::CALL_SCREEN));
+#endif
 }
 
 TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) {
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 5b58553..e09eeab 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -133,3 +133,91 @@
     ASSERT_OK(getDevice()->close());
     ASSERT_TRUE(resetDevice());
 }
+
+TEST_P(AudioPatchHidlTest, UpdatePatchInvalidHandle) {
+    doc::test("Verify that passing an invalid handle to updateAudioPatch is checked");
+    AudioPatchHandle ignored;
+    ASSERT_OK(getDevice()->updateAudioPatch(
+            static_cast<int32_t>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE),
+            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);
+
+/** Stub implementation of IStreamOutEventCallback **/
+class MockOutEventCallbacks : public IStreamOutEventCallback {
+    Return<void> onCodecFormatChanged(const hidl_vec<uint8_t>& audioMetadata __unused) override {
+        return {};
+    }
+};
+
+TEST_P(OutputStreamTest, SetEventCallback) {
+    doc::test("If supported, set event callback for output stream should never fail");
+    auto res = stream->setEventCallback(new MockOutEventCallbacks);
+    EXPECT_RESULT(okOrNotSupported, res);
+    if (res == Result::OK) {
+        ASSERT_OK(stream->setEventCallback(nullptr));
+    } else {
+        doc::partialTest("The stream does not support event callback");
+    }
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 8e6be89..10a1144 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -109,6 +109,11 @@
 class HidlTest : public ::testing::Test {
   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.
@@ -118,9 +123,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());
     }
@@ -411,7 +413,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());
     }
@@ -445,15 +448,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);
@@ -464,7 +467,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");
@@ -472,7 +475,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");
@@ -485,11 +488,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);
     }
 };
 
@@ -881,6 +891,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/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index 33ec996..406a571 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -307,12 +307,11 @@
 Result Effect::getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
                                     GetCurrentConfigSuccessCallback onSuccess) {
     uint32_t halCmd = featureId;
-    uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize)];
-    memset(halResult, 0, sizeof(halResult));
+    std::vector<uint32_t> halResult(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize), 0);
     uint32_t halResultSize = 0;
-    return sendCommandReturningStatusAndData(EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG",
-                                             sizeof(uint32_t), &halCmd, &halResultSize, halResult,
-                                             sizeof(uint32_t), [&] { onSuccess(&halResult[1]); });
+    return sendCommandReturningStatusAndData(
+            EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG", sizeof(uint32_t), &halCmd,
+            &halResultSize, &halResult[0], sizeof(uint32_t), [&] { onSuccess(&halResult[1]); });
 }
 
 Result Effect::getParameterImpl(uint32_t paramSize, const void* paramData,
@@ -339,8 +338,7 @@
                                        GetSupportedConfigsSuccessCallback onSuccess) {
     uint32_t halCmd[2] = {featureId, maxConfigs};
     uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * sizeof(configSize);
-    uint8_t halResult[halResultSize];
-    memset(&halResult[0], 0, halResultSize);
+    std::vector<uint8_t> halResult(static_cast<size_t>(halResultSize), 0);
     return sendCommandReturningStatusAndData(
         EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS", sizeof(halCmd),
         halCmd, &halResultSize, &halResult[0], 2 * sizeof(uint32_t), [&] {
@@ -519,9 +517,9 @@
     uint32_t halDataSize;
     std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
     uint32_t halResultSize = halDataSize;
-    uint32_t halResult[volumes.size()];
+    std::vector<uint32_t> halResult(volumes.size(), 0);
     Result retval = sendCommandReturningData(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize,
-                                             &halData[0], &halResultSize, halResult);
+                                             &halData[0], &halResultSize, &halResult[0]);
     hidl_vec<uint32_t> result;
     if (retval == Result::OK) {
         result.setToExternal(&halResult[0], halResultSize);
@@ -581,8 +579,6 @@
 }
 
 Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
-    memset(halResult, 0, sizeof(halResult));
     EffectAuxChannelsConfig result;
     Result retval = getCurrentConfigImpl(
         EFFECT_FEATURE_AUX_CHANNELS, sizeof(channel_config_t), [&](void* configData) {
@@ -594,11 +590,12 @@
 }
 
 Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
-    uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
+    std::vector<uint32_t> halCmd(
+            alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t)), 0);
     halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS;
     effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1]));
     return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG,
-                                      "SET_FEATURE_CONFIG AUX_CHANNELS", sizeof(halCmd), halCmd);
+                                      "SET_FEATURE_CONFIG AUX_CHANNELS", halCmd.size(), &halCmd[0]);
 }
 
 Return<Result> Effect::setAudioSource(AudioSource source) {
@@ -692,12 +689,11 @@
 
 Return<Result> Effect::setCurrentConfigForFeature(uint32_t featureId,
                                                   const hidl_vec<uint8_t>& configData) {
-    uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size())];
-    memset(halCmd, 0, sizeof(halCmd));
+    std::vector<uint32_t> halCmd(alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size()), 0);
     halCmd[0] = featureId;
     memcpy(&halCmd[1], &configData[0], configData.size());
     return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG",
-                                      sizeof(halCmd), halCmd);
+                                      halCmd.size(), &halCmd[0]);
 }
 
 Return<Result> Effect::close() {
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index ccbc828..29a9cd4 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -129,6 +129,7 @@
     enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_BEACON;
     enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY;
     enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_BYPASS_MUTE;
+    enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_CAPTURE_PRIVATE;
     enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_DEEP_BUFFER;
     enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_HW_AV_SYNC;
     enum_constant public static final audio.policy.V1_0.FlagType AUDIO_FLAG_HW_HOTWORD;
@@ -212,6 +213,7 @@
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANT;
+    enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_GAME;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_MEDIA;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION;
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index a23d9a8..842e724 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -342,6 +342,7 @@
             <xs:enumeration value="AUDIO_USAGE_GAME"/>
             <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE"/>
             <xs:enumeration value="AUDIO_USAGE_ASSISTANT"/>
+            <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT"/>
         </xs:restriction>
     </xs:simpleType>
 
@@ -370,6 +371,7 @@
             <xs:enumeration value="AUDIO_FLAG_NO_MEDIA_PROJECTION"/>
             <xs:enumeration value="AUDIO_FLAG_MUTE_HAPTIC"/>
             <xs:enumeration value="AUDIO_FLAG_NO_SYSTEM_CAPTURE"/>
+            <xs:enumeration value="AUDIO_FLAG_CAPTURE_PRIVATE"/>
         </xs:restriction>
     </xs:simpleType>
 
diff --git a/automotive/OWNERS b/automotive/OWNERS
index 3cf4489..83ee63c 100644
--- a/automotive/OWNERS
+++ b/automotive/OWNERS
@@ -1,4 +1,5 @@
-randolphs@google.com
 pirozzoj@google.com
 twasilczyk@google.com
 pfg@google.com
+gurunagarajan@google.com
+keunyoung@google.com
diff --git a/automotive/audiocontrol/1.0/IAudioControl.hal b/automotive/audiocontrol/1.0/IAudioControl.hal
index 3c8b086..2e7ef75 100644
--- a/automotive/audiocontrol/1.0/IAudioControl.hal
+++ b/automotive/audiocontrol/1.0/IAudioControl.hal
@@ -29,6 +29,11 @@
      *
      * For every context, a valid bus number (0 - num busses-1) must be returned. If an
      * unrecognized contextNumber is encountered, then -1 shall be returned.
+     *
+     * Deprecated: usage of this API and car_volume_groups.xml has been replaced with
+     * car_audio_configuration.xml. If using car_audio_configuration.xml, then the framework
+     * will not call this method. If it doesn't, then it will load car_volume_groups.xml and
+     * call this method.
      */
     getBusForContext(ContextNumber contextNumber)
         generates (int32_t busNumber);
diff --git a/automotive/audiocontrol/1.0/default/Android.bp b/automotive/audiocontrol/1.0/default/Android.bp
index 314830b..ae4b805 100644
--- a/automotive/audiocontrol/1.0/default/Android.bp
+++ b/automotive/audiocontrol/1.0/default/Android.bp
@@ -29,10 +29,5 @@
         "liblog",
         "libutils",
     ],
-
-    cflags: [
-        "-DLOG_TAG=\"AudCntrlDrv\"",
-        "-O0",
-        "-g",
-    ],
+    vintf_fragments: ["audiocontrol_manifest.xml"],
 }
diff --git a/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml b/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml
new file mode 100644
index 0000000..0981eb7
--- /dev/null
+++ b/automotive/audiocontrol/1.0/default/audiocontrol_manifest.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.automotive.audiocontrol</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IAudioControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/automotive/audiocontrol/1.0/vts/functional/Android.bp b/automotive/audiocontrol/1.0/vts/functional/Android.bp
index 3cb6340..1bb8e88 100644
--- a/automotive/audiocontrol/1.0/vts/functional/Android.bp
+++ b/automotive/audiocontrol/1.0/vts/functional/Android.bp
@@ -25,5 +25,8 @@
     static_libs: [
         "android.hardware.automotive.audiocontrol@1.0",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp b/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp
index fc0deb9..de1ec02 100644
--- a/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp
+++ b/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp
@@ -25,11 +25,12 @@
 #include <utils/Errors.h>
 #include <utils/StrongPointer.h>
 
-#include <android/hardware/automotive/audiocontrol/1.0/types.h>
 #include <android/hardware/automotive/audiocontrol/1.0/IAudioControl.h>
+#include <android/hardware/automotive/audiocontrol/1.0/types.h>
 #include <android/log.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 using namespace ::android::hardware::automotive::audiocontrol::V1_0;
 using ::android::hardware::Return;
@@ -40,30 +41,12 @@
 using ::android::hardware::hidl_vec;
 using ::android::sp;
 
-
-// Boiler plate for test harness
-class CarAudioControlHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static CarAudioControlHidlEnvironment* Instance() {
-        static CarAudioControlHidlEnvironment* instance = new CarAudioControlHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IAudioControl>(); }
-   private:
-    CarAudioControlHidlEnvironment() {}
-};
-
-
 // The main test class for the automotive AudioControl HAL
-class CarAudioControlHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-public:
+class CarAudioControlHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override {
         // Make sure we can connect to the driver
-        pAudioControl = ::testing::VtsHalHidlTargetTestBase::getService<IAudioControl>(
-                                    CarAudioControlHidlEnvironment::Instance()->
-                                    getServiceName<IAudioControl>());
+        pAudioControl = IAudioControl::getService(GetParam());
         ASSERT_NE(pAudioControl.get(), nullptr);
     }
 
@@ -82,7 +65,7 @@
  * fader actually works.  The only thing we can do is exercise the HAL and if the HAL crashes,
  * we _might_ get a test failure if that breaks the connection to the driver.
  */
-TEST_F(CarAudioControlHidlTest, FaderExercise) {
+TEST_P(CarAudioControlHidlTest, FaderExercise) {
     ALOGI("Fader exercise test (silent)");
 
     // Set the fader all the way to the back
@@ -104,7 +87,7 @@
 /*
  * Balance exercise test.
  */
-TEST_F(CarAudioControlHidlTest, BalanceExercise) {
+TEST_P(CarAudioControlHidlTest, BalanceExercise) {
     ALOGI("Balance exercise test (silent)");
 
     // Set the balance all the way to the left
@@ -126,7 +109,7 @@
 /*
  * Context mapping test.
  */
-TEST_F(CarAudioControlHidlTest, ContextMapping) {
+TEST_P(CarAudioControlHidlTest, ContextMapping) {
     ALOGI("Context mapping test");
 
     int bus = -1;
@@ -156,3 +139,8 @@
     bus = pAudioControl->getBusForContext((ContextNumber)~0);
     EXPECT_EQ(bus, -1);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, CarAudioControlHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
+        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/automotive/audiocontrol/2.0/Android.bp b/automotive/audiocontrol/2.0/Android.bp
new file mode 100644
index 0000000..e9ce638
--- /dev/null
+++ b/automotive/audiocontrol/2.0/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.audiocontrol@2.0",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IAudioControl.hal",
+        "ICloseHandle.hal",
+        "IFocusListener.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@6.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/automotive/audiocontrol/2.0/IAudioControl.hal b/automotive/audiocontrol/2.0/IAudioControl.hal
new file mode 100644
index 0000000..1073498
--- /dev/null
+++ b/automotive/audiocontrol/2.0/IAudioControl.hal
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+import ICloseHandle;
+import IFocusListener;
+import android.hardware.audio.common@6.0::AudioUsage;
+
+/**
+ * Interacts with the car's audio subsystem to manage audio sources and volumes
+ */
+interface IAudioControl {
+    /**
+     * Registers focus listener to be used by HAL for requesting and abandoning audio focus.
+     *
+     * It is expected that there will only ever be a single focus listener registered. If the
+     * observer dies, the HAL implementation must unregister observer automatically. If called when
+     * a listener is already registered, the existing one should be unregistered and replaced with
+     * the new listener.
+     *
+     * @param listener the listener interface
+     * @return closeHandle A handle to unregister observer.
+     */
+    registerFocusListener(IFocusListener listener) generates (ICloseHandle closeHandle);
+
+    /**
+     * Notifies HAL of changes in audio focus status for focuses requested or abandoned by the HAL.
+     *
+     * This will be called in response to IFocusListener's requestAudioFocus and
+     * abandonAudioFocus, as well as part of any change in focus being held by the HAL due focus
+     * request from other activities or services.
+     *
+     * The HAL is not required to wait for an callback of AUDIOFOCUS_GAIN before playing audio, nor
+     * is it required to stop playing audio in the event of a AUDIOFOCUS_LOSS callback is received.
+     *
+     * @param usage The audio usage associated with the focus change {@code AttributeUsage}
+     * @param zoneId The identifier for the audio zone that the HAL is playing the stream in
+     * @param focusChange the AudioFocusChange that has occurred
+     */
+    oneway onAudioFocusChange(bitfield<AudioUsage> usage, int32_t zoneId,
+        bitfield<AudioFocusChange> focusChange);
+
+    /**
+     * Control the right/left balance setting of the car speakers.
+     *
+     * This is intended to shift the speaker volume toward the right (+) or left (-) side of
+     * the car. 0.0 means "centered". +1.0 means fully right. -1.0 means fully left.
+     *
+     * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
+     * range.
+     */
+    oneway setBalanceTowardRight(float value);
+
+    /**
+     * Control the fore/aft fade setting of the car speakers.
+     *
+     * This is intended to shift the speaker volume toward the front (+) or back (-) of the car.
+     * 0.0 means "centered". +1.0 means fully forward. -1.0 means fully rearward.
+     *
+     * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
+     * range.
+     */
+    oneway setFadeTowardFront(float value);
+};
diff --git a/automotive/audiocontrol/2.0/ICloseHandle.hal b/automotive/audiocontrol/2.0/ICloseHandle.hal
new file mode 100644
index 0000000..537af6d
--- /dev/null
+++ b/automotive/audiocontrol/2.0/ICloseHandle.hal
@@ -0,0 +1,34 @@
+/*
+ * 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.automotive.audiocontrol@2.0;
+
+/**
+ * Represents a generic close handle to remove a callback that doesn't need
+ * active interface.
+ *
+ * When close() is called OR when the interface is released, the underlying
+ * resources must be freed.
+ */
+interface ICloseHandle {
+    /**
+     * Closes the handle.
+     *
+     * The call must not fail and must be issued by the client at most once.
+     * Otherwise, the server must ignore subsequent calls.
+     */
+    close();
+};
diff --git a/automotive/audiocontrol/2.0/IFocusListener.hal b/automotive/audiocontrol/2.0/IFocusListener.hal
new file mode 100644
index 0000000..4fd5ef0
--- /dev/null
+++ b/automotive/audiocontrol/2.0/IFocusListener.hal
@@ -0,0 +1,55 @@
+/*
+ * 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.automotive.audiocontrol@2.0;
+
+import android.hardware.audio.common@6.0::AudioUsage;
+
+/**
+ * Callback interface for audio focus listener.
+ *
+ * For typical configuration, the listener the car audio service.
+ */
+interface IFocusListener {
+    /**
+     * Called whenever HAL is requesting focus as it is starting to play audio of a given usage in a
+     * specified zone.
+     *
+     * In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This
+     * interaction is oneway to avoid blocking HAL so that it is not required to wait for a response
+     * before playing audio.
+     *
+     * @param usage The audio usage associated with the focus request {@code AttributeUsage}
+     * @param zoneId The identifier for the audio zone where the HAL is requesting focus
+     * @param focusGain The AudioFocusChange associated with this request. Should be one of the
+     * following: GAIN, GAIN_TRANSIENT, GAIN_TRANSIENT_MAY_DUCK, GAIN_TRANSIENT_EXCLUSIVE.
+     */
+    oneway requestAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId,
+        bitfield<AudioFocusChange> focusGain);
+
+    /**
+     * Called whenever HAL is abandoning focus as it is finished playing audio of a given usage in a
+     * specific zone.
+     *
+     * In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This
+     * interaction is oneway to avoid blocking HAL so that it is not required to wait for a response
+     * before stopping audio playback.
+     *
+     * @param usage The audio usage for which the HAL is abandoning focus {@code AttributeUsage}
+     * @param zoneId The identifier for the audio zone that the HAL abandoning focus
+     */
+    oneway abandonAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId);
+};
diff --git a/automotive/audiocontrol/2.0/default/Android.bp b/automotive/audiocontrol/2.0/default/Android.bp
new file mode 100644
index 0000000..44ad028
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/Android.bp
@@ -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.
+
+cc_binary {
+    name: "android.hardware.automotive.audiocontrol@2.0-service",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "AudioControl.cpp",
+        "service.cpp",
+        "CloseHandle.cpp",
+    ],
+    init_rc: ["android.hardware.automotive.audiocontrol@2.0-service.rc"],
+
+    shared_libs: [
+        "android.hardware.automotive.audiocontrol@2.0",
+        "libbase",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    vintf_fragments: ["audiocontrol2_manifest.xml"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp
new file mode 100644
index 0000000..b7c11cd
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp
@@ -0,0 +1,220 @@
+/*
+ * 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 "AudioControl.h"
+
+#include <stdio.h>
+
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+#include <private/android_filesystem_config.h>
+
+#include "CloseHandle.h"
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+using ::android::base::EqualsIgnoreCase;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+
+static const float kLowerBound = -1.0f;
+static const float kUpperBound = 1.0f;
+
+AudioControl::AudioControl() {}
+
+Return<sp<ICloseHandle>> AudioControl::registerFocusListener(const sp<IFocusListener>& listener) {
+    LOG(DEBUG) << "registering focus listener";
+    sp<ICloseHandle> closeHandle(nullptr);
+
+    if (listener) {
+        mFocusListener = listener;
+
+        closeHandle = new CloseHandle([this, listener]() {
+            if (mFocusListener == listener) {
+                mFocusListener = nullptr;
+            }
+        });
+    } else {
+        LOG(ERROR) << "Unexpected nullptr for listener resulting in no-op.";
+    }
+
+    return closeHandle;
+}
+
+Return<void> AudioControl::setBalanceTowardRight(float value) {
+    if (isValidValue(value)) {
+        // Just log in this default mock implementation
+        LOG(INFO) << "Balance set to " << value;
+    } else {
+        LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
+    }
+    return Void();
+}
+
+Return<void> AudioControl::setFadeTowardFront(float value) {
+    if (isValidValue(value)) {
+        // Just log in this default mock implementation
+        LOG(INFO) << "Fader set to " << value;
+    } else {
+        LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
+    }
+    return Void();
+}
+
+bool AudioControl::isValidValue(float value) {
+    return (value > kLowerBound) && (value < kUpperBound);
+}
+
+Return<void> AudioControl::onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId,
+                                              hidl_bitfield<AudioFocusChange> focusChange) {
+    LOG(INFO) << "Focus changed: " << static_cast<int>(focusChange) << " for usage "
+              << static_cast<int>(usage) << " in zone " << zoneId;
+    return Void();
+}
+
+Return<void> AudioControl::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds == 0) {
+        LOG(ERROR) << "Invalid parameters passed to debug()";
+        return Void();
+    }
+
+    cmdDump(fd->data[0], options);
+    return Void();
+}
+
+void AudioControl::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
+    if (options.size() == 0) {
+        dump(fd);
+        return;
+    }
+
+    std::string option = options[0];
+    if (EqualsIgnoreCase(option, "--help")) {
+        cmdHelp(fd);
+    } else if (EqualsIgnoreCase(option, "--request")) {
+        cmdRequestFocus(fd, options);
+    } else if (EqualsIgnoreCase(option, "--abandon")) {
+        cmdAbandonFocus(fd, options);
+    } else {
+        dprintf(fd, "Invalid option: %s\n", option.c_str());
+    }
+}
+
+void AudioControl::dump(int fd) {
+    if (mFocusListener == nullptr) {
+        dprintf(fd, "No focus listener registered\n");
+    } else {
+        dprintf(fd, "Focus listener registered\n");
+    }
+}
+
+void AudioControl::cmdHelp(int fd) const {
+    dprintf(fd, "Usage: \n\n");
+    dprintf(fd, "[no args]: dumps focus listener status\n");
+    dprintf(fd, "--help: shows this help\n");
+    dprintf(fd,
+            "--request <USAGE> <ZONE_ID> <FOCUS_GAIN>: requests audio focus for specified "
+            "usage (int), audio zone ID (int), and focus gain type (int)\n");
+    dprintf(fd,
+            "--abandon <USAGE> <ZONE_ID>: abandons audio focus for specified usage (int) and "
+            "audio zone ID (int)\n");
+}
+
+void AudioControl::cmdRequestFocus(int fd, const hidl_vec<hidl_string>& options) {
+    if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return;
+
+    hidl_bitfield<AudioUsage> usage;
+    if (!safelyParseInt(options[1], &usage)) {
+        dprintf(fd, "Non-integer usage provided with request: %s\n", options[1].c_str());
+        return;
+    }
+    int zoneId;
+    if (!safelyParseInt(options[2], &zoneId)) {
+        dprintf(fd, "Non-integer zoneId provided with request: %s\n", options[2].c_str());
+        return;
+    }
+    hidl_bitfield<AudioFocusChange> focusGain;
+    if (!safelyParseInt(options[3], &focusGain)) {
+        dprintf(fd, "Non-integer focusGain provided with request: %s\n", options[3].c_str());
+        return;
+    }
+
+    if (mFocusListener == nullptr) {
+        dprintf(fd, "Unable to request focus - no focus listener registered\n");
+        return;
+    }
+
+    mFocusListener->requestAudioFocus(usage, zoneId, focusGain);
+    dprintf(fd, "Requested focus for usage %d, zoneId %d, and focusGain %d\n", usage, zoneId,
+            focusGain);
+}
+
+void AudioControl::cmdAbandonFocus(int fd, const hidl_vec<hidl_string>& options) {
+    if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 2)) return;
+
+    hidl_bitfield<AudioUsage> usage;
+    if (!safelyParseInt(options[1], &usage)) {
+        dprintf(fd, "Non-integer usage provided with abandon: %s\n", options[1].c_str());
+        return;
+    }
+    int zoneId;
+    if (!safelyParseInt(options[2], &zoneId)) {
+        dprintf(fd, "Non-integer zoneId provided with abandon: %s\n", options[2].c_str());
+        return;
+    }
+
+    if (mFocusListener == nullptr) {
+        dprintf(fd, "Unable to abandon focus - no focus listener registered\n");
+        return;
+    }
+
+    mFocusListener->abandonAudioFocus(usage, zoneId);
+    dprintf(fd, "Abandoned focus for usage %d and zoneId %d\n", usage, zoneId);
+}
+
+bool AudioControl::checkCallerHasWritePermissions(int fd) {
+    // Double check that's only called by root - it should be be blocked at the HIDL debug() level,
+    // but it doesn't hurt to make sure...
+    if (hardware::IPCThreadState::self()->getCallingUid() != AID_ROOT) {
+        dprintf(fd, "Must be root\n");
+        return false;
+    }
+    return true;
+}
+
+bool AudioControl::checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options,
+                                      size_t expectedSize) {
+    // options includes the command, so reducing size by one
+    size_t size = options.size() - 1;
+    if (size == expectedSize) {
+        return true;
+    }
+    dprintf(fd, "Invalid number of arguments: required %zu, got %zu\n", expectedSize, size);
+    return false;
+}
+
+bool AudioControl::safelyParseInt(std::string s, int* out) {
+    if (!android::base::ParseInt(s, out)) {
+        return false;
+    }
+    return true;
+}
+
+}  // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/AudioControl.h b/automotive/audiocontrol/2.0/default/AudioControl.h
new file mode 100644
index 0000000..d66458e
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/AudioControl.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
+
+#include <android/hardware/audio/common/6.0/types.h>
+#include <android/hardware/automotive/audiocontrol/2.0/IAudioControl.h>
+#include <android/hardware/automotive/audiocontrol/2.0/ICloseHandle.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+using android::hardware::audio::common::V6_0::AudioUsage;
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+class AudioControl : public IAudioControl {
+  public:
+    // Methods from ::android::hardware::automotive::audiocontrol::V2_0::IAudioControl follow.
+    Return<sp<ICloseHandle>> registerFocusListener(const sp<IFocusListener>& listener);
+    Return<void> onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId,
+                                    hidl_bitfield<AudioFocusChange> focusChange);
+    Return<void> setBalanceTowardRight(float value) override;
+    Return<void> setFadeTowardFront(float value) override;
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
+
+    // Implementation details
+    AudioControl();
+
+  private:
+    sp<IFocusListener> mFocusListener;
+
+    static bool checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options, size_t minSize);
+    static bool checkCallerHasWritePermissions(int fd);
+    static bool isValidValue(float value);
+    static bool safelyParseInt(std::string s, int* out);
+
+    void cmdDump(int fd, const hidl_vec<hidl_string>& options);
+    void cmdHelp(int fd) const;
+    void cmdRequestFocus(int fd, const hidl_vec<hidl_string>& options);
+    void cmdAbandonFocus(int fd, const hidl_vec<hidl_string>& options);
+    void dump(int fd);
+};
+
+}  // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
+
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
diff --git a/automotive/audiocontrol/2.0/default/CloseHandle.cpp b/automotive/audiocontrol/2.0/default/CloseHandle.cpp
new file mode 100644
index 0000000..bc47931
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/CloseHandle.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 "CloseHandle.h"
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {}
+
+CloseHandle::~CloseHandle() {
+    close();
+}
+
+Return<void> CloseHandle::close() {
+    const auto wasClosed = mIsClosed.exchange(true);
+    if (wasClosed) return {};
+
+    if (mCallback) mCallback();
+    return {};
+}
+
+}  // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/CloseHandle.h b/automotive/audiocontrol/2.0/default/CloseHandle.h
new file mode 100644
index 0000000..6caf0bf
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/CloseHandle.h
@@ -0,0 +1,48 @@
+/*
+ * 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-base/macros.h>
+#include <android/hardware/automotive/audiocontrol/2.0/ICloseHandle.h>
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+/** Generic ICloseHandle implementation ignoring double-close events. */
+class CloseHandle : public ICloseHandle {
+  public:
+    using Callback = std::function<void()>;
+
+    /**
+     * Create a handle with a callback.
+     *
+     * The callback is guaranteed to be called exactly once.
+     *
+     * \param callback Called on the first close() call, or on destruction of the handle
+     */
+    CloseHandle(Callback callback = nullptr);
+    virtual ~CloseHandle();
+
+    Return<void> close() override;
+
+  private:
+    const Callback mCallback;
+    std::atomic<bool> mIsClosed = false;
+
+    DISALLOW_COPY_AND_ASSIGN(CloseHandle);
+};
+
+}  // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc b/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc
new file mode 100644
index 0000000..81c9be4
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.audiocontrol-hal-2.0 /vendor/bin/hw/android.hardware.automotive.audiocontrol@2.0-service
+    class hal
+    user audioserver
+    group system
diff --git a/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml b/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml
new file mode 100644
index 0000000..42d23ed
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.automotive.audiocontrol</name>
+        <transport>hwbinder</transport>
+        <version>2.0</version>
+        <interface>
+            <name>IAudioControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/automotive/audiocontrol/2.0/default/service.cpp b/automotive/audiocontrol/2.0/default/service.cpp
new file mode 100644
index 0000000..dcc46c3
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/service.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "AudioControl.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::automotive::audiocontrol::V2_0::IAudioControl;
+
+// The namespace in which all our implementation code lives
+using namespace android::hardware::automotive::audiocontrol::V2_0::implementation;
+using namespace android;
+
+// Main service entry point
+int main() {
+    // Create an instance of our service class
+    android::sp<IAudioControl> service = new AudioControl();
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    if (service->registerAsService() != OK) {
+        LOG(ERROR) << "registerAsService failed";
+        return 1;
+    }
+
+    // Join (forever) the thread pool we created for the service above
+    joinRpcThreadpool();
+
+    // We don't ever actually expect to return, so return an error if we do get here
+    return 2;
+}
\ No newline at end of file
diff --git a/automotive/audiocontrol/2.0/types.hal b/automotive/audiocontrol/2.0/types.hal
new file mode 100644
index 0000000..80d9ee1
--- /dev/null
+++ b/automotive/audiocontrol/2.0/types.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.automotive.audiocontrol@2.0;
+
+/**
+ * Changes in audio focus that can be experienced
+ */
+enum AudioFocusChange : int32_t {
+    NONE = 0,
+    GAIN = 1,
+    GAIN_TRANSIENT = 2,
+    GAIN_TRANSIENT_MAY_DUCK = 3,
+    GAIN_TRANSIENT_EXCLUSIVE = 4,
+    LOSS = -1 * GAIN,
+    LOSS_TRANSIENT = -1 * GAIN_TRANSIENT,
+    LOSS_TRANSIENT_CAN_DUCK = -1 * GAIN_TRANSIENT_MAY_DUCK,
+};
diff --git a/automotive/audiocontrol/2.0/vts/functional/Android.bp b/automotive/audiocontrol/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..520b042
--- /dev/null
+++ b/automotive/audiocontrol/2.0/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// 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: "VtsHalAudioControlV2_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalAudioControlV2_0TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.automotive.audiocontrol@2.0",
+        "libgmock",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
new file mode 100644
index 0000000..0c10664
--- /dev/null
+++ b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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 "VtsHalAudioControlTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/ProcessState.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include <android/hardware/audio/common/6.0/types.h>
+#include <android/hardware/automotive/audiocontrol/2.0/IAudioControl.h>
+#include <android/hardware/automotive/audiocontrol/2.0/types.h>
+#include <android/log.h>
+
+using namespace ::android::hardware::automotive::audiocontrol::V2_0;
+using ::android::sp;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V6_0::AudioUsage;
+
+// The main test class for the automotive AudioControl HAL
+class CarAudioControlHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        // Make sure we can connect to the driver
+        pAudioControl = IAudioControl::getService(GetParam());
+        ASSERT_NE(pAudioControl.get(), nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+  protected:
+    sp<IAudioControl> pAudioControl;  // Every test needs access to the service
+};
+
+//
+// Tests start here...
+//
+
+/*
+ * Fader exercise test.  Note that only a subjective observer could determine if the
+ * fader actually works.  The only thing we can do is exercise the HAL and if the HAL crashes,
+ * we _might_ get a test failure if that breaks the connection to the driver.
+ */
+TEST_P(CarAudioControlHidlTest, FaderExercise) {
+    ALOGI("Fader exercise test (silent)");
+
+    // Set the fader all the way to the back
+    pAudioControl->setFadeTowardFront(-1.0f);
+
+    // Set the fader all the way to the front
+    pAudioControl->setFadeTowardFront(1.0f);
+
+    // Set the fader part way toward the back
+    pAudioControl->setFadeTowardFront(-0.333f);
+
+    // Set the fader to a out of bounds value (driver should clamp)
+    pAudioControl->setFadeTowardFront(99999.9f);
+
+    // Set the fader back to the middle
+    pAudioControl->setFadeTowardFront(0.0f);
+}
+
+/*
+ * Balance exercise test.
+ */
+TEST_P(CarAudioControlHidlTest, BalanceExercise) {
+    ALOGI("Balance exercise test (silent)");
+
+    // Set the balance all the way to the left
+    pAudioControl->setBalanceTowardRight(-1.0f);
+
+    // Set the balance all the way to the right
+    pAudioControl->setBalanceTowardRight(1.0f);
+
+    // Set the balance part way toward the left
+    pAudioControl->setBalanceTowardRight(-0.333f);
+
+    // Set the balance to a out of bounds value (driver should clamp)
+    pAudioControl->setBalanceTowardRight(99999.9f);
+
+    // Set the balance back to the middle
+    pAudioControl->setBalanceTowardRight(0.0f);
+}
+
+struct FocusListenerMock : public IFocusListener {
+    MOCK_METHOD(Return<void>, requestAudioFocus,
+                (hidl_bitfield<AudioUsage> usage, int zoneId,
+                 hidl_bitfield<AudioFocusChange> focusGain));
+    MOCK_METHOD(Return<void>, abandonAudioFocus, (hidl_bitfield<AudioUsage> usage, int zoneId));
+};
+
+/*
+ * Test focus listener registration.
+ *
+ * Verifies that:
+ * - registerFocusListener succeeds;
+ * - registering a second listener succeeds in replacing the first;
+ * - closing handle does not crash;
+ */
+TEST_P(CarAudioControlHidlTest, FocusListenerRegistration) {
+    ALOGI("Focus listener test");
+
+    sp<FocusListenerMock> listener = new FocusListenerMock();
+
+    auto hidlResult = pAudioControl->registerFocusListener(listener);
+    ASSERT_TRUE(hidlResult.isOk());
+
+    sp<FocusListenerMock> listener2 = new FocusListenerMock();
+
+    auto hidlResult2 = pAudioControl->registerFocusListener(listener2);
+    ASSERT_TRUE(hidlResult2.isOk());
+
+    const sp<ICloseHandle>& closeHandle = hidlResult2;
+    closeHandle->close();
+};
+
+TEST_P(CarAudioControlHidlTest, FocusChangeExercise) {
+    ALOGI("Focus Change test");
+
+    pAudioControl->onAudioFocusChange(AudioUsage::MEDIA | 0, 0,
+                                      AudioFocusChange::GAIN_TRANSIENT | 0);
+};
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, CarAudioControlHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
+        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/automotive/can/1.0/Android.bp b/automotive/can/1.0/Android.bp
new file mode 100644
index 0000000..2ddfaf9
--- /dev/null
+++ b/automotive/can/1.0/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.can@1.0",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "ICanBus.hal",
+        "ICanController.hal",
+        "ICanErrorListener.hal",
+        "ICanMessageListener.hal",
+        "ICloseHandle.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/automotive/can/1.0/ICanBus.hal b/automotive/can/1.0/ICanBus.hal
new file mode 100644
index 0000000..e68f16c
--- /dev/null
+++ b/automotive/can/1.0/ICanBus.hal
@@ -0,0 +1,72 @@
+/*
+ * 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.automotive.can@1.0;
+
+import ICanErrorListener;
+import ICanMessageListener;
+import ICloseHandle;
+
+/**
+ * Represents a CAN bus interface that's up and configured.
+ *
+ * Configuration part is done in ICanController.
+ */
+interface ICanBus {
+    /**
+     * Send CAN message.
+     *
+     * @param message CAN message to send out
+     * @return result OK in the case of success
+     *                PAYLOAD_TOO_LONG if the payload is too long
+     *                INTERFACE_DOWN if the bus is down
+     *                TRANSMISSION_FAILURE in case of transmission failure
+     */
+    send(CanMessage message) generates (Result result);
+
+    /**
+     * Requests HAL implementation to listen for specific CAN messages.
+     *
+     * HAL is responsible for maintaining listener set and sending out messages
+     * to each listener that matches given filter against received message.
+     *
+     * Empty filter list means no filtering. If two or more listeners requested
+     * different filters, HAL server must merge these to fulfill the superset of
+     * these filters. HAL must not send out a message to a listener which filter
+     * doesn't match given message id.
+     *
+     * If filtering is not supported at the hardware level (what's strongly
+     * recommended), it must be covered in the HAL.
+     *
+     * @param filter The set of requested filters
+     * @param listener The interface to receive the messages on
+     * @return result OK in the case of success
+     *                INTERFACE_DOWN if the bus is down
+     * @return close A handle to call in order to remove the listener
+     */
+    listen(vec<CanMessageFilter> filter, ICanMessageListener listener)
+            generates (Result result, ICloseHandle close);
+
+    /**
+     * Adds a new listener for CAN bus or interface errors.
+     *
+     * If the error is fatal, the client is supposed to drop any references to
+     * this specific ICanBus instance (see ICanErrorListener).
+     *
+     * @param listener The interface to receive the error events on
+     * @return close A handle to call in order to remove the listener
+     */
+    listenForErrors(ICanErrorListener listener) generates (ICloseHandle close);
+};
diff --git a/automotive/can/1.0/ICanController.hal b/automotive/can/1.0/ICanController.hal
new file mode 100644
index 0000000..aaf85e9
--- /dev/null
+++ b/automotive/can/1.0/ICanController.hal
@@ -0,0 +1,195 @@
+/*
+ * 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.automotive.can@1.0;
+
+/**
+ * Represents a CAN controller that's capable of configuring CAN bus interfaces.
+ *
+ * The goal of this service is to configure CAN interfaces and bring up HIDL
+ * server instances of ICanBus for each one that's up.
+ *
+ * Providing an ICanController interface to configure CAN buses is optional.
+ * A system can elect to publish only ICanBus if the hardware is hardcoded
+ * for a specific application.
+ */
+interface ICanController {
+    /**
+     * 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. */
+        VIRTUAL,
+
+        /** Native SocketCAN interface. */
+        SOCKETCAN,
+
+        /** Serial line CAN interface. */
+        SLCAN,
+
+        /** Proprietary, device-specific interface. */
+        INDEXED,
+    };
+
+    enum Result : uint8_t {
+        OK,
+
+        /**
+         * General error class, if others are not applicable.
+         */
+        UNKNOWN_ERROR,
+
+        /**
+         * Up request was called out of order (i.e. trying to up the
+         * interface twice).
+         */
+        INVALID_STATE,
+
+        /** Interface type is not supported. */
+        NOT_SUPPORTED,
+
+        /**
+         * Provided interface ID (index, name, device path) doesn't exist or
+         * there is no device with a given serial number.
+         */
+        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,
+    };
+
+    /**
+     * Configuration of the (physical or virtual) CAN bus.
+     *
+     * ISO TP and CAN FD are currently not supported.
+     */
+    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;
+
+        /**
+         * Hardware interface configuration.
+         *
+         * This union's discriminator has an equivalent enum
+         * {@see InterfaceType} to express compatibility via
+         * getSupportedInterfaceTypes().
+         */
+        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;
+
+            /** 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;
+
+            /**
+             * Proprietary, device-specific interface.
+             *
+             * Non-SocketCAN interfaces should use this variant.
+             */
+            struct Indexed {
+                /** Interface number, 0-based. */
+                uint8_t index;
+            } indexed;
+        } interfaceId;
+
+        /**
+         * Bit rate for CAN communication.
+         *
+         * Typical bit rates are: 100000, 125000, 250000, 500000.
+         *
+         * For {@see interfaceId#virtual} and pre-configured
+         * {@see interfaceId#indexed} interfaces this value is ignored.
+         */
+        uint32_t bitrate;
+    };
+
+    /**
+     * Fetches the list of interface types supported by this HAL server.
+     *
+     * @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.
+     * @return result OK if the operation succeeded; error code otherwise.
+     */
+    upInterface(BusConfig config) generates (Result result);
+
+    /**
+     * Unpublish ICanBus server instance and bring down the CAN interface.
+     *
+     * 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 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/ICanErrorListener.hal b/automotive/can/1.0/ICanErrorListener.hal
new file mode 100644
index 0000000..8a6ba05
--- /dev/null
+++ b/automotive/can/1.0/ICanErrorListener.hal
@@ -0,0 +1,32 @@
+/*
+ * 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.automotive.can@1.0;
+
+/**
+ * CAN error listener.
+ */
+interface ICanErrorListener {
+    /**
+     * Called on error event.
+     *
+     * If the error is fatal, the client is supposed to drop any references to
+     * this specific ICanBus instance.
+     *
+     * @param error Error type
+     * @param isFatal Whether an error would result with ICanBus instance being unusable.
+     */
+    onError(ErrorEvent error, bool isFatal);
+};
diff --git a/automotive/can/1.0/ICanMessageListener.hal b/automotive/can/1.0/ICanMessageListener.hal
new file mode 100644
index 0000000..28161fa
--- /dev/null
+++ b/automotive/can/1.0/ICanMessageListener.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.automotive.can@1.0;
+
+/**
+ * CAN message listener.
+ */
+interface ICanMessageListener {
+    /**
+     * Called on received CAN message.
+     *
+     * The timestamp field of message struct is set to time when the message
+     * was received by the hardware. If it's not possible to fetch exact
+     * hardware time, this field should be set as early as possible to decrease
+     * potential time delta.
+     *
+     * @param message Received CAN message
+     */
+    onReceive(CanMessage message);
+};
diff --git a/automotive/can/1.0/ICloseHandle.hal b/automotive/can/1.0/ICloseHandle.hal
new file mode 100644
index 0000000..924c58b
--- /dev/null
+++ b/automotive/can/1.0/ICloseHandle.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.automotive.can@1.0;
+
+/**
+ * Represents a generic close handle to remove a callback that doesn't need
+ * active interface.
+ *
+ * When close() is called OR when the interface is released, the underlying
+ * resources must be freed.
+ */
+interface ICloseHandle {
+    /**
+     * Closes the handle.
+     *
+     * The call must not fail and must be issued by the client at most once.
+     * Otherwise, the server must ignore subsequent calls.
+     */
+    close();
+};
diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp
new file mode 100644
index 0000000..f5cf425
--- /dev/null
+++ b/automotive/can/1.0/default/Android.bp
@@ -0,0 +1,56 @@
+//
+// 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_defaults {
+    name: "android.hardware.automotive.can@defaults",
+    cpp_std: "experimental",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1",
+    ],
+    shared_libs: [
+        "libbase",
+        "libutils",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.automotive.can@1.0-service",
+    init_rc: ["android.hardware.automotive.can@1.0-service.rc"],
+    defaults: ["android.hardware.automotive.can@defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "CanBus.cpp",
+        "CanBusNative.cpp",
+        "CanBusVirtual.cpp",
+        "CanBusSlcan.cpp",
+        "CanController.cpp",
+        "CanSocket.cpp",
+        "CloseHandle.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@libnetdevice",
+        "android.hardware.automotive@libc++fs",
+    ],
+}
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
new file mode 100644
index 0000000..8b98e5e
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -0,0 +1,344 @@
+/*
+ * 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 "CanBus.h"
+
+#include "CloseHandle.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+#include <linux/can.h>
+#include <linux/can/error.h>
+#include <linux/can/raw.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+/** Whether to log sent/received packets. */
+static constexpr bool kSuperVerbose = false;
+
+Return<Result> CanBus::send(const CanMessage& message) {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+    if (!mIsUp) return Result::INTERFACE_DOWN;
+
+    if (UNLIKELY(kSuperVerbose)) {
+        LOG(VERBOSE) << "Sending " << toString(message);
+    }
+
+    if (message.payload.size() > CAN_MAX_DLEN) return Result::PAYLOAD_TOO_LONG;
+
+    struct canfd_frame frame = {};
+    frame.can_id = message.id;
+    if (message.isExtendedId) frame.can_id |= CAN_EFF_FLAG;
+    if (message.remoteTransmissionRequest) frame.can_id |= CAN_RTR_FLAG;
+    frame.len = message.payload.size();
+    memcpy(frame.data, message.payload.data(), message.payload.size());
+
+    if (!mSocket->send(frame)) return Result::TRANSMISSION_FAILURE;
+
+    return Result::OK;
+}
+
+Return<void> CanBus::listen(const hidl_vec<CanMessageFilter>& filter,
+                            const sp<ICanMessageListener>& listenerCb, listen_cb _hidl_cb) {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+    if (listenerCb == nullptr) {
+        _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
+        return {};
+    }
+    if (!mIsUp) {
+        _hidl_cb(Result::INTERFACE_DOWN, nullptr);
+        return {};
+    }
+
+    std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
+
+    sp<CloseHandle> closeHandle = new CloseHandle([this, listenerCb]() {
+        std::lock_guard<std::mutex> lck(mMsgListenersGuard);
+        std::erase_if(mMsgListeners, [&](const auto& e) { return e.callback == listenerCb; });
+    });
+    mMsgListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle});
+    auto& listener = mMsgListeners.back();
+
+    // fix message IDs to have all zeros on bits not covered by mask
+    std::for_each(listener.filter.begin(), listener.filter.end(),
+                  [](auto& rule) { rule.id &= rule.mask; });
+
+    _hidl_cb(Result::OK, closeHandle);
+    return {};
+}
+
+CanBus::CanBus() {}
+
+CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {}
+
+CanBus::~CanBus() {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+    CHECK(!mIsUp) << "Interface is still up while being destroyed";
+
+    std::lock_guard<std::mutex> lckListeners(mMsgListenersGuard);
+    CHECK(mMsgListeners.empty()) << "Listener list is not empty while interface is being destroyed";
+}
+
+void CanBus::setErrorCallback(ErrorCallback errcb) {
+    CHECK(!mIsUp) << "Can't set error callback while interface is up";
+    CHECK(mErrCb == nullptr) << "Error callback is already set";
+    mErrCb = errcb;
+    CHECK(!mIsUp) << "Can't set error callback while interface is up";
+}
+
+ICanController::Result CanBus::preUp() {
+    return ICanController::Result::OK;
+}
+
+bool CanBus::postDown() {
+    return true;
+}
+
+ICanController::Result CanBus::up() {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+    if (mIsUp) {
+        LOG(WARNING) << "Interface is already up";
+        return ICanController::Result::INVALID_STATE;
+    }
+
+    const auto preResult = preUp();
+    if (preResult != ICanController::Result::OK) return preResult;
+
+    const auto isUp = netdevice::isUp(mIfname);
+    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_INTERFACE_ID;
+    }
+
+    if (!*isUp && !netdevice::up(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " up";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+    mDownAfterUse = !*isUp;
+
+    using namespace std::placeholders;
+    CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2);
+    CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this, _1);
+    mSocket = CanSocket::open(mIfname, rdcb, errcb);
+    if (!mSocket) {
+        if (mDownAfterUse) netdevice::down(mIfname);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    mIsUp = true;
+    return ICanController::Result::OK;
+}
+
+void CanBus::clearMsgListeners() {
+    std::vector<wp<ICloseHandle>> listenersToClose;
+    {
+        std::lock_guard<std::mutex> lck(mMsgListenersGuard);
+        std::transform(mMsgListeners.begin(), mMsgListeners.end(),
+                       std::back_inserter(listenersToClose),
+                       [](const auto& e) { return e.closeHandle; });
+    }
+
+    for (auto& weakListener : listenersToClose) {
+        /* Between populating listenersToClose and calling close method here, some listeners might
+         * have been already removed from the original mMsgListeners list (resulting in a dangling
+         * weak pointer here). It's fine - we just want to clean them up. */
+        auto listener = weakListener.promote();
+        if (listener != nullptr) listener->close();
+    }
+
+    std::lock_guard<std::mutex> lck(mMsgListenersGuard);
+    CHECK(mMsgListeners.empty()) << "Listeners list wasn't emptied";
+}
+
+void CanBus::clearErrListeners() {
+    std::lock_guard<std::mutex> lck(mErrListenersGuard);
+    mErrListeners.clear();
+}
+
+Return<sp<ICloseHandle>> CanBus::listenForErrors(const sp<ICanErrorListener>& listener) {
+    if (listener == nullptr) {
+        return new CloseHandle();
+    }
+
+    std::lock_guard<std::mutex> upLck(mIsUpGuard);
+    if (!mIsUp) {
+        listener->onError(ErrorEvent::INTERFACE_DOWN, true);
+        return new CloseHandle();
+    }
+
+    std::lock_guard<std::mutex> errLck(mErrListenersGuard);
+    mErrListeners.emplace_back(listener);
+
+    return new CloseHandle([this, listener]() {
+        std::lock_guard<std::mutex> lck(mErrListenersGuard);
+        std::erase(mErrListeners, listener);
+    });
+}
+
+bool CanBus::down() {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+    if (!mIsUp) {
+        LOG(WARNING) << "Interface is already down";
+        return false;
+    }
+    mIsUp = false;
+
+    clearMsgListeners();
+    clearErrListeners();
+    mSocket.reset();
+
+    bool success = true;
+
+    if (mDownAfterUse && !netdevice::down(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " down";
+        // don't return yet, let's try to do best-effort cleanup
+        success = false;
+    }
+
+    if (!postDown()) success = false;
+
+    return success;
+}
+
+/**
+ * Helper function to determine if a flag meets the requirements of a
+ * FilterFlag. See definition of FilterFlag in types.hal
+ *
+ * \param filterFlag FilterFlag object to match flag against
+ * \param flag bool object from CanMessage object
+ */
+static bool satisfiesFilterFlag(FilterFlag filterFlag, bool flag) {
+    if (filterFlag == FilterFlag::DONT_CARE) return true;
+    if (filterFlag == FilterFlag::SET) return flag;
+    if (filterFlag == FilterFlag::NOT_SET) return !flag;
+    return false;
+}
+
+/**
+ * Match the filter set against message id.
+ *
+ * For details on the filters syntax, please see CanMessageFilter at
+ * the HAL definition (types.hal).
+ *
+ * \param filter Filter to match against
+ * \param id Message id to filter
+ * \return true if the message id matches the filter, false otherwise
+ */
+static bool match(const hidl_vec<CanMessageFilter>& filter, CanMessageId id, bool isRtr,
+                  bool isExtendedId) {
+    if (filter.size() == 0) return true;
+
+    bool anyNonExcludeRulePresent = false;
+    bool anyNonExcludeRuleSatisfied = false;
+    for (auto& rule : filter) {
+        const bool satisfied = ((id & rule.mask) == rule.id) &&
+                               satisfiesFilterFlag(rule.rtr, isRtr) &&
+                               satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
+
+        if (rule.exclude) {
+            // Any excluded (blacklist) rule not being satisfied invalidates the whole filter set.
+            if (satisfied) return false;
+        } else {
+            anyNonExcludeRulePresent = true;
+            if (satisfied) anyNonExcludeRuleSatisfied = true;
+        }
+    }
+    return !anyNonExcludeRulePresent || anyNonExcludeRuleSatisfied;
+}
+
+void CanBus::notifyErrorListeners(ErrorEvent err, bool isFatal) {
+    std::lock_guard<std::mutex> lck(mErrListenersGuard);
+    for (auto& listener : mErrListeners) {
+        if (!listener->onError(err, isFatal).isOk()) {
+            LOG(WARNING) << "Failed to notify listener about error";
+        }
+    }
+}
+
+static ErrorEvent parseErrorFrame(const struct canfd_frame& frame) {
+    // decode error frame (to a degree)
+    if ((frame.can_id & (CAN_ERR_BUSERROR | CAN_ERR_BUSOFF)) != 0) {
+        return ErrorEvent::BUS_ERROR;
+    }
+    if ((frame.data[1] & CAN_ERR_CRTL_TX_OVERFLOW) != 0) {
+        return ErrorEvent::TX_OVERFLOW;
+    }
+    if ((frame.data[1] & CAN_ERR_CRTL_RX_OVERFLOW) != 0) {
+        return ErrorEvent::RX_OVERFLOW;
+    }
+    if ((frame.data[2] & CAN_ERR_PROT_OVERLOAD) != 0) {
+        return ErrorEvent::BUS_OVERLOAD;
+    }
+    if ((frame.can_id & CAN_ERR_PROT) != 0) {
+        return ErrorEvent::MALFORMED_INPUT;
+    }
+    if ((frame.can_id & (CAN_ERR_CRTL | CAN_ERR_TRX | CAN_ERR_RESTARTED)) != 0) {
+        // "controller restarted" constitutes a HARDWARE_ERROR imo
+        return ErrorEvent::HARDWARE_ERROR;
+    }
+    return ErrorEvent::UNKNOWN_ERROR;
+}
+
+void CanBus::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) {
+    if ((frame.can_id & CAN_ERR_FLAG) != 0) {
+        // error bit is set
+        LOG(WARNING) << "CAN Error frame received";
+        notifyErrorListeners(parseErrorFrame(frame), false);
+        return;
+    }
+
+    CanMessage message = {};
+    message.id = frame.can_id & CAN_EFF_MASK;  // mask out eff/rtr/err flags
+    message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len);
+    message.timestamp = timestamp.count();
+    message.isExtendedId = (frame.can_id & CAN_EFF_FLAG) != 0;
+    message.remoteTransmissionRequest = (frame.can_id & CAN_RTR_FLAG) != 0;
+
+    if (UNLIKELY(kSuperVerbose)) {
+        LOG(VERBOSE) << "Got message " << toString(message);
+    }
+
+    std::lock_guard<std::mutex> lck(mMsgListenersGuard);
+    for (auto& listener : mMsgListeners) {
+        if (!match(listener.filter, message.id, message.remoteTransmissionRequest,
+                   message.isExtendedId))
+            continue;
+        if (!listener.callback->onReceive(message).isOk() && !listener.failedOnce) {
+            listener.failedOnce = true;
+            LOG(WARNING) << "Failed to notify listener about message";
+        }
+    }
+}
+
+void CanBus::onError(int errnoVal) {
+    auto eventType = ErrorEvent::HARDWARE_ERROR;
+
+    if (errnoVal == ENODEV || errnoVal == ENETDOWN) {
+        mDownAfterUse = false;
+        eventType = ErrorEvent::INTERFACE_DOWN;
+    }
+    notifyErrorListeners(eventType, true);
+
+    const auto errcb = mErrCb;
+    if (errcb != nullptr) errcb();
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h
new file mode 100644
index 0000000..8b73258
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "CanSocket.h"
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <utils/Mutex.h>
+
+#include <atomic>
+#include <thread>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+struct CanBus : public ICanBus {
+    using ErrorCallback = std::function<void()>;
+
+    virtual ~CanBus();
+
+    Return<Result> send(const CanMessage& message) override;
+    Return<void> listen(const hidl_vec<CanMessageFilter>& filter,
+                        const sp<ICanMessageListener>& listener, listen_cb _hidl_cb) override;
+    Return<sp<ICloseHandle>> listenForErrors(const sp<ICanErrorListener>& listener) override;
+
+    void setErrorCallback(ErrorCallback errcb);
+    ICanController::Result up();
+    bool down();
+
+  protected:
+    /**
+     * Blank constructor, since some interface types (such as SLCAN) don't get a name until after
+     * being initialized.
+     *
+     * If using this constructor, you MUST initialize mIfname prior to the completion of preUp().
+     */
+    CanBus();
+
+    CanBus(const std::string& ifname);
+
+    /**
+     * Prepare the SocketCAN interface.
+     *
+     * After calling this method, mIfname network interface is available and ready to be brought up.
+     *
+     * \return OK on success, or an error state on failure. See ICanController::Result
+     */
+    virtual ICanController::Result preUp();
+
+    /**
+     * Cleanup after bringing the interface down.
+     *
+     * This is a counterpart to preUp().
+     *
+     * \return true upon success and false upon failure
+     */
+    virtual bool postDown();
+
+    /** Network interface name. */
+    std::string mIfname;
+
+  private:
+    struct CanMessageListener {
+        sp<ICanMessageListener> callback;
+        hidl_vec<CanMessageFilter> filter;
+        wp<ICloseHandle> closeHandle;
+        bool failedOnce = false;
+    };
+    void clearMsgListeners();
+    void clearErrListeners();
+
+    void notifyErrorListeners(ErrorEvent err, bool isFatal);
+
+    void onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp);
+    void onError(int errnoVal);
+
+    std::mutex mMsgListenersGuard;
+    std::vector<CanMessageListener> mMsgListeners GUARDED_BY(mMsgListenersGuard);
+
+    std::mutex mErrListenersGuard;
+    std::vector<sp<ICanErrorListener>> mErrListeners GUARDED_BY(mErrListenersGuard);
+
+    std::unique_ptr<CanSocket> mSocket;
+    bool mDownAfterUse;
+
+    /**
+     * Guard for up flag is required to be held for entire time when the interface is being used
+     * (i.e. message being sent), because we don't want the interface to be torn down while
+     * executing that operation.
+     */
+    std::mutex mIsUpGuard;
+    bool mIsUp GUARDED_BY(mIsUpGuard) = false;
+
+    ErrorCallback mErrCb;
+};
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp
new file mode 100644
index 0000000..aafbecc
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusNative.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "CanBusNative.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+CanBusNative::CanBusNative(const std::string& ifname, uint32_t bitrate)
+    : CanBus(ifname), mBitrate(bitrate) {}
+
+ICanController::Result CanBusNative::preUp() {
+    if (!netdevice::exists(mIfname)) {
+        LOG(ERROR) << "Interface " << mIfname << " doesn't exist";
+        return ICanController::Result::BAD_INTERFACE_ID;
+    }
+
+    if (mBitrate == 0) {
+        // interface is already up and we just want to register it
+        return ICanController::Result::OK;
+    }
+
+    if (!netdevice::down(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    if (!netdevice::can::setBitrate(mIfname, mBitrate)) {
+        LOG(ERROR) << "Can't set bitrate " << mBitrate << " for " << mIfname;
+        return ICanController::Result::BAD_BITRATE;
+    }
+
+    return ICanController::Result::OK;
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusNative.h b/automotive/can/1.0/default/CanBusNative.h
new file mode 100644
index 0000000..04d7194
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusNative.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "CanBus.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+struct CanBusNative : public CanBus {
+    CanBusNative(const std::string& ifname, uint32_t bitrate);
+
+  protected:
+    virtual ICanController::Result preUp() override;
+
+  private:
+    const uint32_t mBitrate;
+};
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp
new file mode 100644
index 0000000..f08566c
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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 "CanBusSlcan.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <termios.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+namespace slcanprotocol {
+static const std::string kOpenCommand = "O\r";
+static const std::string kCloseCommand = "C\r";
+static constexpr int kSlcanDiscipline = N_SLCAN;
+static constexpr int kDefaultDiscipline = N_TTY;
+
+static const std::map<uint32_t, std::string> kBitrateCommands = {
+        {10000, "C\rS0\r"},  {20000, "C\rS1\r"},  {50000, "C\rS2\r"},
+        {100000, "C\rS3\r"}, {125000, "C\rS4\r"}, {250000, "C\rS5\r"},
+        {500000, "C\rS6\r"}, {800000, "C\rS7\r"}, {1000000, "C\rS8\r"}};
+}  // namespace slcanprotocol
+
+/**
+ * Serial Line CAN constructor
+ * \param string uartName - name of slcan device (e.x. /dev/ttyUSB0)
+ * \param uint32_t bitrate - speed of the CAN bus (125k = MSCAN, 500k = HSCAN)
+ */
+CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate)
+    : CanBus(), mUartName(uartName), kBitrate(bitrate) {}
+
+/** helper function to update CanBusSlcan object's iface name */
+ICanController::Result CanBusSlcan::updateIfaceName(base::unique_fd& uartFd) {
+    struct ifreq ifrequest = {};
+    /*
+     * Fetching the iface name with an ioctl won't interfere with an open socketCAN iface attached
+     * to this tty. This is important in the event we are trying to register a SLCAN based iface
+     * that has already been configured and brought up.
+     */
+    if (ioctl(uartFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) {
+        PLOG(ERROR) << "Failed to get the name of the created device";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // Update the CanBus object with name that was assigned to it
+    mIfname = ifrequest.ifr_name;
+    return ICanController::Result::OK;
+}
+
+ICanController::Result CanBusSlcan::preUp() {
+    // verify valid bitrate and translate to serial command format
+    std::optional<std::string> canBitrateCommand = std::nullopt;
+    if (kBitrate != 0) {
+        const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate);
+        if (lookupIt == slcanprotocol::kBitrateCommands.end()) {
+            return ICanController::Result::BAD_BITRATE;
+        }
+        canBitrateCommand = lookupIt->second;
+    }
+
+    /* Attempt to open the uart in r/w without blocking or becoming the
+     * controlling terminal */
+    mFd = base::unique_fd(open(mUartName.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY));
+    if (!mFd.ok()) {
+        PLOG(ERROR) << "SLCAN Failed to open " << mUartName;
+        return ICanController::Result::BAD_INTERFACE_ID;
+    }
+
+    // If the device is already up, update the iface name in our CanBusSlcan object
+    if (kBitrate == 0) {
+        return updateIfaceName(mFd);
+    }
+
+    // blank terminal settings and pull them from the device
+    struct termios terminalSettings = {};
+    if (tcgetattr(mFd.get(), &terminalSettings) < 0) {
+        PLOG(ERROR) << "Failed to read attrs of" << mUartName;
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // change settings to raw mode
+    cfmakeraw(&terminalSettings);
+
+    // disable software flow control
+    terminalSettings.c_iflag &= ~IXOFF;
+    // enable hardware flow control
+    terminalSettings.c_cflag |= CRTSCTS;
+
+    struct serial_struct serialSettings;
+    // get serial settings
+    if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) {
+        PLOG(ERROR) << "Failed to read serial settings from " << mUartName;
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+    // set low latency mode
+    serialSettings.flags |= ASYNC_LOW_LATENCY;
+    // apply serial settings
+    if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) {
+        PLOG(ERROR) << "Failed to set low latency mode on " << mUartName;
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    /* TCSADRAIN applies settings after we finish writing the rest of our
+     * changes (as opposed to TCSANOW, which changes immediately) */
+    if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) {
+        PLOG(ERROR) << "Failed to apply terminal settings to " << mUartName;
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // apply speed setting for CAN
+    if (write(mFd.get(), canBitrateCommand->c_str(), canBitrateCommand->length()) <= 0) {
+        PLOG(ERROR) << "Failed to apply CAN bitrate";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // TODO(b/144775286): set open flag & support listen only
+    if (write(mFd.get(), slcanprotocol::kOpenCommand.c_str(),
+              slcanprotocol::kOpenCommand.length()) <= 0) {
+        PLOG(ERROR) << "Failed to set open flag";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // set line discipline to slcan
+    if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) {
+        PLOG(ERROR) << "Failed to set line discipline to slcan";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // Update the CanBus object with name that was assigned to it
+    return updateIfaceName(mFd);
+}
+
+bool CanBusSlcan::postDown() {
+    // reset the line discipline to TTY mode
+    if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kDefaultDiscipline) < 0) {
+        LOG(ERROR) << "Failed to reset line discipline!";
+        return false;
+    }
+
+    // issue the close command
+    if (write(mFd.get(), slcanprotocol::kCloseCommand.c_str(),
+              slcanprotocol::kCloseCommand.length()) <= 0) {
+        LOG(ERROR) << "Failed to close tty!";
+        return false;
+    }
+
+    // close our unique_fd
+    mFd.reset();
+
+    return true;
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusSlcan.h b/automotive/can/1.0/default/CanBusSlcan.h
new file mode 100644
index 0000000..2328a2c
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <net/if.h>
+#include <termios.h>
+#include "CanBus.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+struct CanBusSlcan : public CanBus {
+    CanBusSlcan(const std::string& uartName, uint32_t bitrate);
+
+  protected:
+    virtual ICanController::Result preUp() override;
+    virtual bool postDown() override;
+
+  private:
+    ICanController::Result updateIfaceName(base::unique_fd& uartFd);
+
+    const std::string mUartName;
+    const uint32_t kBitrate;
+    base::unique_fd mFd;
+};
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusVirtual.cpp b/automotive/can/1.0/default/CanBusVirtual.cpp
new file mode 100644
index 0000000..32fe8d6
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusVirtual.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 "CanBusVirtual.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {}
+
+ICanController::Result CanBusVirtual::preUp() {
+    if (netdevice::exists(mIfname)) return ICanController::Result::OK;
+
+    LOG(DEBUG) << "Virtual interface " << mIfname << " doesn't exist, creating...";
+    mWasCreated = true;
+    if (!netdevice::add(mIfname, "vcan")) {
+        LOG(ERROR) << "Can't create vcan interface " << mIfname;
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    return ICanController::Result::OK;
+}
+
+bool CanBusVirtual::postDown() {
+    if (mWasCreated) {
+        mWasCreated = false;
+        if (!netdevice::del(mIfname)) {
+            LOG(ERROR) << "Couldn't remove vcan interface " << mIfname;
+            return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanBusVirtual.h b/automotive/can/1.0/default/CanBusVirtual.h
new file mode 100644
index 0000000..3990b20
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusVirtual.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "CanBus.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+struct CanBusVirtual : public CanBus {
+    CanBusVirtual(const std::string& ifname);
+
+  protected:
+    virtual ICanController::Result preUp() override;
+    virtual bool postDown() override;
+
+  private:
+    bool mWasCreated = false;
+};
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp
new file mode 100644
index 0000000..9c0f2c5
--- /dev/null
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -0,0 +1,330 @@
+/*
+ * 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 "CanController.h"
+
+#include "CanBusNative.h"
+#include "CanBusSlcan.h"
+#include "CanBusVirtual.h"
+
+#include <android-base/logging.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+#include <automotive/filesystem>
+#include <fstream>
+#include <regex>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+using IfId = ICanController::BusConfig::InterfaceId;
+using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator;
+namespace fs = android::hardware::automotive::filesystem;
+
+namespace fsErrors {
+static const std::error_code ok;
+static const std::error_code eperm(EPERM, std::generic_category());
+static const std::error_code enoent(ENOENT, std::generic_category());
+static const std::error_code eacces(EACCES, std::generic_category());
+}  // namespace fsErrors
+
+/* In the /sys/devices tree, there are files called "serial", which contain the serial numbers
+ * for various devices. The exact location inside of this directory is dependent upon the
+ * hardware we are running on, so we have to start from /sys/devices and work our way down. */
+static const fs::path kDevPath("/sys/devices/");
+static const std::regex kTtyRe("^tty[A-Z]+[0-9]+$");
+static constexpr auto kOpts = ~(fs::directory_options::follow_directory_symlink |
+                                fs::directory_options::skip_permission_denied);
+
+/**
+ * A helper object to associate the interface name and type of a USB to CAN adapter.
+ */
+struct UsbCanIface {
+    ICanController::InterfaceType iftype;
+    std::string ifaceName;
+};
+
+Return<void> CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) {
+    _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN,
+              ICanController::InterfaceType::SLCAN});
+    return {};
+}
+
+static bool isValidName(const std::string& name) {
+    static const std::regex nameRE("^[a-zA-Z0-9_]{1,32}$");
+    return std::regex_match(name, nameRE);
+}
+
+/**
+ * Given a UsbCanIface object, get the ifaceName given the serialPath.
+ *
+ * \param serialPath - Absolute path to a "serial" file for a given device in /sys.
+ * \return A populated UsbCanIface. On failure, nullopt is returned.
+ */
+static std::optional<UsbCanIface> getIfaceName(fs::path serialPath) {
+    std::error_code fsStatus;
+    // Since the path is to a file called "serial", we need to search its parent directory.
+    fs::recursive_directory_iterator fsItr(serialPath.parent_path(), kOpts, fsStatus);
+    if (fsStatus != fsErrors::ok) {
+        LOG(ERROR) << "Failed to open " << serialPath.parent_path();
+        return std::nullopt;
+    }
+
+    for (; fsStatus == fsErrors::ok && fsItr != fs::recursive_directory_iterator();
+         fsItr.increment(fsStatus)) {
+        /* We want either a directory called "net" or a directory that looks like tty<something>, so
+         * skip files. */
+        bool isDir = fsItr->is_directory(fsStatus);
+        if (fsStatus != fsErrors::ok || !isDir) continue;
+
+        /* path() returns an iterator that steps through directories from / to the leaf.
+         * end() returns one past the leaf of the path, but we want the leaf. Decrementing the
+         * path gives us a pointer to the leaf, which we then dereference.*/
+        std::string currentDir = *(--(fsItr->path().end()));
+        if (currentDir == "net") {
+            /* This device is a SocketCAN device. The iface name is the only directory under
+             * net/. Multiple directories under net/ is an error.*/
+            fs::directory_iterator netItr(fsItr->path(), kOpts, fsStatus);
+            if (fsStatus != fsErrors::ok) {
+                LOG(ERROR) << "Failed to open " << fsItr->path() << " to get net name!";
+                return std::nullopt;
+            }
+
+            // Get the leaf of the path. This is the interface name, assuming it's the only leaf.
+            std::string netName = *(--(netItr->path().end()));
+
+            // Check if there is more than one item in net/
+            netItr.increment(fsStatus);
+            if (fsStatus != fsErrors::ok) {
+                // It's possible we have a valid net name, but this is most likely an error.
+                LOG(ERROR) << "Failed to verify " << fsItr->path() << " has valid net name!";
+                return std::nullopt;
+            }
+            if (netItr != fs::directory_iterator()) {
+                // There should never be more than one name under net/
+                LOG(ERROR) << "Found more than one net name in " << fsItr->path() << "!";
+                return std::nullopt;
+            }
+            return {{ICanController::InterfaceType::SOCKETCAN, netName}};
+        } else if (std::regex_match(currentDir, kTtyRe)) {
+            // This device is a USB serial device, and currentDir is the tty name.
+            return {{ICanController::InterfaceType::SLCAN, "/dev/" + currentDir}};
+        }
+    }
+
+    // check if the loop above exited due to a c++fs error.
+    if (fsStatus != fsErrors::ok) {
+        LOG(ERROR) << "Failed search filesystem: " << fsStatus;
+    }
+    return std::nullopt;
+}
+
+/**
+ * A helper function to read the serial number from a "serial" file in /sys/devices/
+ *
+ * \param serialnoPath - path to the file to read.
+ * \return the serial number, or nullopt on failure.
+ */
+static std::optional<std::string> readSerialNo(const std::string& serialnoPath) {
+    std::ifstream serialnoStream(serialnoPath);
+    std::string serialno;
+    if (!serialnoStream.good()) {
+        LOG(ERROR) << "Failed to read serial number from " << serialnoPath;
+        return std::nullopt;
+    }
+    std::getline(serialnoStream, serialno);
+    return serialno;
+}
+
+/**
+ * Searches for USB devices found in /sys/devices/, and attempts to find a device matching the
+ * provided list of serial numbers.
+ *
+ * \param configSerialnos - a list of serial number (suffixes) from the HAL config.
+ * \param iftype - the type of the interface to be located.
+ * \return a matching USB device. On failure, std::nullopt is returned.
+ */
+static std::optional<UsbCanIface> findUsbDevice(const hidl_vec<hidl_string>& configSerialnos) {
+    std::error_code fsStatus;
+    fs::recursive_directory_iterator fsItr(kDevPath, kOpts, fsStatus);
+    if (fsStatus != fsErrors::ok) {
+        LOG(ERROR) << "Failed to open " << kDevPath;
+        return std::nullopt;
+    }
+
+    for (; fsStatus == fsErrors::ok && fsItr != fs::recursive_directory_iterator();
+         fsItr.increment(fsStatus)) {
+        // We want to find a file called "serial", which is in a directory somewhere. Skip files.
+        bool isDir = fsItr->is_directory(fsStatus);
+        if (fsStatus != fsErrors::ok) {
+            LOG(ERROR) << "Failed check if " << fsStatus;
+            return std::nullopt;
+        }
+        if (!isDir) continue;
+
+        auto serialnoPath = fsItr->path() / "serial";
+        bool isReg = fs::is_regular_file(serialnoPath, fsStatus);
+
+        /* Make sure we have permissions to this directory, ignore enoent, since the file
+         * "serial" may not exist, which is ok. */
+        if (fsStatus == fsErrors::eperm || fsStatus == fsErrors::eacces) {
+            /* This means we  don't have access to this directory. If we recurse into it, this
+             * will cause the iterator to loose its state and we'll crash. */
+            fsItr.disable_recursion_pending();
+            continue;
+        }
+        if (fsStatus == fsErrors::enoent) continue;
+        if (fsStatus != fsErrors::ok) {
+            LOG(WARNING) << "An unexpected error occurred while checking for serialno: "
+                         << fsStatus;
+            continue;
+        }
+        if (!isReg) continue;
+
+        // we found a serial number
+        auto serialno = readSerialNo(serialnoPath);
+        if (!serialno.has_value()) continue;
+
+        // see if the serial number exists in the config
+        for (auto&& cfgSn : configSerialnos) {
+            if (serialno->ends_with(std::string(cfgSn))) {
+                auto ifaceInfo = getIfaceName(serialnoPath);
+                if (!ifaceInfo.has_value()) break;
+                return ifaceInfo;
+            }
+        }
+    }
+    if (fsStatus != fsErrors::ok) {
+        LOG(ERROR) << "Error searching filesystem: " << fsStatus;
+        return std::nullopt;
+    }
+    return std::nullopt;
+}
+
+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::BAD_SERVICE_NAME;
+    }
+
+    if (mCanBuses.find(config.name) != mCanBuses.end()) {
+        LOG(ERROR) << "Bus " << config.name << " is already up";
+        return ICanController::Result::INVALID_STATE;
+    }
+
+    sp<CanBus> busService;
+
+    // SocketCAN native type interface.
+    if (config.interfaceId.getDiscriminator() == IfIdDisc::socketcan) {
+        auto& socketcan = config.interfaceId.socketcan();
+        std::string ifaceName;
+        if (socketcan.getDiscriminator() == IfId::Socketcan::hidl_discriminator::serialno) {
+            // Configure by serial number.
+            auto selectedDevice = findUsbDevice(socketcan.serialno());
+            // verify the returned device is the correct one
+            if (!selectedDevice.has_value() ||
+                selectedDevice->iftype != ICanController::InterfaceType::SOCKETCAN) {
+                return ICanController::Result::BAD_INTERFACE_ID;
+            }
+            ifaceName = selectedDevice->ifaceName;
+        } else {
+            // configure by iface name.
+            ifaceName = socketcan.ifname();
+        }
+        busService = new CanBusNative(ifaceName, config.bitrate);
+    }
+    // Virtual interface.
+    else if (config.interfaceId.getDiscriminator() == IfIdDisc::virtualif) {
+        busService = new CanBusVirtual(config.interfaceId.virtualif().ifname);
+    }
+    // SLCAN interface.
+    else if (config.interfaceId.getDiscriminator() == IfIdDisc::slcan) {
+        auto& slcan = config.interfaceId.slcan();
+        std::string ttyName;
+        if (slcan.getDiscriminator() == IfId::Slcan::hidl_discriminator::serialno) {
+            // Configure by serial number.
+            auto selectedDevice = findUsbDevice(slcan.serialno());
+            if (!selectedDevice.has_value() ||
+                selectedDevice->iftype != ICanController::InterfaceType::SLCAN) {
+                return ICanController::Result::BAD_INTERFACE_ID;
+            }
+            ttyName = selectedDevice->ifaceName;
+        } else {
+            // Configure by tty name.
+            ttyName = slcan.ttyname();
+        }
+        busService = new CanBusSlcan(ttyName, config.bitrate);
+    } else {
+        return ICanController::Result::NOT_SUPPORTED;
+    }
+
+    busService->setErrorCallback([this, name = config.name]() { downInterface(name); });
+
+    const auto result = busService->up();
+    if (result != ICanController::Result::OK) return result;
+
+    if (busService->registerAsService(config.name) != OK) {
+        LOG(ERROR) << "Failed to register ICanBus/" << config.name;
+        if (!busService->down()) {
+            LOG(WARNING) << "Failed to bring down CAN bus that failed to register";
+        }
+        return ICanController::Result::BAD_SERVICE_NAME;
+    }
+
+    mCanBuses[config.name] = busService;
+
+    return ICanController::Result::OK;
+}
+
+static bool unregisterCanBusService(const hidl_string& name, sp<CanBus> busService) {
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    if (!manager) return false;
+    const auto res = manager->tryUnregister(ICanBus::descriptor, name, busService);
+    if (!res.isOk()) return false;
+    return res;
+}
+
+Return<bool> CanController::downInterface(const hidl_string& name) {
+    LOG(VERBOSE) << "Attempting to bring interface down: " << name;
+
+    std::lock_guard<std::mutex> lck(mCanBusesGuard);
+
+    auto busEntry = mCanBuses.extract(name);
+    if (!busEntry) {
+        LOG(WARNING) << "Interface " << name << " is not up";
+        return false;
+    }
+
+    auto success = true;
+
+    if (!unregisterCanBusService(name, busEntry.mapped())) {
+        LOG(ERROR) << "Couldn't unregister " << name;
+        // don't return yet, let's try to do best-effort cleanup
+        success = false;
+    }
+
+    if (!busEntry.mapped()->down()) {
+        LOG(ERROR) << "Couldn't bring " << name << " down";
+        success = false;
+    }
+
+    return success;
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanController.h b/automotive/can/1.0/default/CanController.h
new file mode 100644
index 0000000..27e82f3
--- /dev/null
+++ b/automotive/can/1.0/default/CanController.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "CanBus.h"
+
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+struct CanController : public ICanController {
+    Return<void> getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) override;
+
+    Return<ICanController::Result> upInterface(const ICanController::BusConfig& config) override;
+    Return<bool> downInterface(const hidl_string& name) override;
+
+  private:
+    std::mutex mCanBusesGuard;
+    std::map<std::string, sp<CanBus>> mCanBuses GUARDED_BY(mCanBusesGuard);
+};
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp
new file mode 100644
index 0000000..f379d5a
--- /dev/null
+++ b/automotive/can/1.0/default/CanSocket.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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 "CanSocket.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+#include <linux/can.h>
+#include <utils/SystemClock.h>
+
+#include <chrono>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+using namespace std::chrono_literals;
+
+/* How frequently the read thread checks whether the interface was asked to be down.
+ *
+ * Note: This does *not* affect read timing or bandwidth, just CPU load vs time to
+ *       down the interface. */
+static constexpr auto kReadPooling = 100ms;
+
+std::unique_ptr<CanSocket> CanSocket::open(const std::string& ifname, ReadCallback rdcb,
+                                           ErrorCallback errcb) {
+    auto sock = netdevice::can::socket(ifname);
+    if (!sock.ok()) {
+        LOG(ERROR) << "Can't open CAN socket on " << ifname;
+        return nullptr;
+    }
+
+    // Can't use std::make_unique due to private CanSocket constructor.
+    return std::unique_ptr<CanSocket>(new CanSocket(std::move(sock), rdcb, errcb));
+}
+
+CanSocket::CanSocket(base::unique_fd socket, ReadCallback rdcb, ErrorCallback errcb)
+    : mReadCallback(rdcb),
+      mErrorCallback(errcb),
+      mSocket(std::move(socket)),
+      mReaderThread(&CanSocket::readerThread, this) {}
+
+CanSocket::~CanSocket() {
+    mStopReaderThread = true;
+
+    /* CanSocket can be brought down as a result of read failure, from the same thread,
+     * so let's just detach and let it finish on its own. */
+    if (mReaderThreadFinished) {
+        mReaderThread.detach();
+    } else {
+        mReaderThread.join();
+    }
+}
+
+bool CanSocket::send(const struct canfd_frame& frame) {
+    const auto res = write(mSocket.get(), &frame, CAN_MTU);
+    if (res < 0) {
+        PLOG(DEBUG) << "CanSocket send failed";
+        return false;
+    }
+    if (res != CAN_MTU) {
+        LOG(DEBUG) << "CanSocket sent wrong number of bytes: " << res;
+        return false;
+    }
+    return true;
+}
+
+static struct timeval toTimeval(std::chrono::microseconds t) {
+    struct timeval tv;
+    tv.tv_sec = t / 1s;
+    tv.tv_usec = (t % 1s) / 1us;
+    return tv;
+}
+
+static int selectRead(const base::unique_fd& fd, std::chrono::microseconds timeout) {
+    auto timeouttv = toTimeval(timeout);
+    fd_set readfds;
+    FD_ZERO(&readfds);
+    FD_SET(fd.get(), &readfds);
+    return select(fd.get() + 1, &readfds, nullptr, nullptr, &timeouttv);
+}
+
+void CanSocket::readerThread() {
+    LOG(VERBOSE) << "Reader thread started";
+    int errnoCopy = 0;
+
+    while (!mStopReaderThread) {
+        /* The ideal would be to have a blocking read(3) call and interrupt it with shutdown(3).
+         * This is unfortunately not supported for SocketCAN, so we need to rely on select(3). */
+        const auto sel = selectRead(mSocket, kReadPooling);
+        if (sel == 0) continue;  // timeout
+        if (sel == -1) {
+            PLOG(ERROR) << "Select failed";
+            break;
+        }
+
+        struct canfd_frame frame;
+        const auto nbytes = read(mSocket.get(), &frame, CAN_MTU);
+
+        /* We could use SIOCGSTAMP to get a precise UNIX timestamp for a given packet, but what
+         * we really need is a time since boot. There is no direct way to convert between these
+         * clocks. We could implement a class to calculate the difference between the clocks
+         * (querying both several times and picking the smallest difference); apply the difference
+         * to a SIOCGSTAMP returned value; re-synchronize if the elapsed time is too much in the
+         * past (indicating the UNIX timestamp might have been adjusted).
+         *
+         * Apart from the added complexity, it's possible the added calculations and system calls
+         * would add so much time to the processing pipeline so the precision of the reported time
+         * was buried under the subsystem latency. Let's just use a local time since boot here and
+         * leave precise hardware timestamps for custom proprietary implementations (if needed). */
+        const std::chrono::nanoseconds ts(elapsedRealtimeNano());
+
+        if (nbytes != CAN_MTU) {
+            if (nbytes >= 0) {
+                LOG(ERROR) << "Failed to read CAN packet, got " << nbytes << " bytes";
+                break;
+            }
+            if (errno == EAGAIN) continue;
+
+            errnoCopy = errno;
+            PLOG(ERROR) << "Failed to read CAN packet";
+            break;
+        }
+
+        mReadCallback(frame, ts);
+    }
+
+    bool failed = !mStopReaderThread;
+    auto errCb = mErrorCallback;
+    mReaderThreadFinished = true;
+
+    // Don't access any fields from here, see CanSocket::~CanSocket comment about detached thread
+    if (failed) errCb(errnoCopy);
+
+    LOG(VERBOSE) << "Reader thread stopped";
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h
new file mode 100644
index 0000000..fd956b5
--- /dev/null
+++ b/automotive/can/1.0/default/CanSocket.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+#include <linux/can.h>
+
+#include <atomic>
+#include <chrono>
+#include <thread>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+/** Wrapper around SocketCAN socket. */
+struct CanSocket {
+    using ReadCallback = std::function<void(const struct canfd_frame&, std::chrono::nanoseconds)>;
+    using ErrorCallback = std::function<void(int errnoVal)>;
+
+    /**
+     * Open and bind SocketCAN socket.
+     *
+     * \param ifname SocketCAN network interface name (such as can0)
+     * \param rdcb Callback on received messages
+     * \param errcb Callback on socket failure
+     * \return Socket instance, or nullptr if it wasn't possible to open one
+     */
+    static std::unique_ptr<CanSocket> open(const std::string& ifname, ReadCallback rdcb,
+                                           ErrorCallback errcb);
+    virtual ~CanSocket();
+
+    /**
+     * Send CAN frame.
+     *
+     * \param frame Frame to send
+     * \return true in case of success, false otherwise
+     */
+    bool send(const struct canfd_frame& frame);
+
+  private:
+    CanSocket(base::unique_fd socket, ReadCallback rdcb, ErrorCallback errcb);
+    void readerThread();
+
+    ReadCallback mReadCallback;
+    ErrorCallback mErrorCallback;
+
+    const base::unique_fd mSocket;
+    std::thread mReaderThread;
+    std::atomic<bool> mStopReaderThread = false;
+    std::atomic<bool> mReaderThreadFinished = false;
+
+    DISALLOW_COPY_AND_ASSIGN(CanSocket);
+};
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CloseHandle.cpp b/automotive/can/1.0/default/CloseHandle.cpp
new file mode 100644
index 0000000..e1ffe2b
--- /dev/null
+++ b/automotive/can/1.0/default/CloseHandle.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 "CloseHandle.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {}
+
+CloseHandle::~CloseHandle() {
+    close();
+}
+
+Return<void> CloseHandle::close() {
+    const auto wasClosed = mIsClosed.exchange(true);
+    if (wasClosed) return {};
+
+    if (mCallback != nullptr) mCallback();
+    return {};
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h
new file mode 100644
index 0000000..c332d74
--- /dev/null
+++ b/automotive/can/1.0/default/CloseHandle.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android/hardware/automotive/can/1.0/ICloseHandle.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+/** Generic ICloseHandle implementation ignoring double-close events. */
+struct CloseHandle : public ICloseHandle {
+    using Callback = std::function<void()>;
+
+    /**
+     * Create a handle with a callback.
+     *
+     * The callback is guaranteed to be called exactly once.
+     *
+     * \param callback Called on the first close() call, or on destruction of the handle
+     */
+    CloseHandle(Callback callback = nullptr);
+    virtual ~CloseHandle();
+
+    Return<void> close() override;
+
+  private:
+    const Callback mCallback;
+    std::atomic<bool> mIsClosed = false;
+
+    DISALLOW_COPY_AND_ASSIGN(CloseHandle);
+};
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
diff --git a/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc b/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc
new file mode 100644
index 0000000..a629bda
--- /dev/null
+++ b/automotive/can/1.0/default/android.hardware.automotive.can@1.0-service.rc
@@ -0,0 +1,5 @@
+service can-hal-1.0-service /vendor/bin/hw/android.hardware.automotive.can@1.0-service
+    class hal
+    capabilities NET_ADMIN
+    user vehicle_network
+    group system inet
diff --git a/automotive/can/1.0/default/libc++fs/.clang-format b/automotive/can/1.0/default/libc++fs/.clang-format
new file mode 100644
index 0000000..dd59681
--- /dev/null
+++ b/automotive/can/1.0/default/libc++fs/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: LLVM
+
+---
+Language: Cpp
+Standard: Cpp03
+
+AlwaysBreakTemplateDeclarations: true
+PointerAlignment: Left
+
+# Disable formatting options which may break tests.
+SortIncludes: false
+ReflowComments: false
+---
diff --git a/automotive/can/1.0/default/libc++fs/Android.bp b/automotive/can/1.0/default/libc++fs/Android.bp
new file mode 100644
index 0000000..7ab1c28
--- /dev/null
+++ b/automotive/can/1.0/default/libc++fs/Android.bp
@@ -0,0 +1,61 @@
+//
+// 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.
+//
+
+// TODO(152067309): Stop building this yourself once it's ABI stable and has
+// been made vendor available. Just use libc++fs instead of this.
+
+cc_defaults {
+    name: "android.hardware.automotive@libc++fsdefaults",
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+    cppflags: [
+        "-std=c++17",
+        "-fexceptions",
+        "-DLIBCXX_BUILDING_LIBCXXABI",
+        "-D_LIBCPP_BUILDING_LIBRARY",
+    ],
+    rtti: true,
+}
+
+cc_library_static {
+    name: "android.hardware.automotive@libc++fs",
+    recovery_available: true,
+    vendor: true,
+    defaults: ["android.hardware.automotive@libc++fsdefaults"],
+    srcs: [
+        "src/filesystem/directory_iterator.cpp",
+        "src/filesystem/operations.cpp",
+    ],
+    multilib: {
+        lib32: {
+            // off_t usage is constrained to within the libc++ source (not the
+            // headers), so we can build the filesystem library with a 64-bit
+            // off_t on LP32 to get large file support without needing all users
+            // of the library to match.
+            cflags: ["-D_FILE_OFFSET_BITS=64"],
+        },
+    },
+    target: {
+        windows: {
+            enabled: false,
+        },
+    },
+}
diff --git a/automotive/can/1.0/default/libc++fs/include/automotive/filesystem b/automotive/can/1.0/default/libc++fs/include/automotive/filesystem
new file mode 100644
index 0000000..660ad09
--- /dev/null
+++ b/automotive/can/1.0/default/libc++fs/include/automotive/filesystem
@@ -0,0 +1,2699 @@
+// -*- C++ -*-
+//===--------------------------- filesystem -------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef _LIBAUTO_FILESYSTEM
+#define _LIBAUTO_FILESYSTEM
+/*
+    filesystem synopsis
+
+    namespace android::hardware::automotive { namespace filesystem {
+
+    class path;
+
+    void swap(path& lhs, path& rhs) noexcept;
+    size_t hash_value(const path& p) noexcept;
+
+    bool operator==(const path& lhs, const path& rhs) noexcept;
+    bool operator!=(const path& lhs, const path& rhs) noexcept;
+    bool operator< (const path& lhs, const path& rhs) noexcept;
+    bool operator<=(const path& lhs, const path& rhs) noexcept;
+    bool operator> (const path& lhs, const path& rhs) noexcept;
+    bool operator>=(const path& lhs, const path& rhs) noexcept;
+
+    path operator/ (const path& lhs, const path& rhs);
+
+    // fs.path.io operators are friends of path.
+    template <class charT, class traits>
+    friend basic_ostream<charT, traits>&
+    operator<<(basic_ostream<charT, traits>& os, const path& p);
+
+    template <class charT, class traits>
+    friend basic_istream<charT, traits>&
+    operator>>(basic_istream<charT, traits>& is, path& p);
+
+    template <class Source>
+      path u8path(const Source& source);
+    template <class InputIterator>
+      path u8path(InputIterator first, InputIterator last);
+
+    class filesystem_error;
+    class directory_entry;
+
+    class directory_iterator;
+
+    // enable directory_iterator range-based for statements
+    directory_iterator begin(directory_iterator iter) noexcept;
+    directory_iterator end(const directory_iterator&) noexcept;
+
+    class recursive_directory_iterator;
+
+    // enable recursive_directory_iterator range-based for statements
+    recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
+    recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;
+
+    class file_status;
+
+    struct space_info
+    {
+      uintmax_t capacity;
+      uintmax_t free;
+      uintmax_t available;
+    };
+
+    enum class file_type;
+    enum class perms;
+    enum class perm_options;
+    enum class copy_options;
+    enum class directory_options;
+
+    typedef chrono::time_point<trivial-clock>  file_time_type;
+
+    // operational functions
+
+    path absolute(const path& p);
+    path absolute(const path& p, error_code &ec);
+
+    path canonical(const path& p);
+    path canonical(const path& p, error_code& ec);
+
+    void copy(const path& from, const path& to);
+    void copy(const path& from, const path& to, error_code& ec);
+    void copy(const path& from, const path& to, copy_options options);
+    void copy(const path& from, const path& to, copy_options options,
+                   error_code& ec);
+
+    bool copy_file(const path& from, const path& to);
+    bool copy_file(const path& from, const path& to, error_code& ec);
+    bool copy_file(const path& from, const path& to, copy_options option);
+    bool copy_file(const path& from, const path& to, copy_options option,
+                           error_code& ec);
+
+    void copy_symlink(const path& existing_symlink, const path& new_symlink);
+    void copy_symlink(const path& existing_symlink, const path& new_symlink,
+                              error_code& ec) noexcept;
+
+    bool create_directories(const path& p);
+    bool create_directories(const path& p, error_code& ec);
+
+    bool create_directory(const path& p);
+    bool create_directory(const path& p, error_code& ec) noexcept;
+
+    bool create_directory(const path& p, const path& attributes);
+    bool create_directory(const path& p, const path& attributes,
+                                  error_code& ec) noexcept;
+
+    void create_directory_symlink(const path& to, const path& new_symlink);
+    void create_directory_symlink(const path& to, const path& new_symlink,
+                                          error_code& ec) noexcept;
+
+    void create_hard_link(const path& to, const path& new_hard_link);
+    void create_hard_link(const path& to, const path& new_hard_link,
+                                  error_code& ec) noexcept;
+
+    void create_symlink(const path& to, const path& new_symlink);
+    void create_symlink(const path& to, const path& new_symlink,
+                                error_code& ec) noexcept;
+
+    path current_path();
+    path current_path(error_code& ec);
+    void current_path(const path& p);
+    void current_path(const path& p, error_code& ec) noexcept;
+
+    bool exists(file_status s) noexcept;
+    bool exists(const path& p);
+    bool exists(const path& p, error_code& ec) noexcept;
+
+    bool equivalent(const path& p1, const path& p2);
+    bool equivalent(const path& p1, const path& p2, error_code& ec) noexcept;
+
+    uintmax_t    file_size(const path& p);
+    uintmax_t    file_size(const path& p, error_code& ec) noexcept;
+
+    uintmax_t    hard_link_count(const path& p);
+    uintmax_t    hard_link_count(const path& p, error_code& ec) noexcept;
+
+    bool is_block_file(file_status s) noexcept;
+    bool is_block_file(const path& p);
+    bool is_block_file(const path& p, error_code& ec) noexcept;
+
+    bool is_character_file(file_status s) noexcept;
+    bool is_character_file(const path& p);
+    bool is_character_file(const path& p, error_code& ec) noexcept;
+
+    bool is_directory(file_status s) noexcept;
+    bool is_directory(const path& p);
+    bool is_directory(const path& p, error_code& ec) noexcept;
+
+    bool is_empty(const path& p);
+    bool is_empty(const path& p, error_code& ec) noexcept;
+
+    bool is_fifo(file_status s) noexcept;
+    bool is_fifo(const path& p);
+    bool is_fifo(const path& p, error_code& ec) noexcept;
+
+    bool is_other(file_status s) noexcept;
+    bool is_other(const path& p);
+    bool is_other(const path& p, error_code& ec) noexcept;
+
+    bool is_regular_file(file_status s) noexcept;
+    bool is_regular_file(const path& p);
+    bool is_regular_file(const path& p, error_code& ec) noexcept;
+
+    bool is_socket(file_status s) noexcept;
+    bool is_socket(const path& p);
+    bool is_socket(const path& p, error_code& ec) noexcept;
+
+    bool is_symlink(file_status s) noexcept;
+    bool is_symlink(const path& p);
+    bool is_symlink(const path& p, error_code& ec) noexcept;
+
+    file_time_type  last_write_time(const path& p);
+    file_time_type  last_write_time(const path& p, error_code& ec) noexcept;
+    void last_write_time(const path& p, file_time_type new_time);
+    void last_write_time(const path& p, file_time_type new_time,
+                                 error_code& ec) noexcept;
+
+    void permissions(const path& p, perms prms,
+                     perm_options opts=perm_options::replace);
+    void permissions(const path& p, perms prms, error_code& ec) noexcept;
+    void permissions(const path& p, perms prms, perm_options opts,
+                     error_code& ec);
+
+    path proximate(const path& p, error_code& ec);
+    path proximate(const path& p, const path& base = current_path());
+    path proximate(const path& p, const path& base, error_code &ec);
+
+    path read_symlink(const path& p);
+    path read_symlink(const path& p, error_code& ec);
+
+    path relative(const path& p, error_code& ec);
+    path relative(const path& p, const path& base=current_path());
+    path relative(const path& p, const path& base, error_code& ec);
+
+    bool remove(const path& p);
+    bool remove(const path& p, error_code& ec) noexcept;
+
+    uintmax_t    remove_all(const path& p);
+    uintmax_t    remove_all(const path& p, error_code& ec);
+
+    void rename(const path& from, const path& to);
+    void rename(const path& from, const path& to, error_code& ec) noexcept;
+
+    void resize_file(const path& p, uintmax_t size);
+    void resize_file(const path& p, uintmax_t size, error_code& ec) noexcept;
+
+    space_info   space(const path& p);
+    space_info   space(const path& p, error_code& ec) noexcept;
+
+    file_status  status(const path& p);
+    file_status  status(const path& p, error_code& ec) noexcept;
+
+    bool status_known(file_status s) noexcept;
+
+    file_status  symlink_status(const path& p);
+    file_status  symlink_status(const path& p, error_code& ec) noexcept;
+
+    path temp_directory_path();
+    path temp_directory_path(error_code& ec);
+
+    path weakly_canonical(path const& p);
+    path weakly_canonical(path const& p, error_code& ec);
+
+
+} }  // namespace android::hardware::automotive::filesystem
+
+*/
+
+#include <__config>
+#include <cstddef>
+#include <cstdlib>
+#include <chrono>
+#include <iterator>
+#include <iosfwd>
+#include <locale>
+#include <memory>
+#include <stack>
+#include <string>
+#include <system_error>
+#include <utility>
+#include <iomanip> // for quoted
+#include <string_view>
+#include <version>
+
+#include <__debug>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#ifndef _LIBCPP_CXX03_LANG
+
+namespace android::hardware::automotive::filesystem {
+using namespace std;
+using namespace std::chrono;
+
+using std::basic_string;
+using std::enable_if;
+using std::error_code;
+using std::false_type;
+
+#ifndef _VSTD
+#define _LIBAUTO_UNDEF_VSTD
+#define _VSTD std
+#endif
+
+#ifdef _VSTD_FS
+#pragma push_macro("_VSTD_FS")
+#else
+#define _LIBAUTO_UNDEF_VSTD_FS
+#endif
+#define _VSTD_FS android::hardware::automotive::filesystem
+
+/* Begin copy of _FilesystemClock from include/chrono */
+struct _FilesystemClock {
+#if !defined(_LIBCPP_HAS_NO_INT128)
+  typedef __int128_t rep;
+  typedef nano period;
+#else
+  typedef long long rep;
+  typedef nano period;
+#endif
+
+  typedef chrono::duration<rep, period> duration;
+  typedef chrono::time_point<_FilesystemClock> time_point;
+
+  static _LIBCPP_CONSTEXPR_AFTER_CXX11 const bool is_steady = false;
+
+  _LIBCPP_FUNC_VIS static time_point now() noexcept;
+
+  _LIBCPP_INLINE_VISIBILITY
+  static time_t to_time_t(const time_point& __t) noexcept {
+      typedef chrono::duration<rep> __secs;
+      return time_t(
+          chrono::duration_cast<__secs>(__t.time_since_epoch()).count());
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  static time_point from_time_t(time_t __t) noexcept {
+      typedef chrono::duration<rep> __secs;
+      return time_point(__secs(__t));
+  }
+};
+/* End copy of _FilesystemClock from include/chrono */
+
+typedef chrono::time_point<_FilesystemClock> file_time_type;
+
+struct _LIBCPP_TYPE_VIS space_info {
+  uintmax_t capacity;
+  uintmax_t free;
+  uintmax_t available;
+};
+
+enum class _LIBCPP_ENUM_VIS file_type : signed char {
+  none = 0,
+  not_found = -1,
+  regular = 1,
+  directory = 2,
+  symlink = 3,
+  block = 4,
+  character = 5,
+  fifo = 6,
+  socket = 7,
+  unknown = 8
+};
+
+enum class _LIBCPP_ENUM_VIS perms : unsigned {
+  none = 0,
+
+  owner_read = 0400,
+  owner_write = 0200,
+  owner_exec = 0100,
+  owner_all = 0700,
+
+  group_read = 040,
+  group_write = 020,
+  group_exec = 010,
+  group_all = 070,
+
+  others_read = 04,
+  others_write = 02,
+  others_exec = 01,
+  others_all = 07,
+
+  all = 0777,
+
+  set_uid = 04000,
+  set_gid = 02000,
+  sticky_bit = 01000,
+  mask = 07777,
+  unknown = 0xFFFF,
+};
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr perms operator&(perms _LHS, perms _RHS) {
+  return static_cast<perms>(static_cast<unsigned>(_LHS) &
+                            static_cast<unsigned>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr perms operator|(perms _LHS, perms _RHS) {
+  return static_cast<perms>(static_cast<unsigned>(_LHS) |
+                            static_cast<unsigned>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr perms operator^(perms _LHS, perms _RHS) {
+  return static_cast<perms>(static_cast<unsigned>(_LHS) ^
+                            static_cast<unsigned>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr perms operator~(perms _LHS) {
+  return static_cast<perms>(~static_cast<unsigned>(_LHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline perms& operator&=(perms& _LHS, perms _RHS) { return _LHS = _LHS & _RHS; }
+
+_LIBCPP_INLINE_VISIBILITY
+inline perms& operator|=(perms& _LHS, perms _RHS) { return _LHS = _LHS | _RHS; }
+
+_LIBCPP_INLINE_VISIBILITY
+inline perms& operator^=(perms& _LHS, perms _RHS) { return _LHS = _LHS ^ _RHS; }
+
+enum class _LIBCPP_ENUM_VIS perm_options : unsigned char {
+  replace = 1,
+  add = 2,
+  remove = 4,
+  nofollow = 8
+};
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr perm_options operator&(perm_options _LHS, perm_options _RHS) {
+  return static_cast<perm_options>(static_cast<unsigned>(_LHS) &
+                                   static_cast<unsigned>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr perm_options operator|(perm_options _LHS, perm_options _RHS) {
+  return static_cast<perm_options>(static_cast<unsigned>(_LHS) |
+                                   static_cast<unsigned>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr perm_options operator^(perm_options _LHS, perm_options _RHS) {
+  return static_cast<perm_options>(static_cast<unsigned>(_LHS) ^
+                                   static_cast<unsigned>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr perm_options operator~(perm_options _LHS) {
+  return static_cast<perm_options>(~static_cast<unsigned>(_LHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline perm_options& operator&=(perm_options& _LHS, perm_options _RHS) {
+  return _LHS = _LHS & _RHS;
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline perm_options& operator|=(perm_options& _LHS, perm_options _RHS) {
+  return _LHS = _LHS | _RHS;
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline perm_options& operator^=(perm_options& _LHS, perm_options _RHS) {
+  return _LHS = _LHS ^ _RHS;
+}
+
+enum class _LIBCPP_ENUM_VIS copy_options : unsigned short {
+  none = 0,
+  skip_existing = 1,
+  overwrite_existing = 2,
+  update_existing = 4,
+  recursive = 8,
+  copy_symlinks = 16,
+  skip_symlinks = 32,
+  directories_only = 64,
+  create_symlinks = 128,
+  create_hard_links = 256,
+  __in_recursive_copy = 512,
+};
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr copy_options operator&(copy_options _LHS, copy_options _RHS) {
+  return static_cast<copy_options>(static_cast<unsigned short>(_LHS) &
+                                   static_cast<unsigned short>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr copy_options operator|(copy_options _LHS, copy_options _RHS) {
+  return static_cast<copy_options>(static_cast<unsigned short>(_LHS) |
+                                   static_cast<unsigned short>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr copy_options operator^(copy_options _LHS, copy_options _RHS) {
+  return static_cast<copy_options>(static_cast<unsigned short>(_LHS) ^
+                                   static_cast<unsigned short>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr copy_options operator~(copy_options _LHS) {
+  return static_cast<copy_options>(~static_cast<unsigned short>(_LHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline copy_options& operator&=(copy_options& _LHS, copy_options _RHS) {
+  return _LHS = _LHS & _RHS;
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline copy_options& operator|=(copy_options& _LHS, copy_options _RHS) {
+  return _LHS = _LHS | _RHS;
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline copy_options& operator^=(copy_options& _LHS, copy_options _RHS) {
+  return _LHS = _LHS ^ _RHS;
+}
+
+enum class _LIBCPP_ENUM_VIS directory_options : unsigned char {
+  none = 0,
+  follow_directory_symlink = 1,
+  skip_permission_denied = 2
+};
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr directory_options operator&(directory_options _LHS,
+                                             directory_options _RHS) {
+  return static_cast<directory_options>(static_cast<unsigned char>(_LHS) &
+                                        static_cast<unsigned char>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr directory_options operator|(directory_options _LHS,
+                                             directory_options _RHS) {
+  return static_cast<directory_options>(static_cast<unsigned char>(_LHS) |
+                                        static_cast<unsigned char>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr directory_options operator^(directory_options _LHS,
+                                             directory_options _RHS) {
+  return static_cast<directory_options>(static_cast<unsigned char>(_LHS) ^
+                                        static_cast<unsigned char>(_RHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline constexpr directory_options operator~(directory_options _LHS) {
+  return static_cast<directory_options>(~static_cast<unsigned char>(_LHS));
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline directory_options& operator&=(directory_options& _LHS,
+                                     directory_options _RHS) {
+  return _LHS = _LHS & _RHS;
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline directory_options& operator|=(directory_options& _LHS,
+                                     directory_options _RHS) {
+  return _LHS = _LHS | _RHS;
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline directory_options& operator^=(directory_options& _LHS,
+                                     directory_options _RHS) {
+  return _LHS = _LHS ^ _RHS;
+}
+
+class _LIBCPP_TYPE_VIS file_status {
+public:
+  // constructors
+  _LIBCPP_INLINE_VISIBILITY
+  file_status() noexcept : file_status(file_type::none) {}
+  _LIBCPP_INLINE_VISIBILITY
+  explicit file_status(file_type __ft, perms __prms = perms::unknown) noexcept
+      : __ft_(__ft),
+        __prms_(__prms) {}
+
+  file_status(const file_status&) noexcept = default;
+  file_status(file_status&&) noexcept = default;
+
+  _LIBCPP_INLINE_VISIBILITY
+  ~file_status() {}
+
+  file_status& operator=(const file_status&) noexcept = default;
+  file_status& operator=(file_status&&) noexcept = default;
+
+  // observers
+  _LIBCPP_INLINE_VISIBILITY
+  file_type type() const noexcept { return __ft_; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  perms permissions() const noexcept { return __prms_; }
+
+  // modifiers
+  _LIBCPP_INLINE_VISIBILITY
+  void type(file_type __ft) noexcept { __ft_ = __ft; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void permissions(perms __p) noexcept { __prms_ = __p; }
+
+private:
+  file_type __ft_;
+  perms __prms_;
+};
+
+class _LIBCPP_TYPE_VIS directory_entry;
+
+template <class _Tp>
+struct __can_convert_char {
+  static const bool value = false;
+};
+template <class _Tp>
+struct __can_convert_char<const _Tp> : public __can_convert_char<_Tp> {};
+template <>
+struct __can_convert_char<char> {
+  static const bool value = true;
+  using __char_type = char;
+};
+template <>
+struct __can_convert_char<wchar_t> {
+  static const bool value = true;
+  using __char_type = wchar_t;
+};
+template <>
+struct __can_convert_char<char16_t> {
+  static const bool value = true;
+  using __char_type = char16_t;
+};
+template <>
+struct __can_convert_char<char32_t> {
+  static const bool value = true;
+  using __char_type = char32_t;
+};
+
+template <class _ECharT>
+typename enable_if<__can_convert_char<_ECharT>::value, bool>::type
+__is_separator(_ECharT __e) {
+  return __e == _ECharT('/');
+}
+
+struct _NullSentinal {};
+
+template <class _Tp>
+using _Void = void;
+
+template <class _Tp, class = void>
+struct __is_pathable_string : public false_type {};
+
+template <class _ECharT, class _Traits, class _Alloc>
+struct __is_pathable_string<
+    basic_string<_ECharT, _Traits, _Alloc>,
+    _Void<typename __can_convert_char<_ECharT>::__char_type> >
+    : public __can_convert_char<_ECharT> {
+  using _Str = basic_string<_ECharT, _Traits, _Alloc>;
+  using _Base = __can_convert_char<_ECharT>;
+  static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); }
+  static _ECharT const* __range_end(_Str const& __s) {
+    return __s.data() + __s.length();
+  }
+  static _ECharT __first_or_null(_Str const& __s) {
+    return __s.empty() ? _ECharT{} : __s[0];
+  }
+};
+
+template <class _ECharT, class _Traits>
+struct __is_pathable_string<
+    basic_string_view<_ECharT, _Traits>,
+    _Void<typename __can_convert_char<_ECharT>::__char_type> >
+    : public __can_convert_char<_ECharT> {
+  using _Str = basic_string_view<_ECharT, _Traits>;
+  using _Base = __can_convert_char<_ECharT>;
+  static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); }
+  static _ECharT const* __range_end(_Str const& __s) {
+    return __s.data() + __s.length();
+  }
+  static _ECharT __first_or_null(_Str const& __s) {
+    return __s.empty() ? _ECharT{} : __s[0];
+  }
+};
+
+template <class _Source, class _DS = typename decay<_Source>::type,
+          class _UnqualPtrType =
+              typename remove_const<typename remove_pointer<_DS>::type>::type,
+          bool _IsCharPtr = is_pointer<_DS>::value&&
+              __can_convert_char<_UnqualPtrType>::value>
+struct __is_pathable_char_array : false_type {};
+
+template <class _Source, class _ECharT, class _UPtr>
+struct __is_pathable_char_array<_Source, _ECharT*, _UPtr, true>
+    : __can_convert_char<typename remove_const<_ECharT>::type> {
+  using _Base = __can_convert_char<typename remove_const<_ECharT>::type>;
+
+  static _ECharT const* __range_begin(const _ECharT* __b) { return __b; }
+  static _ECharT const* __range_end(const _ECharT* __b) {
+    using _Iter = const _ECharT*;
+    const _ECharT __sentinal = _ECharT{};
+    _Iter __e = __b;
+    for (; *__e != __sentinal; ++__e)
+      ;
+    return __e;
+  }
+
+  static _ECharT __first_or_null(const _ECharT* __b) { return *__b; }
+};
+
+template <class _Iter, bool _IsIt = __is_input_iterator<_Iter>::value,
+          class = void>
+struct __is_pathable_iter : false_type {};
+
+template <class _Iter>
+struct __is_pathable_iter<
+    _Iter, true,
+    _Void<typename __can_convert_char<
+        typename iterator_traits<_Iter>::value_type>::__char_type> >
+    : __can_convert_char<typename iterator_traits<_Iter>::value_type> {
+  using _ECharT = typename iterator_traits<_Iter>::value_type;
+  using _Base = __can_convert_char<_ECharT>;
+
+  static _Iter __range_begin(_Iter __b) { return __b; }
+  static _NullSentinal __range_end(_Iter) { return _NullSentinal{}; }
+
+  static _ECharT __first_or_null(_Iter __b) { return *__b; }
+};
+
+template <class _Tp, bool _IsStringT = __is_pathable_string<_Tp>::value,
+          bool _IsCharIterT = __is_pathable_char_array<_Tp>::value,
+          bool _IsIterT = !_IsCharIterT && __is_pathable_iter<_Tp>::value>
+struct __is_pathable : false_type {
+  static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false");
+};
+
+template <class _Tp>
+struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {};
+
+template <class _Tp>
+struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> {
+};
+
+template <class _Tp>
+struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {};
+
+template <class _ECharT>
+struct _PathCVT {
+  static_assert(__can_convert_char<_ECharT>::value,
+                "Char type not convertible");
+
+  typedef __narrow_to_utf8<sizeof(_ECharT) * __CHAR_BIT__> _Narrower;
+
+  static void __append_range(string& __dest, _ECharT const* __b,
+                             _ECharT const* __e) {
+    _Narrower()(back_inserter(__dest), __b, __e);
+  }
+
+  template <class _Iter>
+  static void __append_range(string& __dest, _Iter __b, _Iter __e) {
+    static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");
+    if (__b == __e)
+      return;
+    basic_string<_ECharT> __tmp(__b, __e);
+    _Narrower()(back_inserter(__dest), __tmp.data(),
+                __tmp.data() + __tmp.length());
+  }
+
+  template <class _Iter>
+  static void __append_range(string& __dest, _Iter __b, _NullSentinal) {
+    static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");
+    const _ECharT __sentinal = _ECharT{};
+    if (*__b == __sentinal)
+      return;
+    basic_string<_ECharT> __tmp;
+    for (; *__b != __sentinal; ++__b)
+      __tmp.push_back(*__b);
+    _Narrower()(back_inserter(__dest), __tmp.data(),
+                __tmp.data() + __tmp.length());
+  }
+
+  template <class _Source>
+  static void __append_source(string& __dest, _Source const& __s) {
+    using _Traits = __is_pathable<_Source>;
+    __append_range(__dest, _Traits::__range_begin(__s),
+                   _Traits::__range_end(__s));
+  }
+};
+
+template <>
+struct _PathCVT<char> {
+
+  template <class _Iter>
+  static typename enable_if<__is_exactly_input_iterator<_Iter>::value>::type
+  __append_range(string& __dest, _Iter __b, _Iter __e) {
+    for (; __b != __e; ++__b)
+      __dest.push_back(*__b);
+  }
+
+  template <class _Iter>
+  static typename enable_if<__is_forward_iterator<_Iter>::value>::type
+  __append_range(string& __dest, _Iter __b, _Iter __e) {
+    __dest.__append_forward_unsafe(__b, __e);
+  }
+
+  template <class _Iter>
+  static void __append_range(string& __dest, _Iter __b, _NullSentinal) {
+    const char __sentinal = char{};
+    for (; *__b != __sentinal; ++__b)
+      __dest.push_back(*__b);
+  }
+
+  template <class _Source>
+  static void __append_source(string& __dest, _Source const& __s) {
+    using _Traits = __is_pathable<_Source>;
+    __append_range(__dest, _Traits::__range_begin(__s),
+                   _Traits::__range_end(__s));
+  }
+};
+
+class _LIBCPP_TYPE_VIS path {
+  template <class _SourceOrIter, class _Tp = path&>
+  using _EnableIfPathable =
+      typename enable_if<__is_pathable<_SourceOrIter>::value, _Tp>::type;
+
+  template <class _Tp>
+  using _SourceChar = typename __is_pathable<_Tp>::__char_type;
+
+  template <class _Tp>
+  using _SourceCVT = _PathCVT<_SourceChar<_Tp> >;
+
+public:
+  typedef char value_type;
+  typedef basic_string<value_type> string_type;
+  typedef _VSTD::string_view __string_view;
+  static constexpr value_type preferred_separator = '/';
+
+  enum class _LIBCPP_ENUM_VIS format : unsigned char {
+    auto_format,
+    native_format,
+    generic_format
+  };
+
+  // constructors and destructor
+  _LIBCPP_INLINE_VISIBILITY path() noexcept {}
+  _LIBCPP_INLINE_VISIBILITY path(const path& __p) : __pn_(__p.__pn_) {}
+  _LIBCPP_INLINE_VISIBILITY path(path&& __p) noexcept
+      : __pn_(_VSTD::move(__p.__pn_)) {}
+
+  _LIBCPP_INLINE_VISIBILITY
+  path(string_type&& __s, format = format::auto_format) noexcept
+      : __pn_(_VSTD::move(__s)) {}
+
+  template <class _Source, class = _EnableIfPathable<_Source, void> >
+  path(const _Source& __src, format = format::auto_format) {
+    _SourceCVT<_Source>::__append_source(__pn_, __src);
+  }
+
+  template <class _InputIt>
+  path(_InputIt __first, _InputIt __last, format = format::auto_format) {
+    typedef typename iterator_traits<_InputIt>::value_type _ItVal;
+    _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
+  }
+
+  // TODO Implement locale conversions.
+  template <class _Source, class = _EnableIfPathable<_Source, void> >
+  path(const _Source& __src, const locale& __loc, format = format::auto_format);
+  template <class _InputIt>
+  path(_InputIt __first, _InputIt _last, const locale& __loc,
+       format = format::auto_format);
+
+  _LIBCPP_INLINE_VISIBILITY
+  ~path() = default;
+
+  // assignments
+  _LIBCPP_INLINE_VISIBILITY
+  path& operator=(const path& __p) {
+    __pn_ = __p.__pn_;
+    return *this;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  path& operator=(path&& __p) noexcept {
+    __pn_ = _VSTD::move(__p.__pn_);
+    return *this;
+  }
+
+  template <class = void>
+  _LIBCPP_INLINE_VISIBILITY path& operator=(string_type&& __s) noexcept {
+    __pn_ = _VSTD::move(__s);
+    return *this;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  path& assign(string_type&& __s) noexcept {
+    __pn_ = _VSTD::move(__s);
+    return *this;
+  }
+
+  template <class _Source>
+  _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source>
+  operator=(const _Source& __src) {
+    return this->assign(__src);
+  }
+
+  template <class _Source>
+  _EnableIfPathable<_Source> assign(const _Source& __src) {
+    __pn_.clear();
+    _SourceCVT<_Source>::__append_source(__pn_, __src);
+    return *this;
+  }
+
+  template <class _InputIt>
+  path& assign(_InputIt __first, _InputIt __last) {
+    typedef typename iterator_traits<_InputIt>::value_type _ItVal;
+    __pn_.clear();
+    _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
+    return *this;
+  }
+
+private:
+  template <class _ECharT>
+  static bool __source_is_absolute(_ECharT __first_or_null) {
+    return __is_separator(__first_or_null);
+  }
+
+public:
+  // appends
+  path& operator/=(const path& __p) {
+    if (__p.is_absolute()) {
+      __pn_ = __p.__pn_;
+      return *this;
+    }
+    if (has_filename())
+      __pn_ += preferred_separator;
+    __pn_ += __p.native();
+    return *this;
+  }
+
+  // FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src
+  // is known at compile time to be "/' since the user almost certainly intended
+  // to append a separator instead of overwriting the path with "/"
+  template <class _Source>
+  _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source>
+  operator/=(const _Source& __src) {
+    return this->append(__src);
+  }
+
+  template <class _Source>
+  _EnableIfPathable<_Source> append(const _Source& __src) {
+    using _Traits = __is_pathable<_Source>;
+    using _CVT = _PathCVT<_SourceChar<_Source> >;
+    if (__source_is_absolute(_Traits::__first_or_null(__src)))
+      __pn_.clear();
+    else if (has_filename())
+      __pn_ += preferred_separator;
+    _CVT::__append_source(__pn_, __src);
+    return *this;
+  }
+
+  template <class _InputIt>
+  path& append(_InputIt __first, _InputIt __last) {
+    typedef typename iterator_traits<_InputIt>::value_type _ItVal;
+    static_assert(__can_convert_char<_ItVal>::value, "Must convertible");
+    using _CVT = _PathCVT<_ItVal>;
+    if (__first != __last && __source_is_absolute(*__first))
+      __pn_.clear();
+    else if (has_filename())
+      __pn_ += preferred_separator;
+    _CVT::__append_range(__pn_, __first, __last);
+    return *this;
+  }
+
+  // concatenation
+  _LIBCPP_INLINE_VISIBILITY
+  path& operator+=(const path& __x) {
+    __pn_ += __x.__pn_;
+    return *this;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  path& operator+=(const string_type& __x) {
+    __pn_ += __x;
+    return *this;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  path& operator+=(__string_view __x) {
+    __pn_ += __x;
+    return *this;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  path& operator+=(const value_type* __x) {
+    __pn_ += __x;
+    return *this;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  path& operator+=(value_type __x) {
+    __pn_ += __x;
+    return *this;
+  }
+
+  template <class _ECharT>
+  typename enable_if<__can_convert_char<_ECharT>::value, path&>::type
+  operator+=(_ECharT __x) {
+    basic_string<_ECharT> __tmp;
+    __tmp += __x;
+    _PathCVT<_ECharT>::__append_source(__pn_, __tmp);
+    return *this;
+  }
+
+  template <class _Source>
+  _EnableIfPathable<_Source> operator+=(const _Source& __x) {
+    return this->concat(__x);
+  }
+
+  template <class _Source>
+  _EnableIfPathable<_Source> concat(const _Source& __x) {
+    _SourceCVT<_Source>::__append_source(__pn_, __x);
+    return *this;
+  }
+
+  template <class _InputIt>
+  path& concat(_InputIt __first, _InputIt __last) {
+    typedef typename iterator_traits<_InputIt>::value_type _ItVal;
+    _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
+    return *this;
+  }
+
+  // modifiers
+  _LIBCPP_INLINE_VISIBILITY
+  void clear() noexcept { __pn_.clear(); }
+
+  path& make_preferred() { return *this; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  path& remove_filename() {
+    auto __fname = __filename();
+    if (!__fname.empty())
+      __pn_.erase(__fname.data() - __pn_.data());
+    return *this;
+  }
+
+  path& replace_filename(const path& __replacement) {
+    remove_filename();
+    return (*this /= __replacement);
+  }
+
+  path& replace_extension(const path& __replacement = path());
+
+  _LIBCPP_INLINE_VISIBILITY
+  void swap(path& __rhs) noexcept { __pn_.swap(__rhs.__pn_); }
+
+  // private helper to allow reserving memory in the path
+  _LIBCPP_INLINE_VISIBILITY
+  void __reserve(size_t __s) { __pn_.reserve(__s); }
+
+  // native format observers
+  _LIBCPP_INLINE_VISIBILITY
+  const string_type& native() const noexcept { return __pn_; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  const value_type* c_str() const noexcept { return __pn_.c_str(); }
+
+  _LIBCPP_INLINE_VISIBILITY operator string_type() const { return __pn_; }
+
+  template <class _ECharT, class _Traits = char_traits<_ECharT>,
+            class _Allocator = allocator<_ECharT> >
+  basic_string<_ECharT, _Traits, _Allocator>
+  string(const _Allocator& __a = _Allocator()) const {
+    using _CVT = __widen_from_utf8<sizeof(_ECharT) * __CHAR_BIT__>;
+    using _Str = basic_string<_ECharT, _Traits, _Allocator>;
+    _Str __s(__a);
+    __s.reserve(__pn_.size());
+    _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size());
+    return __s;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY std::string string() const { return __pn_; }
+  _LIBCPP_INLINE_VISIBILITY std::wstring wstring() const {
+    return string<wchar_t>();
+  }
+  _LIBCPP_INLINE_VISIBILITY std::string u8string() const { return __pn_; }
+  _LIBCPP_INLINE_VISIBILITY std::u16string u16string() const {
+    return string<char16_t>();
+  }
+  _LIBCPP_INLINE_VISIBILITY std::u32string u32string() const {
+    return string<char32_t>();
+  }
+
+  // generic format observers
+  template <class _ECharT, class _Traits = char_traits<_ECharT>,
+            class _Allocator = allocator<_ECharT> >
+  basic_string<_ECharT, _Traits, _Allocator>
+  generic_string(const _Allocator& __a = _Allocator()) const {
+    return string<_ECharT, _Traits, _Allocator>(__a);
+  }
+
+  std::string generic_string() const { return __pn_; }
+  std::wstring generic_wstring() const { return string<wchar_t>(); }
+  std::string generic_u8string() const { return __pn_; }
+  std::u16string generic_u16string() const { return string<char16_t>(); }
+  std::u32string generic_u32string() const { return string<char32_t>(); }
+
+private:
+  int __compare(__string_view) const;
+  __string_view __root_name() const;
+  __string_view __root_directory() const;
+  __string_view __root_path_raw() const;
+  __string_view __relative_path() const;
+  __string_view __parent_path() const;
+  __string_view __filename() const;
+  __string_view __stem() const;
+  __string_view __extension() const;
+
+public:
+  // compare
+  _LIBCPP_INLINE_VISIBILITY int compare(const path& __p) const noexcept {
+    return __compare(__p.__pn_);
+  }
+  _LIBCPP_INLINE_VISIBILITY int compare(const string_type& __s) const {
+    return __compare(__s);
+  }
+  _LIBCPP_INLINE_VISIBILITY int compare(__string_view __s) const {
+    return __compare(__s);
+  }
+  _LIBCPP_INLINE_VISIBILITY int compare(const value_type* __s) const {
+    return __compare(__s);
+  }
+
+  // decomposition
+  _LIBCPP_INLINE_VISIBILITY path root_name() const {
+    return string_type(__root_name());
+  }
+  _LIBCPP_INLINE_VISIBILITY path root_directory() const {
+    return string_type(__root_directory());
+  }
+  _LIBCPP_INLINE_VISIBILITY path root_path() const {
+    return root_name().append(string_type(__root_directory()));
+  }
+  _LIBCPP_INLINE_VISIBILITY path relative_path() const {
+    return string_type(__relative_path());
+  }
+  _LIBCPP_INLINE_VISIBILITY path parent_path() const {
+    return string_type(__parent_path());
+  }
+  _LIBCPP_INLINE_VISIBILITY path filename() const {
+    return string_type(__filename());
+  }
+  _LIBCPP_INLINE_VISIBILITY path stem() const { return string_type(__stem()); }
+  _LIBCPP_INLINE_VISIBILITY path extension() const {
+    return string_type(__extension());
+  }
+
+  // query
+  _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY bool
+  empty() const noexcept {
+    return __pn_.empty();
+  }
+
+  _LIBCPP_INLINE_VISIBILITY bool has_root_name() const {
+    return !__root_name().empty();
+  }
+  _LIBCPP_INLINE_VISIBILITY bool has_root_directory() const {
+    return !__root_directory().empty();
+  }
+  _LIBCPP_INLINE_VISIBILITY bool has_root_path() const {
+    return !__root_path_raw().empty();
+  }
+  _LIBCPP_INLINE_VISIBILITY bool has_relative_path() const {
+    return !__relative_path().empty();
+  }
+  _LIBCPP_INLINE_VISIBILITY bool has_parent_path() const {
+    return !__parent_path().empty();
+  }
+  _LIBCPP_INLINE_VISIBILITY bool has_filename() const {
+    return !__filename().empty();
+  }
+  _LIBCPP_INLINE_VISIBILITY bool has_stem() const { return !__stem().empty(); }
+  _LIBCPP_INLINE_VISIBILITY bool has_extension() const {
+    return !__extension().empty();
+  }
+
+  _LIBCPP_INLINE_VISIBILITY bool is_absolute() const {
+    return has_root_directory();
+  }
+  _LIBCPP_INLINE_VISIBILITY bool is_relative() const { return !is_absolute(); }
+
+  // relative paths
+  path lexically_normal() const;
+  path lexically_relative(const path& __base) const;
+
+  _LIBCPP_INLINE_VISIBILITY path lexically_proximate(const path& __base) const {
+    path __result = this->lexically_relative(__base);
+    if (__result.native().empty())
+      return *this;
+    return __result;
+  }
+
+  // iterators
+  class _LIBCPP_TYPE_VIS iterator;
+  typedef iterator const_iterator;
+
+  iterator begin() const;
+  iterator end() const;
+
+  template <class _CharT, class _Traits>
+  _LIBCPP_INLINE_VISIBILITY friend
+      typename enable_if<is_same<_CharT, char>::value &&
+                             is_same<_Traits, char_traits<char> >::value,
+                         basic_ostream<_CharT, _Traits>&>::type
+      operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
+    __os << std::__quoted(__p.native());
+    return __os;
+  }
+
+  template <class _CharT, class _Traits>
+  _LIBCPP_INLINE_VISIBILITY friend
+      typename enable_if<!is_same<_CharT, char>::value ||
+                             !is_same<_Traits, char_traits<char> >::value,
+                         basic_ostream<_CharT, _Traits>&>::type
+      operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
+    __os << std::__quoted(__p.string<_CharT, _Traits>());
+    return __os;
+  }
+
+  template <class _CharT, class _Traits>
+  _LIBCPP_INLINE_VISIBILITY friend basic_istream<_CharT, _Traits>&
+  operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) {
+    basic_string<_CharT, _Traits> __tmp;
+    __is >> __quoted(__tmp);
+    __p = __tmp;
+    return __is;
+  }
+
+  friend _LIBCPP_INLINE_VISIBILITY bool operator==(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.compare(__rhs) == 0;
+  }
+  friend _LIBCPP_INLINE_VISIBILITY bool operator!=(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.compare(__rhs) != 0;
+  }
+  friend _LIBCPP_INLINE_VISIBILITY bool operator<(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.compare(__rhs) < 0;
+  }
+  friend _LIBCPP_INLINE_VISIBILITY bool operator<=(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.compare(__rhs) <= 0;
+  }
+  friend _LIBCPP_INLINE_VISIBILITY bool operator>(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.compare(__rhs) > 0;
+  }
+  friend _LIBCPP_INLINE_VISIBILITY bool operator>=(const path& __lhs, const path& __rhs) noexcept {
+    return __lhs.compare(__rhs) >= 0;
+  }
+
+  friend _LIBCPP_INLINE_VISIBILITY path operator/(const path& __lhs,
+                                                  const path& __rhs) {
+    path __result(__lhs);
+    __result /= __rhs;
+    return __result;
+  }
+private:
+  inline _LIBCPP_INLINE_VISIBILITY path&
+  __assign_view(__string_view const& __s) noexcept {
+    __pn_ = string_type(__s);
+    return *this;
+  }
+  string_type __pn_;
+};
+
+inline _LIBCPP_INLINE_VISIBILITY void swap(path& __lhs, path& __rhs) noexcept {
+  __lhs.swap(__rhs);
+}
+
+_LIBCPP_FUNC_VIS
+size_t hash_value(const path& __p) noexcept;
+
+template <class _Source>
+_LIBCPP_INLINE_VISIBILITY
+    typename enable_if<__is_pathable<_Source>::value, path>::type
+    u8path(const _Source& __s) {
+  static_assert(
+      is_same<typename __is_pathable<_Source>::__char_type, char>::value,
+      "u8path(Source const&) requires Source have a character type of type "
+      "'char'");
+  return path(__s);
+}
+
+template <class _InputIt>
+_LIBCPP_INLINE_VISIBILITY
+    typename enable_if<__is_pathable<_InputIt>::value, path>::type
+    u8path(_InputIt __f, _InputIt __l) {
+  static_assert(
+      is_same<typename __is_pathable<_InputIt>::__char_type, char>::value,
+      "u8path(Iter, Iter) requires Iter have a value_type of type 'char'");
+  return path(__f, __l);
+}
+
+class _LIBCPP_TYPE_VIS path::iterator {
+public:
+  enum _ParserState : unsigned char {
+    _Singular,
+    _BeforeBegin,
+    _InRootName,
+    _InRootDir,
+    _InFilenames,
+    _InTrailingSep,
+    _AtEnd
+  };
+
+public:
+  typedef bidirectional_iterator_tag iterator_category;
+
+  typedef path value_type;
+  typedef std::ptrdiff_t difference_type;
+  typedef const path* pointer;
+  typedef const path& reference;
+
+  typedef void
+      __stashing_iterator_tag; // See reverse_iterator and __is_stashing_iterator
+
+public:
+  _LIBCPP_INLINE_VISIBILITY
+  iterator()
+      : __stashed_elem_(), __path_ptr_(nullptr), __entry_(),
+        __state_(_Singular) {}
+
+  iterator(const iterator&) = default;
+  ~iterator() = default;
+
+  iterator& operator=(const iterator&) = default;
+
+  _LIBCPP_INLINE_VISIBILITY
+  reference operator*() const { return __stashed_elem_; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  pointer operator->() const { return &__stashed_elem_; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  iterator& operator++() {
+    _LIBCPP_ASSERT(__state_ != _Singular,
+                   "attempting to increment a singular iterator");
+    _LIBCPP_ASSERT(__state_ != _AtEnd,
+                   "attempting to increment the end iterator");
+    return __increment();
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  iterator operator++(int) {
+    iterator __it(*this);
+    this->operator++();
+    return __it;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  iterator& operator--() {
+    _LIBCPP_ASSERT(__state_ != _Singular,
+                   "attempting to decrement a singular iterator");
+    _LIBCPP_ASSERT(__entry_.data() != __path_ptr_->native().data(),
+                   "attempting to decrement the begin iterator");
+    return __decrement();
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  iterator operator--(int) {
+    iterator __it(*this);
+    this->operator--();
+    return __it;
+  }
+
+private:
+  friend class path;
+
+  inline _LIBCPP_INLINE_VISIBILITY friend bool operator==(const iterator&,
+                                                          const iterator&);
+
+  iterator& __increment();
+  iterator& __decrement();
+
+  path __stashed_elem_;
+  const path* __path_ptr_;
+  path::__string_view __entry_;
+  _ParserState __state_;
+};
+
+inline _LIBCPP_INLINE_VISIBILITY bool operator==(const path::iterator& __lhs,
+                                                 const path::iterator& __rhs) {
+  return __lhs.__path_ptr_ == __rhs.__path_ptr_ &&
+         __lhs.__entry_.data() == __rhs.__entry_.data();
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool operator!=(const path::iterator& __lhs,
+                                                 const path::iterator& __rhs) {
+  return !(__lhs == __rhs);
+}
+
+class _LIBCPP_EXCEPTION_ABI filesystem_error : public system_error {
+public:
+  _LIBCPP_INLINE_VISIBILITY
+  filesystem_error(const string& __what, error_code __ec)
+      : system_error(__ec, __what),
+        __storage_(make_shared<_Storage>(path(), path())) {
+    __create_what(0);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  filesystem_error(const string& __what, const path& __p1, error_code __ec)
+      : system_error(__ec, __what),
+        __storage_(make_shared<_Storage>(__p1, path())) {
+    __create_what(1);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  filesystem_error(const string& __what, const path& __p1, const path& __p2,
+                   error_code __ec)
+      : system_error(__ec, __what),
+        __storage_(make_shared<_Storage>(__p1, __p2)) {
+    __create_what(2);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  const path& path1() const noexcept { return __storage_->__p1_; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  const path& path2() const noexcept { return __storage_->__p2_; }
+
+  ~filesystem_error() override; // key function
+
+  _LIBCPP_INLINE_VISIBILITY
+  const char* what() const noexcept override {
+    return __storage_->__what_.c_str();
+  }
+
+  _LIBCPP_FUNC_VIS
+  void __create_what(int __num_paths);
+
+private:
+  struct _Storage {
+    _LIBCPP_INLINE_VISIBILITY
+    _Storage(const path& __p1, const path& __p2) : __p1_(__p1), __p2_(__p2) {}
+
+    path __p1_;
+    path __p2_;
+    string __what_;
+  };
+  shared_ptr<_Storage> __storage_;
+};
+
+template <class... _Args>
+_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY
+#ifndef _LIBCPP_NO_EXCEPTIONS
+    void
+    __throw_filesystem_error(_Args&&... __args) {
+  throw filesystem_error(std::forward<_Args>(__args)...);
+}
+#else
+    void
+    __throw_filesystem_error(_Args&&...) {
+  _VSTD::abort();
+}
+#endif
+
+// operational functions
+
+_LIBCPP_FUNC_VIS
+path __absolute(const path&, error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+path __canonical(const path&, error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+void __copy(const path& __from, const path& __to, copy_options __opt,
+            error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+bool __copy_file(const path& __from, const path& __to, copy_options __opt,
+                 error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+void __copy_symlink(const path& __existing_symlink, const path& __new_symlink,
+                    error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+bool __create_directories(const path& p, error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+bool __create_directory(const path& p, error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+bool __create_directory(const path& p, const path& attributes,
+                        error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+void __create_directory_symlink(const path& __to, const path& __new_symlink,
+                                error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+void __create_hard_link(const path& __to, const path& __new_hard_link,
+                        error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+void __create_symlink(const path& __to, const path& __new_symlink,
+                      error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+path __current_path(error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+void __current_path(const path&, error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+bool __equivalent(const path&, const path&, error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+uintmax_t __file_size(const path&, error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+uintmax_t __hard_link_count(const path&, error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+bool __fs_is_empty(const path& p, error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+file_time_type __last_write_time(const path& p, error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+void __last_write_time(const path& p, file_time_type new_time,
+                       error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+void __permissions(const path&, perms, perm_options, error_code* = nullptr);
+_LIBCPP_FUNC_VIS
+path __read_symlink(const path& p, error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+bool __remove(const path& p, error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+uintmax_t __remove_all(const path& p, error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+void __rename(const path& from, const path& to, error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+void __resize_file(const path& p, uintmax_t size, error_code* ec = nullptr);
+_LIBCPP_FUNC_VIS
+space_info __space(const path&, error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+file_status __status(const path&, error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+file_status __symlink_status(const path&, error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+path __system_complete(const path&, error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+path __temp_directory_path(error_code* __ec = nullptr);
+_LIBCPP_FUNC_VIS
+path __weakly_canonical(path const& __p, error_code* __ec = nullptr);
+
+inline _LIBCPP_INLINE_VISIBILITY path current_path() {
+  return __current_path();
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path current_path(error_code& __ec) {
+  return __current_path(&__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void current_path(const path& __p) {
+  __current_path(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void current_path(const path& __p,
+                                                   error_code& __ec) noexcept {
+  __current_path(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path absolute(const path& __p) {
+  return __absolute(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path absolute(const path& __p,
+                                               error_code& __ec) {
+  return __absolute(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path canonical(const path& __p) {
+  return __canonical(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path canonical(const path& __p,
+                                                error_code& __ec) {
+  return __canonical(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from,
+                                           const path& __to) {
+  __copy(__from, __to, copy_options::none);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from, const path& __to,
+                                           error_code& __ec) {
+  __copy(__from, __to, copy_options::none, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from, const path& __to,
+                                           copy_options __opt) {
+  __copy(__from, __to, __opt);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from, const path& __to,
+                                           copy_options __opt,
+                                           error_code& __ec) {
+  __copy(__from, __to, __opt, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool copy_file(const path& __from,
+                                                const path& __to) {
+  return __copy_file(__from, __to, copy_options::none);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+copy_file(const path& __from, const path& __to, error_code& __ec) {
+  return __copy_file(__from, __to, copy_options::none, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+copy_file(const path& __from, const path& __to, copy_options __opt) {
+  return __copy_file(__from, __to, __opt);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool copy_file(const path& __from,
+                                                const path& __to,
+                                                copy_options __opt,
+                                                error_code& __ec) {
+  return __copy_file(__from, __to, __opt, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void copy_symlink(const path& __existing,
+                                                   const path& __new) {
+  __copy_symlink(__existing, __new);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void
+copy_symlink(const path& __ext, const path& __new, error_code& __ec) noexcept {
+  __copy_symlink(__ext, __new, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool create_directories(const path& __p) {
+  return __create_directories(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool create_directories(const path& __p,
+                                                         error_code& __ec) {
+  return __create_directories(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool create_directory(const path& __p) {
+  return __create_directory(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+create_directory(const path& __p, error_code& __ec) noexcept {
+  return __create_directory(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool create_directory(const path& __p,
+                                                       const path& __attrs) {
+  return __create_directory(__p, __attrs);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+create_directory(const path& __p, const path& __attrs,
+                 error_code& __ec) noexcept {
+  return __create_directory(__p, __attrs, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void
+create_directory_symlink(const path& __to, const path& __new) {
+  __create_directory_symlink(__to, __new);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void
+create_directory_symlink(const path& __to, const path& __new,
+                         error_code& __ec) noexcept {
+  __create_directory_symlink(__to, __new, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void create_hard_link(const path& __to,
+                                                       const path& __new) {
+  __create_hard_link(__to, __new);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void
+create_hard_link(const path& __to, const path& __new,
+                 error_code& __ec) noexcept {
+  __create_hard_link(__to, __new, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void create_symlink(const path& __to,
+                                                     const path& __new) {
+  __create_symlink(__to, __new);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void
+create_symlink(const path& __to, const path& __new, error_code& __ec) noexcept {
+  return __create_symlink(__to, __new, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool status_known(file_status __s) noexcept {
+  return __s.type() != file_type::none;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool exists(file_status __s) noexcept {
+  return status_known(__s) && __s.type() != file_type::not_found;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool exists(const path& __p) {
+  return exists(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool exists(const path& __p,
+                                             error_code& __ec) noexcept {
+  auto __s = __status(__p, &__ec);
+  if (status_known(__s))
+    __ec.clear();
+  return exists(__s);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool equivalent(const path& __p1,
+                                                 const path& __p2) {
+  return __equivalent(__p1, __p2);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept {
+  return __equivalent(__p1, __p2, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY uintmax_t file_size(const path& __p) {
+  return __file_size(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY uintmax_t
+file_size(const path& __p, error_code& __ec) noexcept {
+  return __file_size(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY uintmax_t hard_link_count(const path& __p) {
+  return __hard_link_count(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY uintmax_t
+hard_link_count(const path& __p, error_code& __ec) noexcept {
+  return __hard_link_count(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(file_status __s) noexcept {
+  return __s.type() == file_type::block;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(const path& __p) {
+  return is_block_file(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(const path& __p,
+                                                    error_code& __ec) noexcept {
+  return is_block_file(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+is_character_file(file_status __s) noexcept {
+  return __s.type() == file_type::character;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_character_file(const path& __p) {
+  return is_character_file(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+is_character_file(const path& __p, error_code& __ec) noexcept {
+  return is_character_file(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_directory(file_status __s) noexcept {
+  return __s.type() == file_type::directory;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_directory(const path& __p) {
+  return is_directory(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_directory(const path& __p,
+                                                   error_code& __ec) noexcept {
+  return is_directory(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_empty(const path& __p) {
+  return __fs_is_empty(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_empty(const path& __p,
+                                               error_code& __ec) {
+  return __fs_is_empty(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(file_status __s) noexcept {
+  return __s.type() == file_type::fifo;
+}
+inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(const path& __p) {
+  return is_fifo(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(const path& __p,
+                                              error_code& __ec) noexcept {
+  return is_fifo(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+is_regular_file(file_status __s) noexcept {
+  return __s.type() == file_type::regular;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_regular_file(const path& __p) {
+  return is_regular_file(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+is_regular_file(const path& __p, error_code& __ec) noexcept {
+  return is_regular_file(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_socket(file_status __s) noexcept {
+  return __s.type() == file_type::socket;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_socket(const path& __p) {
+  return is_socket(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_socket(const path& __p,
+                                                error_code& __ec) noexcept {
+  return is_socket(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(file_status __s) noexcept {
+  return __s.type() == file_type::symlink;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(const path& __p) {
+  return is_symlink(__symlink_status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(const path& __p,
+                                                 error_code& __ec) noexcept {
+  return is_symlink(__symlink_status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_other(file_status __s) noexcept {
+  return exists(__s) && !is_regular_file(__s) && !is_directory(__s) &&
+         !is_symlink(__s);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_other(const path& __p) {
+  return is_other(__status(__p));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool is_other(const path& __p,
+                                               error_code& __ec) noexcept {
+  return is_other(__status(__p, &__ec));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY file_time_type
+last_write_time(const path& __p) {
+  return __last_write_time(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY file_time_type
+last_write_time(const path& __p, error_code& __ec) noexcept {
+  return __last_write_time(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void last_write_time(const path& __p,
+                                                      file_time_type __t) {
+  __last_write_time(__p, __t);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void
+last_write_time(const path& __p, file_time_type __t,
+                error_code& __ec) noexcept {
+  __last_write_time(__p, __t, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void
+permissions(const path& __p, perms __prms,
+            perm_options __opts = perm_options::replace) {
+  __permissions(__p, __prms, __opts);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void permissions(const path& __p, perms __prms,
+                                                  error_code& __ec) noexcept {
+  __permissions(__p, __prms, perm_options::replace, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void permissions(const path& __p, perms __prms,
+                                                  perm_options __opts,
+                                                  error_code& __ec) {
+  __permissions(__p, __prms, __opts, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path proximate(const path& __p,
+                                                const path& __base,
+                                                error_code& __ec) {
+  path __tmp = __weakly_canonical(__p, &__ec);
+  if (__ec)
+    return {};
+  path __tmp_base = __weakly_canonical(__base, &__ec);
+  if (__ec)
+    return {};
+  return __tmp.lexically_proximate(__tmp_base);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path proximate(const path& __p,
+                                                error_code& __ec) {
+  return proximate(__p, current_path(), __ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path
+proximate(const path& __p, const path& __base = current_path()) {
+  return __weakly_canonical(__p).lexically_proximate(
+      __weakly_canonical(__base));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path read_symlink(const path& __p) {
+  return __read_symlink(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path read_symlink(const path& __p,
+                                                   error_code& __ec) {
+  return __read_symlink(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path relative(const path& __p,
+                                               const path& __base,
+                                               error_code& __ec) {
+  path __tmp = __weakly_canonical(__p, &__ec);
+  if (__ec)
+    return path();
+  path __tmpbase = __weakly_canonical(__base, &__ec);
+  if (__ec)
+    return path();
+  return __tmp.lexically_relative(__tmpbase);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path relative(const path& __p,
+                                               error_code& __ec) {
+  return relative(__p, current_path(), __ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path
+relative(const path& __p, const path& __base = current_path()) {
+  return __weakly_canonical(__p).lexically_relative(__weakly_canonical(__base));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool remove(const path& __p) {
+  return __remove(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool remove(const path& __p,
+                                             error_code& __ec) noexcept {
+  return __remove(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY uintmax_t remove_all(const path& __p) {
+  return __remove_all(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY uintmax_t remove_all(const path& __p,
+                                                      error_code& __ec) {
+  return __remove_all(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void rename(const path& __from,
+                                             const path& __to) {
+  return __rename(__from, __to);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void
+rename(const path& __from, const path& __to, error_code& __ec) noexcept {
+  return __rename(__from, __to, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void resize_file(const path& __p,
+                                                  uintmax_t __ns) {
+  return __resize_file(__p, __ns);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void
+resize_file(const path& __p, uintmax_t __ns, error_code& __ec) noexcept {
+  return __resize_file(__p, __ns, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY space_info space(const path& __p) {
+  return __space(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY space_info space(const path& __p,
+                                                  error_code& __ec) noexcept {
+  return __space(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY file_status status(const path& __p) {
+  return __status(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY file_status status(const path& __p,
+                                                    error_code& __ec) noexcept {
+  return __status(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY file_status symlink_status(const path& __p) {
+  return __symlink_status(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY file_status
+symlink_status(const path& __p, error_code& __ec) noexcept {
+  return __symlink_status(__p, &__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path temp_directory_path() {
+  return __temp_directory_path();
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path temp_directory_path(error_code& __ec) {
+  return __temp_directory_path(&__ec);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path weakly_canonical(path const& __p) {
+  return __weakly_canonical(__p);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY path weakly_canonical(path const& __p,
+                                                       error_code& __ec) {
+  return __weakly_canonical(__p, &__ec);
+}
+
+class directory_iterator;
+class recursive_directory_iterator;
+class __dir_stream;
+
+class directory_entry {
+  typedef _VSTD_FS::path _Path;
+
+public:
+  // constructors and destructors
+  directory_entry() noexcept = default;
+  directory_entry(directory_entry const&) = default;
+  directory_entry(directory_entry&&) noexcept = default;
+
+  _LIBCPP_INLINE_VISIBILITY
+  explicit directory_entry(_Path const& __p) : __p_(__p) {
+    error_code __ec;
+    __refresh(&__ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  directory_entry(_Path const& __p, error_code& __ec) : __p_(__p) {
+    __refresh(&__ec);
+  }
+
+  ~directory_entry() {}
+
+  directory_entry& operator=(directory_entry const&) = default;
+  directory_entry& operator=(directory_entry&&) noexcept = default;
+
+  _LIBCPP_INLINE_VISIBILITY
+  void assign(_Path const& __p) {
+    __p_ = __p;
+    error_code __ec;
+    __refresh(&__ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void assign(_Path const& __p, error_code& __ec) {
+    __p_ = __p;
+    __refresh(&__ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void replace_filename(_Path const& __p) {
+    __p_.replace_filename(__p);
+    error_code __ec;
+    __refresh(&__ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void replace_filename(_Path const& __p, error_code& __ec) {
+    __p_ = __p_.parent_path() / __p;
+    __refresh(&__ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void refresh() { __refresh(); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void refresh(error_code& __ec) noexcept { __refresh(&__ec); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  _Path const& path() const noexcept { return __p_; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  operator const _Path&() const noexcept { return __p_; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool exists() const { return _VSTD_FS::exists(file_status{__get_ft()}); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool exists(error_code& __ec) const noexcept {
+    return _VSTD_FS::exists(file_status{__get_ft(&__ec)});
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_block_file() const { return __get_ft() == file_type::block; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_block_file(error_code& __ec) const noexcept {
+    return __get_ft(&__ec) == file_type::block;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_character_file() const { return __get_ft() == file_type::character; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_character_file(error_code& __ec) const noexcept {
+    return __get_ft(&__ec) == file_type::character;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_directory() const { return __get_ft() == file_type::directory; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_directory(error_code& __ec) const noexcept {
+    return __get_ft(&__ec) == file_type::directory;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_fifo() const { return __get_ft() == file_type::fifo; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_fifo(error_code& __ec) const noexcept {
+    return __get_ft(&__ec) == file_type::fifo;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_other() const { return _VSTD_FS::is_other(file_status{__get_ft()}); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_other(error_code& __ec) const noexcept {
+    return _VSTD_FS::is_other(file_status{__get_ft(&__ec)});
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_regular_file() const { return __get_ft() == file_type::regular; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_regular_file(error_code& __ec) const noexcept {
+    return __get_ft(&__ec) == file_type::regular;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_socket() const { return __get_ft() == file_type::socket; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_socket(error_code& __ec) const noexcept {
+    return __get_ft(&__ec) == file_type::socket;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_symlink() const { return __get_sym_ft() == file_type::symlink; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool is_symlink(error_code& __ec) const noexcept {
+    return __get_sym_ft(&__ec) == file_type::symlink;
+  }
+  _LIBCPP_INLINE_VISIBILITY
+  uintmax_t file_size() const { return __get_size(); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  uintmax_t file_size(error_code& __ec) const noexcept {
+    return __get_size(&__ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  uintmax_t hard_link_count() const { return __get_nlink(); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  uintmax_t hard_link_count(error_code& __ec) const noexcept {
+    return __get_nlink(&__ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_time_type last_write_time() const { return __get_write_time(); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_time_type last_write_time(error_code& __ec) const noexcept {
+    return __get_write_time(&__ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_status status() const { return __get_status(); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_status status(error_code& __ec) const noexcept {
+    return __get_status(&__ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_status symlink_status() const { return __get_symlink_status(); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_status symlink_status(error_code& __ec) const noexcept {
+    return __get_symlink_status(&__ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool operator<(directory_entry const& __rhs) const noexcept {
+    return __p_ < __rhs.__p_;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool operator==(directory_entry const& __rhs) const noexcept {
+    return __p_ == __rhs.__p_;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool operator!=(directory_entry const& __rhs) const noexcept {
+    return __p_ != __rhs.__p_;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool operator<=(directory_entry const& __rhs) const noexcept {
+    return __p_ <= __rhs.__p_;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool operator>(directory_entry const& __rhs) const noexcept {
+    return __p_ > __rhs.__p_;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool operator>=(directory_entry const& __rhs) const noexcept {
+    return __p_ >= __rhs.__p_;
+  }
+
+private:
+  friend class directory_iterator;
+  friend class recursive_directory_iterator;
+  friend class __dir_stream;
+
+  enum _CacheType : unsigned char {
+    _Empty,
+    _IterSymlink,
+    _IterNonSymlink,
+    _RefreshSymlink,
+    _RefreshSymlinkUnresolved,
+    _RefreshNonSymlink
+  };
+
+  struct __cached_data {
+    uintmax_t __size_;
+    uintmax_t __nlink_;
+    file_time_type __write_time_;
+    perms __sym_perms_;
+    perms __non_sym_perms_;
+    file_type __type_;
+    _CacheType __cache_type_;
+
+    _LIBCPP_INLINE_VISIBILITY
+    __cached_data() noexcept { __reset(); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    void __reset() {
+      __cache_type_ = _Empty;
+      __type_ = file_type::none;
+      __sym_perms_ = __non_sym_perms_ = perms::unknown;
+      __size_ = __nlink_ = uintmax_t(-1);
+      __write_time_ = file_time_type::min();
+    }
+  };
+
+  _LIBCPP_INLINE_VISIBILITY
+  static __cached_data __create_iter_result(file_type __ft) {
+    __cached_data __data;
+    __data.__type_ = __ft;
+    __data.__cache_type_ = [&]() {
+      switch (__ft) {
+      case file_type::none:
+        return _Empty;
+      case file_type::symlink:
+        return _IterSymlink;
+      default:
+        return _IterNonSymlink;
+      }
+    }();
+    return __data;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void __assign_iter_entry(_Path&& __p, __cached_data __dt) {
+    __p_ = std::move(__p);
+    __data_ = __dt;
+  }
+
+  _LIBCPP_FUNC_VIS
+  error_code __do_refresh() noexcept;
+
+  _LIBCPP_INLINE_VISIBILITY
+  static bool __is_dne_error(error_code const& __ec) {
+    if (!__ec)
+      return true;
+    switch (static_cast<errc>(__ec.value())) {
+    case errc::no_such_file_or_directory:
+    case errc::not_a_directory:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void __handle_error(const char* __msg, error_code* __dest_ec,
+                      error_code const& __ec, bool __allow_dne = false) const {
+    if (__dest_ec) {
+      *__dest_ec = __ec;
+      return;
+    }
+    if (__ec && (!__allow_dne || !__is_dne_error(__ec)))
+      __throw_filesystem_error(__msg, __p_, __ec);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void __refresh(error_code* __ec = nullptr) {
+    __handle_error("in directory_entry::refresh", __ec, __do_refresh(),
+                   /*allow_dne*/ true);
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_type __get_sym_ft(error_code* __ec = nullptr) const {
+    switch (__data_.__cache_type_) {
+    case _Empty:
+      return __symlink_status(__p_, __ec).type();
+    case _IterSymlink:
+    case _RefreshSymlink:
+    case _RefreshSymlinkUnresolved:
+      if (__ec)
+        __ec->clear();
+      return file_type::symlink;
+    case _IterNonSymlink:
+    case _RefreshNonSymlink:
+      file_status __st(__data_.__type_);
+      if (__ec && !_VSTD_FS::exists(__st))
+        *__ec = make_error_code(errc::no_such_file_or_directory);
+      else if (__ec)
+        __ec->clear();
+      return __data_.__type_;
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_type __get_ft(error_code* __ec = nullptr) const {
+    switch (__data_.__cache_type_) {
+    case _Empty:
+    case _IterSymlink:
+    case _RefreshSymlinkUnresolved:
+      return __status(__p_, __ec).type();
+    case _IterNonSymlink:
+    case _RefreshNonSymlink:
+    case _RefreshSymlink: {
+      file_status __st(__data_.__type_);
+      if (__ec && !_VSTD_FS::exists(__st))
+        *__ec = make_error_code(errc::no_such_file_or_directory);
+      else if (__ec)
+        __ec->clear();
+      return __data_.__type_;
+    }
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_status __get_status(error_code* __ec = nullptr) const {
+    switch (__data_.__cache_type_) {
+    case _Empty:
+    case _IterNonSymlink:
+    case _IterSymlink:
+    case _RefreshSymlinkUnresolved:
+      return __status(__p_, __ec);
+    case _RefreshNonSymlink:
+    case _RefreshSymlink:
+      return file_status(__get_ft(__ec), __data_.__non_sym_perms_);
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_status __get_symlink_status(error_code* __ec = nullptr) const {
+    switch (__data_.__cache_type_) {
+    case _Empty:
+    case _IterNonSymlink:
+    case _IterSymlink:
+      return __symlink_status(__p_, __ec);
+    case _RefreshNonSymlink:
+      return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_);
+    case _RefreshSymlink:
+    case _RefreshSymlinkUnresolved:
+      return file_status(__get_sym_ft(__ec), __data_.__sym_perms_);
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  uintmax_t __get_size(error_code* __ec = nullptr) const {
+    switch (__data_.__cache_type_) {
+    case _Empty:
+    case _IterNonSymlink:
+    case _IterSymlink:
+    case _RefreshSymlinkUnresolved:
+      return _VSTD_FS::__file_size(__p_, __ec);
+    case _RefreshSymlink:
+    case _RefreshNonSymlink: {
+      error_code __m_ec;
+      file_status __st(__get_ft(&__m_ec));
+      __handle_error("in directory_entry::file_size", __ec, __m_ec);
+      if (_VSTD_FS::exists(__st) && !_VSTD_FS::is_regular_file(__st)) {
+        errc __err_kind = _VSTD_FS::is_directory(__st) ? errc::is_a_directory
+                                                       : errc::not_supported;
+        __handle_error("in directory_entry::file_size", __ec,
+                       make_error_code(__err_kind));
+      }
+      return __data_.__size_;
+    }
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  uintmax_t __get_nlink(error_code* __ec = nullptr) const {
+    switch (__data_.__cache_type_) {
+    case _Empty:
+    case _IterNonSymlink:
+    case _IterSymlink:
+    case _RefreshSymlinkUnresolved:
+      return _VSTD_FS::__hard_link_count(__p_, __ec);
+    case _RefreshSymlink:
+    case _RefreshNonSymlink: {
+      error_code __m_ec;
+      (void)__get_ft(&__m_ec);
+      __handle_error("in directory_entry::hard_link_count", __ec, __m_ec);
+      return __data_.__nlink_;
+    }
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  file_time_type __get_write_time(error_code* __ec = nullptr) const {
+    switch (__data_.__cache_type_) {
+    case _Empty:
+    case _IterNonSymlink:
+    case _IterSymlink:
+    case _RefreshSymlinkUnresolved:
+      return _VSTD_FS::__last_write_time(__p_, __ec);
+    case _RefreshSymlink:
+    case _RefreshNonSymlink: {
+      error_code __m_ec;
+      file_status __st(__get_ft(&__m_ec));
+      __handle_error("in directory_entry::last_write_time", __ec, __m_ec);
+      if (_VSTD_FS::exists(__st) &&
+          __data_.__write_time_ == file_time_type::min())
+        __handle_error("in directory_entry::last_write_time", __ec,
+                       make_error_code(errc::value_too_large));
+      return __data_.__write_time_;
+    }
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+private:
+  _Path __p_;
+  __cached_data __data_;
+};
+
+class __dir_element_proxy {
+public:
+  inline _LIBCPP_INLINE_VISIBILITY directory_entry operator*() {
+    return _VSTD::move(__elem_);
+  }
+
+private:
+  friend class directory_iterator;
+  friend class recursive_directory_iterator;
+  explicit __dir_element_proxy(directory_entry const& __e) : __elem_(__e) {}
+  __dir_element_proxy(__dir_element_proxy&& __o)
+      : __elem_(_VSTD::move(__o.__elem_)) {}
+  directory_entry __elem_;
+};
+
+class directory_iterator {
+public:
+  typedef directory_entry value_type;
+  typedef ptrdiff_t difference_type;
+  typedef value_type const* pointer;
+  typedef value_type const& reference;
+  typedef input_iterator_tag iterator_category;
+
+public:
+  //ctor & dtor
+  directory_iterator() noexcept {}
+
+  explicit directory_iterator(const path& __p)
+      : directory_iterator(__p, nullptr) {}
+
+  directory_iterator(const path& __p, directory_options __opts)
+      : directory_iterator(__p, nullptr, __opts) {}
+
+  directory_iterator(const path& __p, error_code& __ec)
+      : directory_iterator(__p, &__ec) {}
+
+  directory_iterator(const path& __p, directory_options __opts,
+                     error_code& __ec)
+      : directory_iterator(__p, &__ec, __opts) {}
+
+  directory_iterator(const directory_iterator&) = default;
+  directory_iterator(directory_iterator&&) = default;
+  directory_iterator& operator=(const directory_iterator&) = default;
+
+  directory_iterator& operator=(directory_iterator&& __o) noexcept {
+    // non-default implementation provided to support self-move assign.
+    if (this != &__o) {
+      __imp_ = _VSTD::move(__o.__imp_);
+    }
+    return *this;
+  }
+
+  ~directory_iterator() = default;
+
+  const directory_entry& operator*() const {
+    _LIBCPP_ASSERT(__imp_, "The end iterator cannot be dereferenced");
+    return __dereference();
+  }
+
+  const directory_entry* operator->() const { return &**this; }
+
+  directory_iterator& operator++() { return __increment(); }
+
+  __dir_element_proxy operator++(int) {
+    __dir_element_proxy __p(**this);
+    __increment();
+    return __p;
+  }
+
+  directory_iterator& increment(error_code& __ec) { return __increment(&__ec); }
+
+private:
+  inline _LIBCPP_INLINE_VISIBILITY friend bool
+  operator==(const directory_iterator& __lhs,
+             const directory_iterator& __rhs) noexcept;
+
+  // construct the dir_stream
+  _LIBCPP_FUNC_VIS
+  directory_iterator(const path&, error_code*,
+                     directory_options = directory_options::none);
+
+  _LIBCPP_FUNC_VIS
+  directory_iterator& __increment(error_code* __ec = nullptr);
+
+  _LIBCPP_FUNC_VIS
+  const directory_entry& __dereference() const;
+
+private:
+  shared_ptr<__dir_stream> __imp_;
+};
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+operator==(const directory_iterator& __lhs,
+           const directory_iterator& __rhs) noexcept {
+  return __lhs.__imp_ == __rhs.__imp_;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+operator!=(const directory_iterator& __lhs,
+           const directory_iterator& __rhs) noexcept {
+  return !(__lhs == __rhs);
+}
+
+// enable directory_iterator range-based for statements
+inline _LIBCPP_INLINE_VISIBILITY directory_iterator
+begin(directory_iterator __iter) noexcept {
+  return __iter;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY directory_iterator
+end(const directory_iterator&) noexcept {
+  return directory_iterator();
+}
+
+class recursive_directory_iterator {
+public:
+  using value_type = directory_entry;
+  using difference_type = std::ptrdiff_t;
+  using pointer = directory_entry const*;
+  using reference = directory_entry const&;
+  using iterator_category = std::input_iterator_tag;
+
+public:
+  // constructors and destructor
+  _LIBCPP_INLINE_VISIBILITY
+  recursive_directory_iterator() noexcept : __rec_(false) {}
+
+  _LIBCPP_INLINE_VISIBILITY
+  explicit recursive_directory_iterator(
+      const path& __p, directory_options __xoptions = directory_options::none)
+      : recursive_directory_iterator(__p, __xoptions, nullptr) {}
+
+  _LIBCPP_INLINE_VISIBILITY
+  recursive_directory_iterator(const path& __p, directory_options __xoptions,
+                               error_code& __ec)
+      : recursive_directory_iterator(__p, __xoptions, &__ec) {}
+
+  _LIBCPP_INLINE_VISIBILITY
+  recursive_directory_iterator(const path& __p, error_code& __ec)
+      : recursive_directory_iterator(__p, directory_options::none, &__ec) {}
+
+  recursive_directory_iterator(const recursive_directory_iterator&) = default;
+  recursive_directory_iterator(recursive_directory_iterator&&) = default;
+
+  recursive_directory_iterator&
+  operator=(const recursive_directory_iterator&) = default;
+
+  _LIBCPP_INLINE_VISIBILITY
+  recursive_directory_iterator&
+  operator=(recursive_directory_iterator&& __o) noexcept {
+    // non-default implementation provided to support self-move assign.
+    if (this != &__o) {
+      __imp_ = _VSTD::move(__o.__imp_);
+      __rec_ = __o.__rec_;
+    }
+    return *this;
+  }
+
+  ~recursive_directory_iterator() = default;
+
+  _LIBCPP_INLINE_VISIBILITY
+  const directory_entry& operator*() const { return __dereference(); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  const directory_entry* operator->() const { return &__dereference(); }
+
+  recursive_directory_iterator& operator++() { return __increment(); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  __dir_element_proxy operator++(int) {
+    __dir_element_proxy __p(**this);
+    __increment();
+    return __p;
+  }
+
+  _LIBCPP_INLINE_VISIBILITY
+  recursive_directory_iterator& increment(error_code& __ec) {
+    return __increment(&__ec);
+  }
+
+  _LIBCPP_FUNC_VIS directory_options options() const;
+  _LIBCPP_FUNC_VIS int depth() const;
+
+  _LIBCPP_INLINE_VISIBILITY
+  void pop() { __pop(); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void pop(error_code& __ec) { __pop(&__ec); }
+
+  _LIBCPP_INLINE_VISIBILITY
+  bool recursion_pending() const { return __rec_; }
+
+  _LIBCPP_INLINE_VISIBILITY
+  void disable_recursion_pending() { __rec_ = false; }
+
+private:
+  recursive_directory_iterator(const path& __p, directory_options __opt,
+                               error_code* __ec);
+
+  _LIBCPP_FUNC_VIS
+  const directory_entry& __dereference() const;
+
+  _LIBCPP_FUNC_VIS
+  bool __try_recursion(error_code* __ec);
+
+  _LIBCPP_FUNC_VIS
+  void __advance(error_code* __ec = nullptr);
+
+  _LIBCPP_FUNC_VIS
+  recursive_directory_iterator& __increment(error_code* __ec = nullptr);
+
+  _LIBCPP_FUNC_VIS
+  void __pop(error_code* __ec = nullptr);
+
+  inline _LIBCPP_INLINE_VISIBILITY friend bool
+  operator==(const recursive_directory_iterator&,
+             const recursive_directory_iterator&) noexcept;
+
+  struct __shared_imp;
+  shared_ptr<__shared_imp> __imp_;
+  bool __rec_;
+}; // class recursive_directory_iterator
+
+inline _LIBCPP_INLINE_VISIBILITY bool
+operator==(const recursive_directory_iterator& __lhs,
+           const recursive_directory_iterator& __rhs) noexcept {
+  return __lhs.__imp_ == __rhs.__imp_;
+}
+
+_LIBCPP_INLINE_VISIBILITY
+inline bool operator!=(const recursive_directory_iterator& __lhs,
+                       const recursive_directory_iterator& __rhs) noexcept {
+  return !(__lhs == __rhs);
+}
+// enable recursive_directory_iterator range-based for statements
+inline _LIBCPP_INLINE_VISIBILITY recursive_directory_iterator
+begin(recursive_directory_iterator __iter) noexcept {
+  return __iter;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY recursive_directory_iterator
+end(const recursive_directory_iterator&) noexcept {
+  return recursive_directory_iterator();
+}
+
+}  // namespace android::hardware::automotive::filesystem
+#ifdef _LIBAUTO_UNDEF_VSTD
+#undef _VSTD
+#undef _LIBAUTO_UNDEF_VSTD
+#endif
+
+#ifndef _LIBAUTO_UNDEF_VSTD_FS
+#pragma pop_macro("_VSTD_FS")
+#else
+#undef _VSTD
+#undef _LIBAUTO_UNDEF_VSTD_FS
+#endif
+
+#endif // !_LIBCPP_CXX03_LANG
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBAUTO_FILESYSTEM
diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp b/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp
new file mode 100644
index 0000000..624538b
--- /dev/null
+++ b/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp
@@ -0,0 +1,397 @@
+//===------------------ directory_iterator.cpp ----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/* clang-format off */
+#include "automotive/filesystem"
+#include <__config>
+#if defined(_LIBCPP_WIN32API)
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#else
+#include <dirent.h>
+#endif
+#include <errno.h>
+
+#include "filesystem_common.h"
+
+namespace android::hardware::automotive::filesystem {
+
+namespace detail {
+namespace {
+
+#if !defined(_LIBCPP_WIN32API)
+template <class DirEntT, class = decltype(DirEntT::d_type)>
+static file_type get_file_type(DirEntT* ent, int) {
+  switch (ent->d_type) {
+  case DT_BLK:
+    return file_type::block;
+  case DT_CHR:
+    return file_type::character;
+  case DT_DIR:
+    return file_type::directory;
+  case DT_FIFO:
+    return file_type::fifo;
+  case DT_LNK:
+    return file_type::symlink;
+  case DT_REG:
+    return file_type::regular;
+  case DT_SOCK:
+    return file_type::socket;
+  // Unlike in lstat, hitting "unknown" here simply means that the underlying
+  // filesystem doesn't support d_type. Report is as 'none' so we correctly
+  // set the cache to empty.
+  case DT_UNKNOWN:
+    break;
+  }
+  return file_type::none;
+}
+
+template <class DirEntT>
+static file_type get_file_type(DirEntT* ent, long) {
+  return file_type::none;
+}
+
+static pair<string_view, file_type> posix_readdir(DIR* dir_stream,
+                                                  error_code& ec) {
+  struct dirent* dir_entry_ptr = nullptr;
+  errno = 0; // zero errno in order to detect errors
+  ec.clear();
+  if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) {
+    if (errno)
+      ec = capture_errno();
+    return {};
+  } else {
+    return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)};
+  }
+}
+#else
+
+static file_type get_file_type(const WIN32_FIND_DATA& data) {
+  //auto attrs = data.dwFileAttributes;
+  // FIXME(EricWF)
+  return file_type::unknown;
+}
+static uintmax_t get_file_size(const WIN32_FIND_DATA& data) {
+  return (data.nFileSizeHight * (MAXDWORD + 1)) + data.nFileSizeLow;
+}
+static file_time_type get_write_time(const WIN32_FIND_DATA& data) {
+  ULARGE_INTEGER tmp;
+  FILETIME& time = data.ftLastWriteTime;
+  tmp.u.LowPart = time.dwLowDateTime;
+  tmp.u.HighPart = time.dwHighDateTime;
+  return file_time_type(file_time_type::duration(time.QuadPart));
+}
+
+#endif
+
+} // namespace
+} // namespace detail
+
+using detail::ErrorHandler;
+
+#if defined(_LIBCPP_WIN32API)
+class __dir_stream {
+public:
+  __dir_stream() = delete;
+  __dir_stream& operator=(const __dir_stream&) = delete;
+
+  __dir_stream(__dir_stream&& __ds) noexcept : __stream_(__ds.__stream_),
+                                               __root_(move(__ds.__root_)),
+                                               __entry_(move(__ds.__entry_)) {
+    __ds.__stream_ = INVALID_HANDLE_VALUE;
+  }
+
+  __dir_stream(const path& root, directory_options opts, error_code& ec)
+      : __stream_(INVALID_HANDLE_VALUE), __root_(root) {
+    __stream_ = ::FindFirstFileEx(root.c_str(), &__data_);
+    if (__stream_ == INVALID_HANDLE_VALUE) {
+      ec = error_code(::GetLastError(), generic_category());
+      const bool ignore_permission_denied =
+          bool(opts & directory_options::skip_permission_denied);
+      if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED)
+        ec.clear();
+      return;
+    }
+  }
+
+  ~__dir_stream() noexcept {
+    if (__stream_ == INVALID_HANDLE_VALUE)
+      return;
+    close();
+  }
+
+  bool good() const noexcept { return __stream_ != INVALID_HANDLE_VALUE; }
+
+  bool advance(error_code& ec) {
+    while (::FindNextFile(__stream_, &__data_)) {
+      if (!strcmp(__data_.cFileName, ".") || strcmp(__data_.cFileName, ".."))
+        continue;
+      // FIXME: Cache more of this
+      //directory_entry::__cached_data cdata;
+      //cdata.__type_ = get_file_type(__data_);
+      //cdata.__size_ = get_file_size(__data_);
+      //cdata.__write_time_ = get_write_time(__data_);
+      __entry_.__assign_iter_entry(
+          __root_ / __data_.cFileName,
+          directory_entry::__create_iter_result(get_file_type(__data)));
+      return true;
+    }
+    ec = error_code(::GetLastError(), generic_category());
+    close();
+    return false;
+  }
+
+private:
+  error_code close() noexcept {
+    error_code ec;
+    if (!::FindClose(__stream_))
+      ec = error_code(::GetLastError(), generic_category());
+    __stream_ = INVALID_HANDLE_VALUE;
+    return ec;
+  }
+
+  HANDLE __stream_{INVALID_HANDLE_VALUE};
+  WIN32_FIND_DATA __data_;
+
+public:
+  path __root_;
+  directory_entry __entry_;
+};
+#else
+class __dir_stream {
+public:
+  __dir_stream() = delete;
+  __dir_stream& operator=(const __dir_stream&) = delete;
+
+  __dir_stream(__dir_stream&& other) noexcept : __stream_(other.__stream_),
+                                                __root_(move(other.__root_)),
+                                                __entry_(move(other.__entry_)) {
+    other.__stream_ = nullptr;
+  }
+
+  __dir_stream(const path& root, directory_options opts, error_code& ec)
+      : __stream_(nullptr), __root_(root) {
+    if ((__stream_ = ::opendir(root.c_str())) == nullptr) {
+      ec = detail::capture_errno();
+      const bool allow_eacess =
+          bool(opts & directory_options::skip_permission_denied);
+      if (allow_eacess && ec.value() == EACCES)
+        ec.clear();
+      return;
+    }
+    advance(ec);
+  }
+
+  ~__dir_stream() noexcept {
+    if (__stream_)
+      close();
+  }
+
+  bool good() const noexcept { return __stream_ != nullptr; }
+
+  bool advance(error_code& ec) {
+    while (true) {
+      auto str_type_pair = detail::posix_readdir(__stream_, ec);
+      auto& str = str_type_pair.first;
+      if (str == "." || str == "..") {
+        continue;
+      } else if (ec || str.empty()) {
+        close();
+        return false;
+      } else {
+        __entry_.__assign_iter_entry(
+            __root_ / str,
+            directory_entry::__create_iter_result(str_type_pair.second));
+        return true;
+      }
+    }
+  }
+
+private:
+  error_code close() noexcept {
+    error_code m_ec;
+    if (::closedir(__stream_) == -1)
+      m_ec = detail::capture_errno();
+    __stream_ = nullptr;
+    return m_ec;
+  }
+
+  DIR* __stream_{nullptr};
+
+public:
+  path __root_;
+  directory_entry __entry_;
+};
+#endif
+
+// directory_iterator
+
+directory_iterator::directory_iterator(const path& p, error_code* ec,
+                                       directory_options opts) {
+  ErrorHandler<void> err("directory_iterator::directory_iterator(...)", ec, &p);
+
+  error_code m_ec;
+  __imp_ = make_shared<__dir_stream>(p, opts, m_ec);
+  if (ec)
+    *ec = m_ec;
+  if (!__imp_->good()) {
+    __imp_.reset();
+    if (m_ec)
+      err.report(m_ec);
+  }
+}
+
+directory_iterator& directory_iterator::__increment(error_code* ec) {
+  _LIBCPP_ASSERT(__imp_, "Attempting to increment an invalid iterator");
+  ErrorHandler<void> err("directory_iterator::operator++()", ec);
+
+  error_code m_ec;
+  if (!__imp_->advance(m_ec)) {
+    path root = move(__imp_->__root_);
+    __imp_.reset();
+    if (m_ec)
+      err.report(m_ec, "at root \"%s\"", root);
+  }
+  return *this;
+}
+
+directory_entry const& directory_iterator::__dereference() const {
+  _LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator");
+  return __imp_->__entry_;
+}
+
+// recursive_directory_iterator
+
+struct recursive_directory_iterator::__shared_imp {
+  stack<__dir_stream> __stack_;
+  directory_options __options_;
+};
+
+recursive_directory_iterator::recursive_directory_iterator(
+    const path& p, directory_options opt, error_code* ec)
+    : __imp_(nullptr), __rec_(true) {
+  ErrorHandler<void> err("recursive_directory_iterator", ec, &p);
+
+  error_code m_ec;
+  __dir_stream new_s(p, opt, m_ec);
+  if (m_ec)
+    err.report(m_ec);
+  if (m_ec || !new_s.good())
+    return;
+
+  __imp_ = make_shared<__shared_imp>();
+  __imp_->__options_ = opt;
+  __imp_->__stack_.push(move(new_s));
+}
+
+void recursive_directory_iterator::__pop(error_code* ec) {
+  _LIBCPP_ASSERT(__imp_, "Popping the end iterator");
+  if (ec)
+    ec->clear();
+  __imp_->__stack_.pop();
+  if (__imp_->__stack_.size() == 0)
+    __imp_.reset();
+  else
+    __advance(ec);
+}
+
+directory_options recursive_directory_iterator::options() const {
+  return __imp_->__options_;
+}
+
+int recursive_directory_iterator::depth() const {
+  return __imp_->__stack_.size() - 1;
+}
+
+const directory_entry& recursive_directory_iterator::__dereference() const {
+  return __imp_->__stack_.top().__entry_;
+}
+
+recursive_directory_iterator&
+recursive_directory_iterator::__increment(error_code* ec) {
+  if (ec)
+    ec->clear();
+  if (recursion_pending()) {
+    if (__try_recursion(ec) || (ec && *ec))
+      return *this;
+  }
+  __rec_ = true;
+  __advance(ec);
+  return *this;
+}
+
+void recursive_directory_iterator::__advance(error_code* ec) {
+  ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
+
+  const directory_iterator end_it;
+  auto& stack = __imp_->__stack_;
+  error_code m_ec;
+  while (stack.size() > 0) {
+    if (stack.top().advance(m_ec))
+      return;
+    if (m_ec)
+      break;
+    stack.pop();
+  }
+
+  if (m_ec) {
+    path root = move(stack.top().__root_);
+    __imp_.reset();
+    err.report(m_ec, "at root \"%s\"", root);
+  } else {
+    __imp_.reset();
+  }
+}
+
+bool recursive_directory_iterator::__try_recursion(error_code* ec) {
+  ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
+
+  bool rec_sym = bool(options() & directory_options::follow_directory_symlink);
+
+  auto& curr_it = __imp_->__stack_.top();
+
+  bool skip_rec = false;
+  error_code m_ec;
+  if (!rec_sym) {
+    file_status st(curr_it.__entry_.__get_sym_ft(&m_ec));
+    if (m_ec && status_known(st))
+      m_ec.clear();
+    if (m_ec || is_symlink(st) || !is_directory(st))
+      skip_rec = true;
+  } else {
+    file_status st(curr_it.__entry_.__get_ft(&m_ec));
+    if (m_ec && status_known(st))
+      m_ec.clear();
+    if (m_ec || !is_directory(st))
+      skip_rec = true;
+  }
+
+  if (!skip_rec) {
+    __dir_stream new_it(curr_it.__entry_.path(), __imp_->__options_, m_ec);
+    if (new_it.good()) {
+      __imp_->__stack_.push(move(new_it));
+      return true;
+    }
+  }
+  if (m_ec) {
+    const bool allow_eacess =
+        bool(__imp_->__options_ & directory_options::skip_permission_denied);
+    if (m_ec.value() == EACCES && allow_eacess) {
+      if (ec)
+        ec->clear();
+    } else {
+      path at_ent = move(curr_it.__entry_.__p_);
+      __imp_.reset();
+      err.report(m_ec, "attempting recursion into \"%s\"", at_ent);
+    }
+  }
+  return false;
+}
+
+}  // namespace android::hardware::automotive::filesystem
+/* clang-format on */
diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/filesystem_common.h b/automotive/can/1.0/default/libc++fs/src/filesystem/filesystem_common.h
new file mode 100644
index 0000000..4f44661
--- /dev/null
+++ b/automotive/can/1.0/default/libc++fs/src/filesystem/filesystem_common.h
@@ -0,0 +1,441 @@
+//===----------------------------------------------------------------------===////
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===////
+/* clang-format off */
+#ifndef AUTO_FILESYSTEM_COMMON_H
+#define AUTO_FILESYSTEM_COMMON_H
+
+#include "automotive/filesystem"
+#include <array>
+#include <chrono>
+#include <cstdlib>
+#include <climits>
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/time.h> // for ::utimes as used in __last_write_time
+#include <fcntl.h>    /* values for fchmodat */
+
+#if !defined(__APPLE__)
+// We can use the presence of UTIME_OMIT to detect platforms that provide
+// utimensat.
+#if defined(UTIME_OMIT)
+#define _LIBCPP_USE_UTIMENSAT
+#endif
+#endif
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+namespace android::hardware::automotive::filesystem {
+using namespace std::chrono;
+
+using std::error_code;
+using std::is_floating_point;
+using std::micro;
+using std::nano;
+using std::ratio;
+
+namespace detail {
+namespace {
+
+static string format_string_imp(const char* msg, ...) {
+  // we might need a second shot at this, so pre-emptivly make a copy
+  struct GuardVAList {
+    va_list& target;
+    bool active = true;
+    GuardVAList(va_list& target) : target(target), active(true) {}
+    void clear() {
+      if (active)
+        va_end(target);
+      active = false;
+    }
+    ~GuardVAList() {
+      if (active)
+        va_end(target);
+    }
+  };
+  va_list args;
+  va_start(args, msg);
+  GuardVAList args_guard(args);
+
+  va_list args_cp;
+  va_copy(args_cp, args);
+  GuardVAList args_copy_guard(args_cp);
+
+  std::string result;
+
+  array<char, 256> local_buff;
+  size_t size_with_null = local_buff.size();
+  auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp);
+
+  args_copy_guard.clear();
+
+  // handle empty expansion
+  if (ret == 0)
+    return result;
+  if (static_cast<size_t>(ret) < size_with_null) {
+    result.assign(local_buff.data(), static_cast<size_t>(ret));
+    return result;
+  }
+
+  // we did not provide a long enough buffer on our first attempt. The
+  // return value is the number of bytes (excluding the null byte) that are
+  // needed for formatting.
+  size_with_null = static_cast<size_t>(ret) + 1;
+  result.__resize_default_init(size_with_null - 1);
+  ret = ::vsnprintf(&result[0], size_with_null, msg, args);
+  _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
+
+  return result;
+}
+
+const char* unwrap(string const& s) { return s.c_str(); }
+const char* unwrap(path const& p) { return p.native().c_str(); }
+template <class Arg>
+Arg const& unwrap(Arg const& a) {
+  static_assert(!is_class<Arg>::value, "cannot pass class here");
+  return a;
+}
+
+template <class... Args>
+string format_string(const char* fmt, Args const&... args) {
+  return format_string_imp(fmt, unwrap(args)...);
+}
+
+error_code capture_errno() {
+  _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
+  return error_code(errno, generic_category());
+}
+
+template <class T>
+T error_value();
+template <>
+_LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value<void>() {}
+template <>
+bool error_value<bool>() {
+  return false;
+}
+template <>
+uintmax_t error_value<uintmax_t>() {
+  return uintmax_t(-1);
+}
+template <>
+_LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() {
+  return file_time_type::min();
+}
+template <>
+path error_value<path>() {
+  return {};
+}
+
+template <class T>
+struct ErrorHandler {
+  const char* func_name;
+  error_code* ec = nullptr;
+  const path* p1 = nullptr;
+  const path* p2 = nullptr;
+
+  ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr,
+               const path* p2 = nullptr)
+      : func_name(fname), ec(ec), p1(p1), p2(p2) {
+    if (ec)
+      ec->clear();
+  }
+
+  T report(const error_code& m_ec) const {
+    if (ec) {
+      *ec = m_ec;
+      return error_value<T>();
+    }
+    string what = string("in ") + func_name;
+    switch (bool(p1) + bool(p2)) {
+    case 0:
+      __throw_filesystem_error(what, m_ec);
+    case 1:
+      __throw_filesystem_error(what, *p1, m_ec);
+    case 2:
+      __throw_filesystem_error(what, *p1, *p2, m_ec);
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  template <class... Args>
+  T report(const error_code& m_ec, const char* msg, Args const&... args) const {
+    if (ec) {
+      *ec = m_ec;
+      return error_value<T>();
+    }
+    string what =
+        string("in ") + func_name + ": " + format_string(msg, args...);
+    switch (bool(p1) + bool(p2)) {
+    case 0:
+      __throw_filesystem_error(what, m_ec);
+    case 1:
+      __throw_filesystem_error(what, *p1, m_ec);
+    case 2:
+      __throw_filesystem_error(what, *p1, *p2, m_ec);
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  T report(errc const& err) const { return report(make_error_code(err)); }
+
+  template <class... Args>
+  T report(errc const& err, const char* msg, Args const&... args) const {
+    return report(make_error_code(err), msg, args...);
+  }
+
+private:
+  ErrorHandler(ErrorHandler const&) = delete;
+  ErrorHandler& operator=(ErrorHandler const&) = delete;
+};
+
+using chrono::duration;
+using chrono::duration_cast;
+
+using TimeSpec = struct ::timespec;
+using StatT = struct ::stat;
+
+template <class FileTimeT, class TimeT,
+          bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
+struct time_util_base {
+  using rep = typename FileTimeT::rep;
+  using fs_duration = typename FileTimeT::duration;
+  using fs_seconds = duration<rep>;
+  using fs_nanoseconds = duration<rep, nano>;
+  using fs_microseconds = duration<rep, micro>;
+
+  static constexpr rep max_seconds =
+      duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
+
+  static constexpr rep max_nsec =
+      duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
+                                    fs_seconds(max_seconds))
+          .count();
+
+  static constexpr rep min_seconds =
+      duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
+
+  static constexpr rep min_nsec_timespec =
+      duration_cast<fs_nanoseconds>(
+          (FileTimeT::duration::min() - fs_seconds(min_seconds)) +
+          fs_seconds(1))
+          .count();
+
+private:
+#if _LIBCPP_STD_VER > 11 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
+  static constexpr fs_duration get_min_nsecs() {
+    return duration_cast<fs_duration>(
+        fs_nanoseconds(min_nsec_timespec) -
+        duration_cast<fs_nanoseconds>(fs_seconds(1)));
+  }
+  // Static assert that these values properly round trip.
+  static_assert(fs_seconds(min_seconds) + get_min_nsecs() ==
+                    FileTimeT::duration::min(),
+                "value doesn't roundtrip");
+
+  static constexpr bool check_range() {
+    // This kinda sucks, but it's what happens when we don't have __int128_t.
+    if (sizeof(TimeT) == sizeof(rep)) {
+      typedef duration<long long, ratio<3600 * 24 * 365> > Years;
+      return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) &&
+             duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250);
+    }
+    return max_seconds >= numeric_limits<TimeT>::max() &&
+           min_seconds <= numeric_limits<TimeT>::min();
+  }
+  static_assert(check_range(), "the representable range is unacceptable small");
+#endif
+};
+
+template <class FileTimeT, class TimeT>
+struct time_util_base<FileTimeT, TimeT, true> {
+  using rep = typename FileTimeT::rep;
+  using fs_duration = typename FileTimeT::duration;
+  using fs_seconds = duration<rep>;
+  using fs_nanoseconds = duration<rep, nano>;
+  using fs_microseconds = duration<rep, micro>;
+
+  static const rep max_seconds;
+  static const rep max_nsec;
+  static const rep min_seconds;
+  static const rep min_nsec_timespec;
+};
+
+template <class FileTimeT, class TimeT>
+const typename FileTimeT::rep
+    time_util_base<FileTimeT, TimeT, true>::max_seconds =
+        duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
+
+template <class FileTimeT, class TimeT>
+const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec =
+    duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
+                                  fs_seconds(max_seconds))
+        .count();
+
+template <class FileTimeT, class TimeT>
+const typename FileTimeT::rep
+    time_util_base<FileTimeT, TimeT, true>::min_seconds =
+        duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
+
+template <class FileTimeT, class TimeT>
+const typename FileTimeT::rep
+    time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec =
+        duration_cast<fs_nanoseconds>((FileTimeT::duration::min() -
+                                       fs_seconds(min_seconds)) +
+                                      fs_seconds(1))
+            .count();
+
+template <class FileTimeT, class TimeT, class TimeSpecT>
+struct time_util : time_util_base<FileTimeT, TimeT> {
+  using Base = time_util_base<FileTimeT, TimeT>;
+  using Base::max_nsec;
+  using Base::max_seconds;
+  using Base::min_nsec_timespec;
+  using Base::min_seconds;
+
+  using typename Base::fs_duration;
+  using typename Base::fs_microseconds;
+  using typename Base::fs_nanoseconds;
+  using typename Base::fs_seconds;
+
+public:
+  template <class CType, class ChronoType>
+  static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out,
+                                                        ChronoType time) {
+    using Lim = numeric_limits<CType>;
+    if (time > Lim::max() || time < Lim::min())
+      return false;
+    *out = static_cast<CType>(time);
+    return true;
+  }
+
+  static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
+    if (tm.tv_sec >= 0) {
+      return tm.tv_sec < max_seconds ||
+             (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
+    } else if (tm.tv_sec == (min_seconds - 1)) {
+      return tm.tv_nsec >= min_nsec_timespec;
+    } else {
+      return tm.tv_sec >= min_seconds;
+    }
+  }
+
+  static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) {
+    auto secs = duration_cast<fs_seconds>(tm.time_since_epoch());
+    auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs);
+    if (nsecs.count() < 0) {
+      secs = secs + fs_seconds(1);
+      nsecs = nsecs + fs_seconds(1);
+    }
+    using TLim = numeric_limits<TimeT>;
+    if (secs.count() >= 0)
+      return secs.count() <= TLim::max();
+    return secs.count() >= TLim::min();
+  }
+
+  static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
+  convert_from_timespec(TimeSpecT tm) {
+    if (tm.tv_sec >= 0 || tm.tv_nsec == 0) {
+      return FileTimeT(fs_seconds(tm.tv_sec) +
+                       duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec)));
+    } else { // tm.tv_sec < 0
+      auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) -
+                                                   fs_nanoseconds(tm.tv_nsec));
+      auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec;
+      return FileTimeT(Dur);
+    }
+  }
+
+  template <class SubSecT>
+  static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
+  set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) {
+    auto dur = tp.time_since_epoch();
+    auto sec_dur = duration_cast<fs_seconds>(dur);
+    auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur);
+    // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
+    if (subsec_dur.count() < 0) {
+      if (sec_dur.count() > min_seconds) {
+        sec_dur = sec_dur - fs_seconds(1);
+        subsec_dur = subsec_dur + fs_seconds(1);
+      } else {
+        subsec_dur = fs_nanoseconds::zero();
+      }
+    }
+    return checked_set(sec_out, sec_dur.count()) &&
+           checked_set(subsec_out, subsec_dur.count());
+  }
+  static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest,
+                                                                FileTimeT tp) {
+    if (!is_representable(tp))
+      return false;
+    return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);
+  }
+};
+
+using fs_time = time_util<file_time_type, time_t, TimeSpec>;
+
+#if defined(__APPLE__)
+TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
+TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
+#else
+TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
+TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
+#endif
+
+// allow the utimes implementation to compile even it we're not going
+// to use it.
+
+bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS,
+                  error_code& ec) {
+  using namespace chrono;
+  auto Convert = [](long nsec) {
+    using int_type = decltype(std::declval< ::timeval>().tv_usec);
+    auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
+    return static_cast<int_type>(dur);
+  };
+  struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec, Convert(TS[0].tv_nsec)},
+                                     {TS[1].tv_sec, Convert(TS[1].tv_nsec)}};
+  if (::utimes(p.c_str(), ConvertedTS) == -1) {
+    ec = capture_errno();
+    return true;
+  }
+  return false;
+}
+
+#if defined(_LIBCPP_USE_UTIMENSAT)
+bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS,
+                     error_code& ec) {
+  if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) {
+    ec = capture_errno();
+    return true;
+  }
+  return false;
+}
+#endif
+
+bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS,
+                    error_code& ec) {
+#if !defined(_LIBCPP_USE_UTIMENSAT)
+  return posix_utimes(p, TS, ec);
+#else
+  return posix_utimensat(p, TS, ec);
+#endif
+}
+
+} // namespace
+} // end namespace detail
+
+}  // namespace android::hardware::automotive::filesystem
+
+#endif // AUTO_FILESYSTEM_COMMON_H
+/* clang-format on */
diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp b/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp
new file mode 100644
index 0000000..404c0bd
--- /dev/null
+++ b/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp
@@ -0,0 +1,1773 @@
+//===--------------------- filesystem/ops.cpp -----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/* clang-format off */
+#include "automotive/filesystem"
+#include <array>
+#include <iterator>
+#include <fstream>
+#include <random> /* for unique_path */
+#include <string_view>
+#include <type_traits>
+#include <vector>
+#include <cstdlib>
+#include <climits>
+
+#include "filesystem_common.h"
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <time.h>
+#include <fcntl.h> /* values for fchmodat */
+
+#if defined(__linux__)
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
+#include <sys/sendfile.h>
+#define _LIBCPP_USE_SENDFILE
+#endif
+#elif defined(__APPLE__) || __has_include(<copyfile.h>)
+#include <copyfile.h>
+#define _LIBCPP_USE_COPYFILE
+#endif
+
+#if !defined(__APPLE__)
+#define _LIBCPP_USE_CLOCK_GETTIME
+#endif
+
+#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
+#include <sys/time.h> // for gettimeofday and timeval
+#endif                // !defined(CLOCK_REALTIME)
+
+#if defined(_LIBCPP_COMPILER_GCC)
+#if _GNUC_VER < 500
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+#endif
+
+namespace android::hardware::automotive::filesystem {
+
+#ifdef _VSTD_FS
+#pragma push_macro("_VSTD_FS")
+#else
+#define _LIBAUTO_UNDEF_VSTD_FS
+#endif
+#define _VSTD_FS android::hardware::automotive::filesystem
+
+namespace {
+namespace parser {
+
+using string_view_t = path::__string_view;
+using string_view_pair = pair<string_view_t, string_view_t>;
+using PosPtr = path::value_type const*;
+
+struct PathParser {
+  enum ParserState : unsigned char {
+    // Zero is a special sentinel value used by default constructed iterators.
+    PS_BeforeBegin = path::iterator::_BeforeBegin,
+    PS_InRootName = path::iterator::_InRootName,
+    PS_InRootDir = path::iterator::_InRootDir,
+    PS_InFilenames = path::iterator::_InFilenames,
+    PS_InTrailingSep = path::iterator::_InTrailingSep,
+    PS_AtEnd = path::iterator::_AtEnd
+  };
+
+  const string_view_t Path;
+  string_view_t RawEntry;
+  ParserState State;
+
+private:
+  PathParser(string_view_t P, ParserState State) noexcept : Path(P),
+                                                            State(State) {}
+
+public:
+  PathParser(string_view_t P, string_view_t E, unsigned char S)
+      : Path(P), RawEntry(E), State(static_cast<ParserState>(S)) {
+    // S cannot be '0' or PS_BeforeBegin.
+  }
+
+  static PathParser CreateBegin(string_view_t P) noexcept {
+    PathParser PP(P, PS_BeforeBegin);
+    PP.increment();
+    return PP;
+  }
+
+  static PathParser CreateEnd(string_view_t P) noexcept {
+    PathParser PP(P, PS_AtEnd);
+    return PP;
+  }
+
+  PosPtr peek() const noexcept {
+    auto TkEnd = getNextTokenStartPos();
+    auto End = getAfterBack();
+    return TkEnd == End ? nullptr : TkEnd;
+  }
+
+  void increment() noexcept {
+    const PosPtr End = getAfterBack();
+    const PosPtr Start = getNextTokenStartPos();
+    if (Start == End)
+      return makeState(PS_AtEnd);
+
+    switch (State) {
+    case PS_BeforeBegin: {
+      PosPtr TkEnd = consumeSeparator(Start, End);
+      if (TkEnd)
+        return makeState(PS_InRootDir, Start, TkEnd);
+      else
+        return makeState(PS_InFilenames, Start, consumeName(Start, End));
+    }
+    case PS_InRootDir:
+      return makeState(PS_InFilenames, Start, consumeName(Start, End));
+
+    case PS_InFilenames: {
+      PosPtr SepEnd = consumeSeparator(Start, End);
+      if (SepEnd != End) {
+        PosPtr TkEnd = consumeName(SepEnd, End);
+        if (TkEnd)
+          return makeState(PS_InFilenames, SepEnd, TkEnd);
+      }
+      return makeState(PS_InTrailingSep, Start, SepEnd);
+    }
+
+    case PS_InTrailingSep:
+      return makeState(PS_AtEnd);
+
+    case PS_InRootName:
+    case PS_AtEnd:
+      _LIBCPP_UNREACHABLE();
+    }
+  }
+
+  void decrement() noexcept {
+    const PosPtr REnd = getBeforeFront();
+    const PosPtr RStart = getCurrentTokenStartPos() - 1;
+    if (RStart == REnd) // we're decrementing the begin
+      return makeState(PS_BeforeBegin);
+
+    switch (State) {
+    case PS_AtEnd: {
+      // Try to consume a trailing separator or root directory first.
+      if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {
+        if (SepEnd == REnd)
+          return makeState(PS_InRootDir, Path.data(), RStart + 1);
+        return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1);
+      } else {
+        PosPtr TkStart = consumeName(RStart, REnd);
+        return makeState(PS_InFilenames, TkStart + 1, RStart + 1);
+      }
+    }
+    case PS_InTrailingSep:
+      return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1,
+                       RStart + 1);
+    case PS_InFilenames: {
+      PosPtr SepEnd = consumeSeparator(RStart, REnd);
+      if (SepEnd == REnd)
+        return makeState(PS_InRootDir, Path.data(), RStart + 1);
+      PosPtr TkEnd = consumeName(SepEnd, REnd);
+      return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);
+    }
+    case PS_InRootDir:
+      // return makeState(PS_InRootName, Path.data(), RStart + 1);
+    case PS_InRootName:
+    case PS_BeforeBegin:
+      _LIBCPP_UNREACHABLE();
+    }
+  }
+
+  /// \brief Return a view with the "preferred representation" of the current
+  ///   element. For example trailing separators are represented as a '.'
+  string_view_t operator*() const noexcept {
+    switch (State) {
+    case PS_BeforeBegin:
+    case PS_AtEnd:
+      return "";
+    case PS_InRootDir:
+      return "/";
+    case PS_InTrailingSep:
+      return "";
+    case PS_InRootName:
+    case PS_InFilenames:
+      return RawEntry;
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  explicit operator bool() const noexcept {
+    return State != PS_BeforeBegin && State != PS_AtEnd;
+  }
+
+  PathParser& operator++() noexcept {
+    increment();
+    return *this;
+  }
+
+  PathParser& operator--() noexcept {
+    decrement();
+    return *this;
+  }
+
+  bool atEnd() const noexcept {
+    return State == PS_AtEnd;
+  }
+
+  bool inRootDir() const noexcept {
+    return State == PS_InRootDir;
+  }
+
+  bool inRootName() const noexcept {
+    return State == PS_InRootName;
+  }
+
+  bool inRootPath() const noexcept {
+    return inRootName() || inRootDir();
+  }
+
+private:
+  void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept {
+    State = NewState;
+    RawEntry = string_view_t(Start, End - Start);
+  }
+  void makeState(ParserState NewState) noexcept {
+    State = NewState;
+    RawEntry = {};
+  }
+
+  PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); }
+
+  PosPtr getBeforeFront() const noexcept { return Path.data() - 1; }
+
+  /// \brief Return a pointer to the first character after the currently
+  ///   lexed element.
+  PosPtr getNextTokenStartPos() const noexcept {
+    switch (State) {
+    case PS_BeforeBegin:
+      return Path.data();
+    case PS_InRootName:
+    case PS_InRootDir:
+    case PS_InFilenames:
+      return &RawEntry.back() + 1;
+    case PS_InTrailingSep:
+    case PS_AtEnd:
+      return getAfterBack();
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  /// \brief Return a pointer to the first character in the currently lexed
+  ///   element.
+  PosPtr getCurrentTokenStartPos() const noexcept {
+    switch (State) {
+    case PS_BeforeBegin:
+    case PS_InRootName:
+      return &Path.front();
+    case PS_InRootDir:
+    case PS_InFilenames:
+    case PS_InTrailingSep:
+      return &RawEntry.front();
+    case PS_AtEnd:
+      return &Path.back() + 1;
+    }
+    _LIBCPP_UNREACHABLE();
+  }
+
+  PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {
+    if (P == End || *P != '/')
+      return nullptr;
+    const int Inc = P < End ? 1 : -1;
+    P += Inc;
+    while (P != End && *P == '/')
+      P += Inc;
+    return P;
+  }
+
+  PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {
+    if (P == End || *P == '/')
+      return nullptr;
+    const int Inc = P < End ? 1 : -1;
+    P += Inc;
+    while (P != End && *P != '/')
+      P += Inc;
+    return P;
+  }
+};
+
+string_view_pair separate_filename(string_view_t const& s) {
+  if (s == "." || s == ".." || s.empty())
+    return string_view_pair{s, ""};
+  auto pos = s.find_last_of('.');
+  if (pos == string_view_t::npos || pos == 0)
+    return string_view_pair{s, string_view_t{}};
+  return string_view_pair{s.substr(0, pos), s.substr(pos)};
+}
+
+string_view_t createView(PosPtr S, PosPtr E) noexcept {
+  return {S, static_cast<size_t>(E - S) + 1};
+}
+
+} // namespace parser
+} // namespace
+
+//                       POSIX HELPERS
+
+namespace detail {
+namespace {
+
+using value_type = path::value_type;
+using string_type = path::string_type;
+
+struct FileDescriptor {
+  const path& name;
+  int fd = -1;
+  StatT m_stat;
+  file_status m_status;
+
+  template <class... Args>
+  static FileDescriptor create(const path* p, error_code& ec, Args... args) {
+    ec.clear();
+    int fd;
+    if ((fd = ::open(p->c_str(), args...)) == -1) {
+      ec = capture_errno();
+      return FileDescriptor{p};
+    }
+    return FileDescriptor(p, fd);
+  }
+
+  template <class... Args>
+  static FileDescriptor create_with_status(const path* p, error_code& ec,
+                                           Args... args) {
+    FileDescriptor fd = create(p, ec, args...);
+    if (!ec)
+      fd.refresh_status(ec);
+
+    return fd;
+  }
+
+  file_status get_status() const { return m_status; }
+  StatT const& get_stat() const { return m_stat; }
+
+  bool status_known() const { return _VSTD_FS::status_known(m_status); }
+
+  file_status refresh_status(error_code& ec);
+
+  void close() noexcept {
+    if (fd != -1)
+      ::close(fd);
+    fd = -1;
+  }
+
+  FileDescriptor(FileDescriptor&& other)
+      : name(other.name), fd(other.fd), m_stat(other.m_stat),
+        m_status(other.m_status) {
+    other.fd = -1;
+    other.m_status = file_status{};
+  }
+
+  ~FileDescriptor() { close(); }
+
+  FileDescriptor(FileDescriptor const&) = delete;
+  FileDescriptor& operator=(FileDescriptor const&) = delete;
+
+private:
+  explicit FileDescriptor(const path* p, int fd = -1) : name(*p), fd(fd) {}
+};
+
+perms posix_get_perms(const StatT& st) noexcept {
+  return static_cast<perms>(st.st_mode) & perms::mask;
+}
+
+::mode_t posix_convert_perms(perms prms) {
+  return static_cast< ::mode_t>(prms & perms::mask);
+}
+
+file_status create_file_status(error_code& m_ec, path const& p,
+                               const StatT& path_stat, error_code* ec) {
+  if (ec)
+    *ec = m_ec;
+  if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) {
+    return file_status(file_type::not_found);
+  } else if (m_ec) {
+    ErrorHandler<void> err("posix_stat", ec, &p);
+    err.report(m_ec, "failed to determine attributes for the specified path");
+    return file_status(file_type::none);
+  }
+  // else
+
+  file_status fs_tmp;
+  auto const mode = path_stat.st_mode;
+  if (S_ISLNK(mode))
+    fs_tmp.type(file_type::symlink);
+  else if (S_ISREG(mode))
+    fs_tmp.type(file_type::regular);
+  else if (S_ISDIR(mode))
+    fs_tmp.type(file_type::directory);
+  else if (S_ISBLK(mode))
+    fs_tmp.type(file_type::block);
+  else if (S_ISCHR(mode))
+    fs_tmp.type(file_type::character);
+  else if (S_ISFIFO(mode))
+    fs_tmp.type(file_type::fifo);
+  else if (S_ISSOCK(mode))
+    fs_tmp.type(file_type::socket);
+  else
+    fs_tmp.type(file_type::unknown);
+
+  fs_tmp.permissions(detail::posix_get_perms(path_stat));
+  return fs_tmp;
+}
+
+file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) {
+  error_code m_ec;
+  if (::stat(p.c_str(), &path_stat) == -1)
+    m_ec = detail::capture_errno();
+  return create_file_status(m_ec, p, path_stat, ec);
+}
+
+file_status posix_stat(path const& p, error_code* ec) {
+  StatT path_stat;
+  return posix_stat(p, path_stat, ec);
+}
+
+file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) {
+  error_code m_ec;
+  if (::lstat(p.c_str(), &path_stat) == -1)
+    m_ec = detail::capture_errno();
+  return create_file_status(m_ec, p, path_stat, ec);
+}
+
+file_status posix_lstat(path const& p, error_code* ec) {
+  StatT path_stat;
+  return posix_lstat(p, path_stat, ec);
+}
+
+bool posix_ftruncate(const FileDescriptor& fd, size_t to_size, error_code& ec) {
+  if (::ftruncate(fd.fd, to_size) == -1) {
+    ec = capture_errno();
+    return true;
+  }
+  ec.clear();
+  return false;
+}
+
+bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) {
+  if (::fchmod(fd.fd, st.st_mode) == -1) {
+    ec = capture_errno();
+    return true;
+  }
+  ec.clear();
+  return false;
+}
+
+bool stat_equivalent(const StatT& st1, const StatT& st2) {
+  return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
+}
+
+file_status FileDescriptor::refresh_status(error_code& ec) {
+  // FD must be open and good.
+  m_status = file_status{};
+  m_stat = {};
+  error_code m_ec;
+  if (::fstat(fd, &m_stat) == -1)
+    m_ec = capture_errno();
+  m_status = create_file_status(m_ec, name, m_stat, &ec);
+  return m_status;
+}
+} // namespace
+} // end namespace detail
+
+using detail::capture_errno;
+using detail::ErrorHandler;
+using detail::StatT;
+using detail::TimeSpec;
+using parser::createView;
+using parser::PathParser;
+using parser::string_view_t;
+
+const bool _FilesystemClock::is_steady;
+
+_FilesystemClock::time_point _FilesystemClock::now() noexcept {
+  typedef chrono::duration<rep> __secs;
+#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
+  typedef chrono::duration<rep, nano> __nsecs;
+  struct timespec tp;
+  if (0 != clock_gettime(CLOCK_REALTIME, &tp))
+    __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
+  return time_point(__secs(tp.tv_sec) +
+                    chrono::duration_cast<duration>(__nsecs(tp.tv_nsec)));
+#else
+  typedef chrono::duration<rep, micro> __microsecs;
+  timeval tv;
+  gettimeofday(&tv, 0);
+  return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec));
+#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
+}
+
+filesystem_error::~filesystem_error() {}
+
+void filesystem_error::__create_what(int __num_paths) {
+  const char* derived_what = system_error::what();
+  __storage_->__what_ = [&]() -> string {
+    const char* p1 = path1().native().empty() ? "\"\"" : path1().c_str();
+    const char* p2 = path2().native().empty() ? "\"\"" : path2().c_str();
+    switch (__num_paths) {
+    default:
+      return detail::format_string("filesystem error: %s", derived_what);
+    case 1:
+      return detail::format_string("filesystem error: %s [%s]", derived_what,
+                                   p1);
+    case 2:
+      return detail::format_string("filesystem error: %s [%s] [%s]",
+                                   derived_what, p1, p2);
+    }
+  }();
+}
+
+static path __do_absolute(const path& p, path* cwd, error_code* ec) {
+  if (ec)
+    ec->clear();
+  if (p.is_absolute())
+    return p;
+  *cwd = __current_path(ec);
+  if (ec && *ec)
+    return {};
+  return (*cwd) / p;
+}
+
+path __absolute(const path& p, error_code* ec) {
+  path cwd;
+  return __do_absolute(p, &cwd, ec);
+}
+
+path __canonical(path const& orig_p, error_code* ec) {
+  path cwd;
+  ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
+
+  path p = __do_absolute(orig_p, &cwd, ec);
+  char buff[PATH_MAX + 1];
+  char* ret;
+  if ((ret = ::realpath(p.c_str(), buff)) == nullptr)
+    return err.report(capture_errno());
+  return {ret};
+}
+
+void __copy(const path& from, const path& to, copy_options options,
+            error_code* ec) {
+  ErrorHandler<void> err("copy", ec, &from, &to);
+
+  const bool sym_status = bool(
+      options & (copy_options::create_symlinks | copy_options::skip_symlinks));
+
+  const bool sym_status2 = bool(options & copy_options::copy_symlinks);
+
+  error_code m_ec1;
+  StatT f_st = {};
+  const file_status f = sym_status || sym_status2
+                            ? detail::posix_lstat(from, f_st, &m_ec1)
+                            : detail::posix_stat(from, f_st, &m_ec1);
+  if (m_ec1)
+    return err.report(m_ec1);
+
+  StatT t_st = {};
+  const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1)
+                                   : detail::posix_stat(to, t_st, &m_ec1);
+
+  if (not status_known(t))
+    return err.report(m_ec1);
+
+  if (!exists(f) || is_other(f) || is_other(t) ||
+      (is_directory(f) && is_regular_file(t)) ||
+      detail::stat_equivalent(f_st, t_st)) {
+    return err.report(errc::function_not_supported);
+  }
+
+  if (ec)
+    ec->clear();
+
+  if (is_symlink(f)) {
+    if (bool(copy_options::skip_symlinks & options)) {
+      // do nothing
+    } else if (not exists(t)) {
+      __copy_symlink(from, to, ec);
+    } else {
+      return err.report(errc::file_exists);
+    }
+    return;
+  } else if (is_regular_file(f)) {
+    if (bool(copy_options::directories_only & options)) {
+      // do nothing
+    } else if (bool(copy_options::create_symlinks & options)) {
+      __create_symlink(from, to, ec);
+    } else if (bool(copy_options::create_hard_links & options)) {
+      __create_hard_link(from, to, ec);
+    } else if (is_directory(t)) {
+      __copy_file(from, to / from.filename(), options, ec);
+    } else {
+      __copy_file(from, to, options, ec);
+    }
+    return;
+  } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
+    return err.report(errc::is_a_directory);
+  } else if (is_directory(f) && (bool(copy_options::recursive & options) ||
+                                 copy_options::none == options)) {
+
+    if (!exists(t)) {
+      // create directory to with attributes from 'from'.
+      __create_directory(to, from, ec);
+      if (ec && *ec) {
+        return;
+      }
+    }
+    directory_iterator it =
+        ec ? directory_iterator(from, *ec) : directory_iterator(from);
+    if (ec && *ec) {
+      return;
+    }
+    error_code m_ec2;
+    for (; it != directory_iterator(); it.increment(m_ec2)) {
+      if (m_ec2) {
+        return err.report(m_ec2);
+      }
+      __copy(it->path(), to / it->path().filename(),
+             options | copy_options::__in_recursive_copy, ec);
+      if (ec && *ec) {
+        return;
+      }
+    }
+  }
+}
+
+namespace detail {
+namespace {
+
+#ifdef _LIBCPP_USE_SENDFILE
+bool copy_file_impl_sendfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
+                             error_code& ec) {
+
+  size_t count = read_fd.get_stat().st_size;
+  do {
+    ssize_t res;
+    if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) {
+      ec = capture_errno();
+      return false;
+    }
+    count -= res;
+  } while (count > 0);
+
+  ec.clear();
+
+  return true;
+}
+#elif defined(_LIBCPP_USE_COPYFILE)
+bool copy_file_impl_copyfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
+                             error_code& ec) {
+  struct CopyFileState {
+    copyfile_state_t state;
+    CopyFileState() { state = copyfile_state_alloc(); }
+    ~CopyFileState() { copyfile_state_free(state); }
+
+  private:
+    CopyFileState(CopyFileState const&) = delete;
+    CopyFileState& operator=(CopyFileState const&) = delete;
+  };
+
+  CopyFileState cfs;
+  if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) {
+    ec = capture_errno();
+    return false;
+  }
+
+  ec.clear();
+  return true;
+}
+#endif
+
+// Note: This function isn't guarded by ifdef's even though it may be unused
+// in order to assure it still compiles.
+__attribute__((unused)) bool copy_file_impl_default(FileDescriptor& read_fd,
+                                                    FileDescriptor& write_fd,
+                                                    error_code& ec) {
+  ifstream in;
+  in.__open(read_fd.fd, ios::binary);
+  if (!in.is_open()) {
+    // This assumes that __open didn't reset the error code.
+    ec = capture_errno();
+    return false;
+  }
+  ofstream out;
+  out.__open(write_fd.fd, ios::binary);
+  if (!out.is_open()) {
+    ec = capture_errno();
+    return false;
+  }
+
+  if (in.good() && out.good()) {
+    using InIt = istreambuf_iterator<char>;
+    using OutIt = ostreambuf_iterator<char>;
+    InIt bin(in);
+    InIt ein;
+    OutIt bout(out);
+    copy(bin, ein, bout);
+  }
+  if (out.fail() || in.fail()) {
+    ec = make_error_code(errc::io_error);
+    return false;
+  }
+
+  ec.clear();
+  return true;
+}
+
+bool copy_file_impl(FileDescriptor& from, FileDescriptor& to, error_code& ec) {
+#if defined(_LIBCPP_USE_SENDFILE)
+  return copy_file_impl_sendfile(from, to, ec);
+#elif defined(_LIBCPP_USE_COPYFILE)
+  return copy_file_impl_copyfile(from, to, ec);
+#else
+  return copy_file_impl_default(from, to, ec);
+#endif
+}
+
+} // namespace
+} // namespace detail
+
+bool __copy_file(const path& from, const path& to, copy_options options,
+                 error_code* ec) {
+  using detail::FileDescriptor;
+  ErrorHandler<bool> err("copy_file", ec, &to, &from);
+
+  error_code m_ec;
+  FileDescriptor from_fd =
+      FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK);
+  if (m_ec)
+    return err.report(m_ec);
+
+  auto from_st = from_fd.get_status();
+  StatT const& from_stat = from_fd.get_stat();
+  if (!is_regular_file(from_st)) {
+    if (not m_ec)
+      m_ec = make_error_code(errc::not_supported);
+    return err.report(m_ec);
+  }
+
+  const bool skip_existing = bool(copy_options::skip_existing & options);
+  const bool update_existing = bool(copy_options::update_existing & options);
+  const bool overwrite_existing =
+      bool(copy_options::overwrite_existing & options);
+
+  StatT to_stat_path;
+  file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec);
+  if (!status_known(to_st))
+    return err.report(m_ec);
+
+  const bool to_exists = exists(to_st);
+  if (to_exists && !is_regular_file(to_st))
+    return err.report(errc::not_supported);
+
+  if (to_exists && detail::stat_equivalent(from_stat, to_stat_path))
+    return err.report(errc::file_exists);
+
+  if (to_exists && skip_existing)
+    return false;
+
+  bool ShouldCopy = [&]() {
+    if (to_exists && update_existing) {
+      auto from_time = detail::extract_mtime(from_stat);
+      auto to_time = detail::extract_mtime(to_stat_path);
+      if (from_time.tv_sec < to_time.tv_sec)
+        return false;
+      if (from_time.tv_sec == to_time.tv_sec &&
+          from_time.tv_nsec <= to_time.tv_nsec)
+        return false;
+      return true;
+    }
+    if (!to_exists || overwrite_existing)
+      return true;
+    return err.report(errc::file_exists);
+  }();
+  if (!ShouldCopy)
+    return false;
+
+  // Don't truncate right away. We may not be opening the file we originally
+  // looked at; we'll check this later.
+  int to_open_flags = O_WRONLY;
+  if (!to_exists)
+    to_open_flags |= O_CREAT;
+  FileDescriptor to_fd = FileDescriptor::create_with_status(
+      &to, m_ec, to_open_flags, from_stat.st_mode);
+  if (m_ec)
+    return err.report(m_ec);
+
+  if (to_exists) {
+    // Check that the file we initially stat'ed is equivalent to the one
+    // we opened.
+    // FIXME: report this better.
+    if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat()))
+      return err.report(errc::bad_file_descriptor);
+
+    // Set the permissions and truncate the file we opened.
+    if (detail::posix_fchmod(to_fd, from_stat, m_ec))
+      return err.report(m_ec);
+    if (detail::posix_ftruncate(to_fd, 0, m_ec))
+      return err.report(m_ec);
+  }
+
+  if (!copy_file_impl(from_fd, to_fd, m_ec)) {
+    // FIXME: Remove the dest file if we failed, and it didn't exist previously.
+    return err.report(m_ec);
+  }
+
+  return true;
+}
+
+void __copy_symlink(const path& existing_symlink, const path& new_symlink,
+                    error_code* ec) {
+  const path real_path(__read_symlink(existing_symlink, ec));
+  if (ec && *ec) {
+    return;
+  }
+  // NOTE: proposal says you should detect if you should call
+  // create_symlink or create_directory_symlink. I don't think this
+  // is needed with POSIX
+  __create_symlink(real_path, new_symlink, ec);
+}
+
+bool __create_directories(const path& p, error_code* ec) {
+  ErrorHandler<bool> err("create_directories", ec, &p);
+
+  error_code m_ec;
+  auto const st = detail::posix_stat(p, &m_ec);
+  if (!status_known(st))
+    return err.report(m_ec);
+  else if (is_directory(st))
+    return false;
+  else if (exists(st))
+    return err.report(errc::file_exists);
+
+  const path parent = p.parent_path();
+  if (!parent.empty()) {
+    const file_status parent_st = status(parent, m_ec);
+    if (not status_known(parent_st))
+      return err.report(m_ec);
+    if (not exists(parent_st)) {
+      __create_directories(parent, ec);
+      if (ec && *ec) {
+        return false;
+      }
+    }
+  }
+  return __create_directory(p, ec);
+}
+
+bool __create_directory(const path& p, error_code* ec) {
+  ErrorHandler<bool> err("create_directory", ec, &p);
+
+  if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
+    return true;
+  if (errno != EEXIST)
+    err.report(capture_errno());
+  return false;
+}
+
+bool __create_directory(path const& p, path const& attributes, error_code* ec) {
+  ErrorHandler<bool> err("create_directory", ec, &p, &attributes);
+
+  StatT attr_stat;
+  error_code mec;
+  auto st = detail::posix_stat(attributes, attr_stat, &mec);
+  if (!status_known(st))
+    return err.report(mec);
+  if (!is_directory(st))
+    return err.report(errc::not_a_directory,
+                      "the specified attribute path is invalid");
+
+  if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
+    return true;
+  if (errno != EEXIST)
+    err.report(capture_errno());
+  return false;
+}
+
+void __create_directory_symlink(path const& from, path const& to,
+                                error_code* ec) {
+  ErrorHandler<void> err("create_directory_symlink", ec, &from, &to);
+  if (::symlink(from.c_str(), to.c_str()) != 0)
+    return err.report(capture_errno());
+}
+
+void __create_hard_link(const path& from, const path& to, error_code* ec) {
+  ErrorHandler<void> err("create_hard_link", ec, &from, &to);
+  if (::link(from.c_str(), to.c_str()) == -1)
+    return err.report(capture_errno());
+}
+
+void __create_symlink(path const& from, path const& to, error_code* ec) {
+  ErrorHandler<void> err("create_symlink", ec, &from, &to);
+  if (::symlink(from.c_str(), to.c_str()) == -1)
+    return err.report(capture_errno());
+}
+
+path __current_path(error_code* ec) {
+  ErrorHandler<path> err("current_path", ec);
+
+  auto size = ::pathconf(".", _PC_PATH_MAX);
+  _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
+
+  auto buff = unique_ptr<char[]>(new char[size + 1]);
+  char* ret;
+  if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr)
+    return err.report(capture_errno(), "call to getcwd failed");
+
+  return {buff.get()};
+}
+
+void __current_path(const path& p, error_code* ec) {
+  ErrorHandler<void> err("current_path", ec, &p);
+  if (::chdir(p.c_str()) == -1)
+    err.report(capture_errno());
+}
+
+bool __equivalent(const path& p1, const path& p2, error_code* ec) {
+  ErrorHandler<bool> err("equivalent", ec, &p1, &p2);
+
+  error_code ec1, ec2;
+  StatT st1 = {}, st2 = {};
+  auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
+  if (!exists(s1))
+    return err.report(errc::not_supported);
+  auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
+  if (!exists(s2))
+    return err.report(errc::not_supported);
+
+  return detail::stat_equivalent(st1, st2);
+}
+
+uintmax_t __file_size(const path& p, error_code* ec) {
+  ErrorHandler<uintmax_t> err("file_size", ec, &p);
+
+  error_code m_ec;
+  StatT st;
+  file_status fst = detail::posix_stat(p, st, &m_ec);
+  if (!exists(fst) || !is_regular_file(fst)) {
+    errc error_kind =
+        is_directory(fst) ? errc::is_a_directory : errc::not_supported;
+    if (!m_ec)
+      m_ec = make_error_code(error_kind);
+    return err.report(m_ec);
+  }
+  // is_regular_file(p) == true
+  return static_cast<uintmax_t>(st.st_size);
+}
+
+uintmax_t __hard_link_count(const path& p, error_code* ec) {
+  ErrorHandler<uintmax_t> err("hard_link_count", ec, &p);
+
+  error_code m_ec;
+  StatT st;
+  detail::posix_stat(p, st, &m_ec);
+  if (m_ec)
+    return err.report(m_ec);
+  return static_cast<uintmax_t>(st.st_nlink);
+}
+
+bool __fs_is_empty(const path& p, error_code* ec) {
+  ErrorHandler<bool> err("is_empty", ec, &p);
+
+  error_code m_ec;
+  StatT pst;
+  auto st = detail::posix_stat(p, pst, &m_ec);
+  if (m_ec)
+    return err.report(m_ec);
+  else if (!is_directory(st) && !is_regular_file(st))
+    return err.report(errc::not_supported);
+  else if (is_directory(st)) {
+    auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p);
+    if (ec && *ec)
+      return false;
+    return it == directory_iterator{};
+  } else if (is_regular_file(st))
+    return static_cast<uintmax_t>(pst.st_size) == 0;
+
+  _LIBCPP_UNREACHABLE();
+}
+
+static file_time_type __extract_last_write_time(const path& p, const StatT& st,
+                                                error_code* ec) {
+  using detail::fs_time;
+  ErrorHandler<file_time_type> err("last_write_time", ec, &p);
+
+  auto ts = detail::extract_mtime(st);
+  if (!fs_time::is_representable(ts))
+    return err.report(errc::value_too_large);
+
+  return fs_time::convert_from_timespec(ts);
+}
+
+file_time_type __last_write_time(const path& p, error_code* ec) {
+  using namespace chrono;
+  ErrorHandler<file_time_type> err("last_write_time", ec, &p);
+
+  error_code m_ec;
+  StatT st;
+  detail::posix_stat(p, st, &m_ec);
+  if (m_ec)
+    return err.report(m_ec);
+  return __extract_last_write_time(p, st, ec);
+}
+
+void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
+  using detail::fs_time;
+  ErrorHandler<void> err("last_write_time", ec, &p);
+
+  error_code m_ec;
+  array<TimeSpec, 2> tbuf;
+#if !defined(_LIBCPP_USE_UTIMENSAT)
+  // This implementation has a race condition between determining the
+  // last access time and attempting to set it to the same value using
+  // ::utimes
+  StatT st;
+  file_status fst = detail::posix_stat(p, st, &m_ec);
+  if (m_ec)
+    return err.report(m_ec);
+  tbuf[0] = detail::extract_atime(st);
+#else
+  tbuf[0].tv_sec = 0;
+  tbuf[0].tv_nsec = UTIME_OMIT;
+#endif
+  if (!fs_time::convert_to_timespec(tbuf[1], new_time))
+    return err.report(errc::value_too_large);
+
+  detail::set_file_times(p, tbuf, m_ec);
+  if (m_ec)
+    return err.report(m_ec);
+}
+
+void __permissions(const path& p, perms prms, perm_options opts,
+                   error_code* ec) {
+  ErrorHandler<void> err("permissions", ec, &p);
+
+  auto has_opt = [&](perm_options o) { return bool(o & opts); };
+  const bool resolve_symlinks = !has_opt(perm_options::nofollow);
+  const bool add_perms = has_opt(perm_options::add);
+  const bool remove_perms = has_opt(perm_options::remove);
+  _LIBCPP_ASSERT(
+      (add_perms + remove_perms + has_opt(perm_options::replace)) == 1,
+      "One and only one of the perm_options constants replace, add, or remove "
+      "is present in opts");
+
+  bool set_sym_perms = false;
+  prms &= perms::mask;
+  if (!resolve_symlinks || (add_perms || remove_perms)) {
+    error_code m_ec;
+    file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec)
+                                      : detail::posix_lstat(p, &m_ec);
+    set_sym_perms = is_symlink(st);
+    if (m_ec)
+      return err.report(m_ec);
+    _LIBCPP_ASSERT(st.permissions() != perms::unknown,
+                   "Permissions unexpectedly unknown");
+    if (add_perms)
+      prms |= st.permissions();
+    else if (remove_perms)
+      prms = st.permissions() & ~prms;
+  }
+  const auto real_perms = detail::posix_convert_perms(prms);
+
+#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
+  const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
+  if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
+    return err.report(capture_errno());
+  }
+#else
+  if (set_sym_perms)
+    return err.report(errc::operation_not_supported);
+  if (::chmod(p.c_str(), real_perms) == -1) {
+    return err.report(capture_errno());
+  }
+#endif
+}
+
+path __read_symlink(const path& p, error_code* ec) {
+  ErrorHandler<path> err("read_symlink", ec, &p);
+
+  char buff[PATH_MAX + 1];
+  error_code m_ec;
+  ::ssize_t ret;
+  if ((ret = ::readlink(p.c_str(), buff, PATH_MAX)) == -1) {
+    return err.report(capture_errno());
+  }
+  _LIBCPP_ASSERT(ret <= PATH_MAX, "TODO");
+  _LIBCPP_ASSERT(ret > 0, "TODO");
+  buff[ret] = 0;
+  return {buff};
+}
+
+bool __remove(const path& p, error_code* ec) {
+  ErrorHandler<bool> err("remove", ec, &p);
+  if (::remove(p.c_str()) == -1) {
+    if (errno != ENOENT)
+      err.report(capture_errno());
+    return false;
+  }
+  return true;
+}
+
+namespace {
+
+uintmax_t remove_all_impl(path const& p, error_code& ec) {
+  const auto npos = static_cast<uintmax_t>(-1);
+  const file_status st = __symlink_status(p, &ec);
+  if (ec)
+    return npos;
+  uintmax_t count = 1;
+  if (is_directory(st)) {
+    for (directory_iterator it(p, ec); !ec && it != directory_iterator();
+         it.increment(ec)) {
+      auto other_count = remove_all_impl(it->path(), ec);
+      if (ec)
+        return npos;
+      count += other_count;
+    }
+    if (ec)
+      return npos;
+  }
+  if (!__remove(p, &ec))
+    return npos;
+  return count;
+}
+
+} // end namespace
+
+uintmax_t __remove_all(const path& p, error_code* ec) {
+  ErrorHandler<uintmax_t> err("remove_all", ec, &p);
+
+  error_code mec;
+  auto count = remove_all_impl(p, mec);
+  if (mec) {
+    if (mec == errc::no_such_file_or_directory)
+      return 0;
+    return err.report(mec);
+  }
+  return count;
+}
+
+void __rename(const path& from, const path& to, error_code* ec) {
+  ErrorHandler<void> err("rename", ec, &from, &to);
+  if (::rename(from.c_str(), to.c_str()) == -1)
+    err.report(capture_errno());
+}
+
+void __resize_file(const path& p, uintmax_t size, error_code* ec) {
+  ErrorHandler<void> err("resize_file", ec, &p);
+  if (::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
+    return err.report(capture_errno());
+}
+
+space_info __space(const path& p, error_code* ec) {
+  ErrorHandler<void> err("space", ec, &p);
+  space_info si;
+  struct statvfs m_svfs = {};
+  if (::statvfs(p.c_str(), &m_svfs) == -1) {
+    err.report(capture_errno());
+    si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
+    return si;
+  }
+  // Multiply with overflow checking.
+  auto do_mult = [&](uintmax_t& out, uintmax_t other) {
+    out = other * m_svfs.f_frsize;
+    if (other == 0 || out / other != m_svfs.f_frsize)
+      out = static_cast<uintmax_t>(-1);
+  };
+  do_mult(si.capacity, m_svfs.f_blocks);
+  do_mult(si.free, m_svfs.f_bfree);
+  do_mult(si.available, m_svfs.f_bavail);
+  return si;
+}
+
+file_status __status(const path& p, error_code* ec) {
+  return detail::posix_stat(p, ec);
+}
+
+file_status __symlink_status(const path& p, error_code* ec) {
+  return detail::posix_lstat(p, ec);
+}
+
+path __temp_directory_path(error_code* ec) {
+  ErrorHandler<path> err("temp_directory_path", ec);
+
+  const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
+  const char* ret = nullptr;
+
+  for (auto& ep : env_paths)
+    if ((ret = getenv(ep)))
+      break;
+  if (ret == nullptr)
+    ret = "/tmp";
+
+  path p(ret);
+  error_code m_ec;
+  file_status st = detail::posix_stat(p, &m_ec);
+  if (!status_known(st))
+    return err.report(m_ec, "cannot access path \"%s\"", p);
+
+  if (!exists(st) || !is_directory(st))
+    return err.report(errc::not_a_directory, "path \"%s\" is not a directory",
+                      p);
+
+  return p;
+}
+
+path __weakly_canonical(const path& p, error_code* ec) {
+  ErrorHandler<path> err("weakly_canonical", ec, &p);
+
+  if (p.empty())
+    return __canonical("", ec);
+
+  path result;
+  path tmp;
+  tmp.__reserve(p.native().size());
+  auto PP = PathParser::CreateEnd(p.native());
+  --PP;
+  vector<string_view_t> DNEParts;
+
+  while (PP.State != PathParser::PS_BeforeBegin) {
+    tmp.assign(createView(p.native().data(), &PP.RawEntry.back()));
+    error_code m_ec;
+    file_status st = __status(tmp, &m_ec);
+    if (!status_known(st)) {
+      return err.report(m_ec);
+    } else if (exists(st)) {
+      result = __canonical(tmp, ec);
+      break;
+    }
+    DNEParts.push_back(*PP);
+    --PP;
+  }
+  if (PP.State == PathParser::PS_BeforeBegin)
+    result = __canonical("", ec);
+  if (ec)
+    ec->clear();
+  if (DNEParts.empty())
+    return result;
+  for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It)
+    result /= *It;
+  return result.lexically_normal();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                            path definitions
+///////////////////////////////////////////////////////////////////////////////
+
+constexpr path::value_type path::preferred_separator;
+
+path& path::replace_extension(path const& replacement) {
+  path p = extension();
+  if (not p.empty()) {
+    __pn_.erase(__pn_.size() - p.native().size());
+  }
+  if (!replacement.empty()) {
+    if (replacement.native()[0] != '.') {
+      __pn_ += ".";
+    }
+    __pn_.append(replacement.__pn_);
+  }
+  return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// path.decompose
+
+string_view_t path::__root_name() const {
+  auto PP = PathParser::CreateBegin(__pn_);
+  if (PP.State == PathParser::PS_InRootName)
+    return *PP;
+  return {};
+}
+
+string_view_t path::__root_directory() const {
+  auto PP = PathParser::CreateBegin(__pn_);
+  if (PP.State == PathParser::PS_InRootName)
+    ++PP;
+  if (PP.State == PathParser::PS_InRootDir)
+    return *PP;
+  return {};
+}
+
+string_view_t path::__root_path_raw() const {
+  auto PP = PathParser::CreateBegin(__pn_);
+  if (PP.State == PathParser::PS_InRootName) {
+    auto NextCh = PP.peek();
+    if (NextCh && *NextCh == '/') {
+      ++PP;
+      return createView(__pn_.data(), &PP.RawEntry.back());
+    }
+    return PP.RawEntry;
+  }
+  if (PP.State == PathParser::PS_InRootDir)
+    return *PP;
+  return {};
+}
+
+static bool ConsumeRootName(PathParser *PP) {
+  static_assert(PathParser::PS_BeforeBegin == 1 &&
+      PathParser::PS_InRootName == 2,
+      "Values for enums are incorrect");
+  while (PP->State <= PathParser::PS_InRootName)
+    ++(*PP);
+  return PP->State == PathParser::PS_AtEnd;
+}
+
+static bool ConsumeRootDir(PathParser* PP) {
+  static_assert(PathParser::PS_BeforeBegin == 1 &&
+                PathParser::PS_InRootName == 2 &&
+                PathParser::PS_InRootDir == 3, "Values for enums are incorrect");
+  while (PP->State <= PathParser::PS_InRootDir)
+    ++(*PP);
+  return PP->State == PathParser::PS_AtEnd;
+}
+
+string_view_t path::__relative_path() const {
+  auto PP = PathParser::CreateBegin(__pn_);
+  if (ConsumeRootDir(&PP))
+    return {};
+  return createView(PP.RawEntry.data(), &__pn_.back());
+}
+
+string_view_t path::__parent_path() const {
+  if (empty())
+    return {};
+  // Determine if we have a root path but not a relative path. In that case
+  // return *this.
+  {
+    auto PP = PathParser::CreateBegin(__pn_);
+    if (ConsumeRootDir(&PP))
+      return __pn_;
+  }
+  // Otherwise remove a single element from the end of the path, and return
+  // a string representing that path
+  {
+    auto PP = PathParser::CreateEnd(__pn_);
+    --PP;
+    if (PP.RawEntry.data() == __pn_.data())
+      return {};
+    --PP;
+    return createView(__pn_.data(), &PP.RawEntry.back());
+  }
+}
+
+string_view_t path::__filename() const {
+  if (empty())
+    return {};
+  {
+    PathParser PP = PathParser::CreateBegin(__pn_);
+    if (ConsumeRootDir(&PP))
+      return {};
+  }
+  return *(--PathParser::CreateEnd(__pn_));
+}
+
+string_view_t path::__stem() const {
+  return parser::separate_filename(__filename()).first;
+}
+
+string_view_t path::__extension() const {
+  return parser::separate_filename(__filename()).second;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// path.gen
+
+enum PathPartKind : unsigned char {
+  PK_None,
+  PK_RootSep,
+  PK_Filename,
+  PK_Dot,
+  PK_DotDot,
+  PK_TrailingSep
+};
+
+static PathPartKind ClassifyPathPart(string_view_t Part) {
+  if (Part.empty())
+    return PK_TrailingSep;
+  if (Part == ".")
+    return PK_Dot;
+  if (Part == "..")
+    return PK_DotDot;
+  if (Part == "/")
+    return PK_RootSep;
+  return PK_Filename;
+}
+
+path path::lexically_normal() const {
+  if (__pn_.empty())
+    return *this;
+
+  using PartKindPair = pair<string_view_t, PathPartKind>;
+  vector<PartKindPair> Parts;
+  // Guess as to how many elements the path has to avoid reallocating.
+  Parts.reserve(32);
+
+  // Track the total size of the parts as we collect them. This allows the
+  // resulting path to reserve the correct amount of memory.
+  size_t NewPathSize = 0;
+  auto AddPart = [&](PathPartKind K, string_view_t P) {
+    NewPathSize += P.size();
+    Parts.emplace_back(P, K);
+  };
+  auto LastPartKind = [&]() {
+    if (Parts.empty())
+      return PK_None;
+    return Parts.back().second;
+  };
+
+  bool MaybeNeedTrailingSep = false;
+  // Build a stack containing the remaining elements of the path, popping off
+  // elements which occur before a '..' entry.
+  for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) {
+    auto Part = *PP;
+    PathPartKind Kind = ClassifyPathPart(Part);
+    switch (Kind) {
+    case PK_Filename:
+    case PK_RootSep: {
+      // Add all non-dot and non-dot-dot elements to the stack of elements.
+      AddPart(Kind, Part);
+      MaybeNeedTrailingSep = false;
+      break;
+    }
+    case PK_DotDot: {
+      // Only push a ".." element if there are no elements preceding the "..",
+      // or if the preceding element is itself "..".
+      auto LastKind = LastPartKind();
+      if (LastKind == PK_Filename) {
+        NewPathSize -= Parts.back().first.size();
+        Parts.pop_back();
+      } else if (LastKind != PK_RootSep)
+        AddPart(PK_DotDot, "..");
+      MaybeNeedTrailingSep = LastKind == PK_Filename;
+      break;
+    }
+    case PK_Dot:
+    case PK_TrailingSep: {
+      MaybeNeedTrailingSep = true;
+      break;
+    }
+    case PK_None:
+      _LIBCPP_UNREACHABLE();
+    }
+  }
+  // [fs.path.generic]p6.8: If the path is empty, add a dot.
+  if (Parts.empty())
+    return ".";
+
+  // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any
+  // trailing directory-separator.
+  bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename;
+
+  path Result;
+  Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
+  for (auto& PK : Parts)
+    Result /= PK.first;
+
+  if (NeedTrailingSep)
+    Result /= "";
+
+  return Result;
+}
+
+static int DetermineLexicalElementCount(PathParser PP) {
+  int Count = 0;
+  for (; PP; ++PP) {
+    auto Elem = *PP;
+    if (Elem == "..")
+      --Count;
+    else if (Elem != "." && Elem != "")
+      ++Count;
+  }
+  return Count;
+}
+
+path path::lexically_relative(const path& base) const {
+  { // perform root-name/root-directory mismatch checks
+    auto PP = PathParser::CreateBegin(__pn_);
+    auto PPBase = PathParser::CreateBegin(base.__pn_);
+    auto CheckIterMismatchAtBase = [&]() {
+      return PP.State != PPBase.State &&
+             (PP.inRootPath() || PPBase.inRootPath());
+    };
+    if (PP.inRootName() && PPBase.inRootName()) {
+      if (*PP != *PPBase)
+        return {};
+    } else if (CheckIterMismatchAtBase())
+      return {};
+
+    if (PP.inRootPath())
+      ++PP;
+    if (PPBase.inRootPath())
+      ++PPBase;
+    if (CheckIterMismatchAtBase())
+      return {};
+  }
+
+  // Find the first mismatching element
+  auto PP = PathParser::CreateBegin(__pn_);
+  auto PPBase = PathParser::CreateBegin(base.__pn_);
+  while (PP && PPBase && PP.State == PPBase.State && *PP == *PPBase) {
+    ++PP;
+    ++PPBase;
+  }
+
+  // If there is no mismatch, return ".".
+  if (!PP && !PPBase)
+    return ".";
+
+  // Otherwise, determine the number of elements, 'n', which are not dot or
+  // dot-dot minus the number of dot-dot elements.
+  int ElemCount = DetermineLexicalElementCount(PPBase);
+  if (ElemCount < 0)
+    return {};
+
+  // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise
+  if (ElemCount == 0 && (PP.atEnd() || *PP == ""))
+    return ".";
+
+  // return a path constructed with 'n' dot-dot elements, followed by the
+  // elements of '*this' after the mismatch.
+  path Result;
+  // FIXME: Reserve enough room in Result that it won't have to re-allocate.
+  while (ElemCount--)
+    Result /= "..";
+  for (; PP; ++PP)
+    Result /= *PP;
+  return Result;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// path.comparisons
+static int CompareRootName(PathParser *LHS, PathParser *RHS) {
+  if (!LHS->inRootName() && !RHS->inRootName())
+    return 0;
+
+  auto GetRootName = [](PathParser *Parser) -> string_view_t {
+    return Parser->inRootName() ? **Parser : "";
+  };
+  int res = GetRootName(LHS).compare(GetRootName(RHS));
+  ConsumeRootName(LHS);
+  ConsumeRootName(RHS);
+  return res;
+}
+
+static int CompareRootDir(PathParser *LHS, PathParser *RHS) {
+  if (!LHS->inRootDir() && RHS->inRootDir())
+    return -1;
+  else if (LHS->inRootDir() && !RHS->inRootDir())
+    return 1;
+  else {
+    ConsumeRootDir(LHS);
+    ConsumeRootDir(RHS);
+    return 0;
+  }
+}
+
+static int CompareRelative(PathParser *LHSPtr, PathParser *RHSPtr) {
+  auto &LHS = *LHSPtr;
+  auto &RHS = *RHSPtr;
+
+  int res;
+  while (LHS && RHS) {
+    if ((res = (*LHS).compare(*RHS)) != 0)
+      return res;
+    ++LHS;
+    ++RHS;
+  }
+  return 0;
+}
+
+static int CompareEndState(PathParser *LHS, PathParser *RHS) {
+  if (LHS->atEnd() && !RHS->atEnd())
+    return -1;
+  else if (!LHS->atEnd() && RHS->atEnd())
+    return 1;
+  return 0;
+}
+
+int path::__compare(string_view_t __s) const {
+  auto LHS = PathParser::CreateBegin(__pn_);
+  auto RHS = PathParser::CreateBegin(__s);
+  int res;
+
+  if ((res = CompareRootName(&LHS, &RHS)) != 0)
+    return res;
+
+  if ((res = CompareRootDir(&LHS, &RHS)) != 0)
+    return res;
+
+  if ((res = CompareRelative(&LHS, &RHS)) != 0)
+    return res;
+
+  return CompareEndState(&LHS, &RHS);
+}
+
+////////////////////////////////////////////////////////////////////////////
+// path.nonmembers
+size_t hash_value(const path& __p) noexcept {
+  auto PP = PathParser::CreateBegin(__p.native());
+  size_t hash_value = 0;
+  hash<string_view_t> hasher;
+  while (PP) {
+    hash_value = __hash_combine(hash_value, hasher(*PP));
+    ++PP;
+  }
+  return hash_value;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// path.itr
+path::iterator path::begin() const {
+  auto PP = PathParser::CreateBegin(__pn_);
+  iterator it;
+  it.__path_ptr_ = this;
+  it.__state_ = static_cast<path::iterator::_ParserState>(PP.State);
+  it.__entry_ = PP.RawEntry;
+  it.__stashed_elem_.__assign_view(*PP);
+  return it;
+}
+
+path::iterator path::end() const {
+  iterator it{};
+  it.__state_ = path::iterator::_AtEnd;
+  it.__path_ptr_ = this;
+  return it;
+}
+
+path::iterator& path::iterator::__increment() {
+  PathParser PP(__path_ptr_->native(), __entry_, __state_);
+  ++PP;
+  __state_ = static_cast<_ParserState>(PP.State);
+  __entry_ = PP.RawEntry;
+  __stashed_elem_.__assign_view(*PP);
+  return *this;
+}
+
+path::iterator& path::iterator::__decrement() {
+  PathParser PP(__path_ptr_->native(), __entry_, __state_);
+  --PP;
+  __state_ = static_cast<_ParserState>(PP.State);
+  __entry_ = PP.RawEntry;
+  __stashed_elem_.__assign_view(*PP);
+  return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//                           directory entry definitions
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _LIBCPP_WIN32API
+error_code directory_entry::__do_refresh() noexcept {
+  __data_.__reset();
+  error_code failure_ec;
+
+  StatT full_st;
+  file_status st = detail::posix_lstat(__p_, full_st, &failure_ec);
+  if (!status_known(st)) {
+    __data_.__reset();
+    return failure_ec;
+  }
+
+  if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
+    __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
+    __data_.__type_ = st.type();
+    __data_.__non_sym_perms_ = st.permissions();
+  } else { // we have a symlink
+    __data_.__sym_perms_ = st.permissions();
+    // Get the information about the linked entity.
+    // Ignore errors from stat, since we don't want errors regarding symlink
+    // resolution to be reported to the user.
+    error_code ignored_ec;
+    st = detail::posix_stat(__p_, full_st, &ignored_ec);
+
+    __data_.__type_ = st.type();
+    __data_.__non_sym_perms_ = st.permissions();
+
+    // If we failed to resolve the link, then only partially populate the
+    // cache.
+    if (!status_known(st)) {
+      __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
+      return error_code{};
+    }
+    // Otherwise, we resolved the link, potentially as not existing.
+    // That's OK.
+    __data_.__cache_type_ = directory_entry::_RefreshSymlink;
+  }
+
+  if (_VSTD_FS::is_regular_file(st))
+    __data_.__size_ = static_cast<uintmax_t>(full_st.st_size);
+
+  if (_VSTD_FS::exists(st)) {
+    __data_.__nlink_ = static_cast<uintmax_t>(full_st.st_nlink);
+
+    // Attempt to extract the mtime, and fail if it's not representable using
+    // file_time_type. For now we ignore the error, as we'll report it when
+    // the value is actually used.
+    error_code ignored_ec;
+    __data_.__write_time_ =
+        __extract_last_write_time(__p_, full_st, &ignored_ec);
+  }
+
+  return failure_ec;
+}
+#else
+error_code directory_entry::__do_refresh() noexcept {
+  __data_.__reset();
+  error_code failure_ec;
+
+  file_status st = _VSTD_FS::symlink_status(__p_, failure_ec);
+  if (!status_known(st)) {
+    __data_.__reset();
+    return failure_ec;
+  }
+
+  if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
+    __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
+    __data_.__type_ = st.type();
+    __data_.__non_sym_perms_ = st.permissions();
+  } else { // we have a symlink
+    __data_.__sym_perms_ = st.permissions();
+    // Get the information about the linked entity.
+    // Ignore errors from stat, since we don't want errors regarding symlink
+    // resolution to be reported to the user.
+    error_code ignored_ec;
+    st = _VSTD_FS::status(__p_, ignored_ec);
+
+    __data_.__type_ = st.type();
+    __data_.__non_sym_perms_ = st.permissions();
+
+    // If we failed to resolve the link, then only partially populate the
+    // cache.
+    if (!status_known(st)) {
+      __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
+      return error_code{};
+    }
+    __data_.__cache_type_ = directory_entry::_RefreshSymlink;
+  }
+
+  // FIXME: This is currently broken, and the implementation only a placeholder.
+  // We need to cache last_write_time, file_size, and hard_link_count here before
+  // the implementation actually works.
+
+  return failure_ec;
+}
+#endif
+
+#ifndef _LIBAUTO_UNDEF_VSTD_FS
+#pragma pop_macro("_VSTD_FS")
+#else
+#undef _VSTD
+#undef _LIBAUTO_UNDEF_VSTD_FS
+#endif
+}  // namespace android::hardware::automotive::filesystem
+/* clang-format on */
diff --git a/automotive/can/1.0/default/libnetdevice/Android.bp b/automotive/can/1.0/default/libnetdevice/Android.bp
new file mode 100644
index 0000000..31e5ad0
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/Android.bp
@@ -0,0 +1,30 @@
+//
+// 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_library_static {
+    name: "android.hardware.automotive.can@libnetdevice",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    vendor_available: true,
+    relative_install_path: "hw",
+    srcs: [
+        "NetlinkRequest.cpp",
+        "NetlinkSocket.cpp",
+        "can.cpp",
+        "common.cpp",
+        "libnetdevice.cpp",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
new file mode 100644
index 0000000..556debf
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 "NetlinkRequest.h"
+
+#include <android-base/logging.h>
+
+namespace android::netdevice::impl {
+
+static struct rtattr* nlmsg_tail(struct nlmsghdr* n) {
+    return reinterpret_cast<struct rtattr*>(  //
+            reinterpret_cast<uintptr_t>(n) + NLMSG_ALIGN(n->nlmsg_len));
+}
+
+struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
+                         size_t dataLen) {
+    size_t newLen = NLMSG_ALIGN(n->nlmsg_len) + RTA_SPACE(dataLen);
+    if (newLen > maxLen) {
+        LOG(ERROR) << "addattr_l failed - exceeded maxLen: " << newLen << " > " << maxLen;
+        return nullptr;
+    }
+
+    auto attr = nlmsg_tail(n);
+    attr->rta_len = RTA_SPACE(dataLen);
+    attr->rta_type = type;
+    if (dataLen > 0) memcpy(RTA_DATA(attr), data, dataLen);
+
+    n->nlmsg_len = newLen;
+    return attr;
+}
+
+struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type) {
+    return addattr_l(n, maxLen, type, nullptr, 0);
+}
+
+void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest) {
+    size_t nestLen = reinterpret_cast<uintptr_t>(nlmsg_tail(n)) - reinterpret_cast<uintptr_t>(nest);
+    nest->rta_len = nestLen;
+}
+
+}  // namespace android::netdevice::impl
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
new file mode 100644
index 0000000..3e28d78
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <linux/rtnetlink.h>
+
+#include <string>
+
+namespace android::netdevice {
+
+typedef unsigned short rtattrtype_t;  // as in rtnetlink.h
+typedef __u16 nlmsgtype_t;            // as in netlink.h
+
+/** Implementation details, do not use outside NetlinkRequest template. */
+namespace impl {
+
+struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
+                         size_t dataLen);
+struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type);
+void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest);
+
+}  // namespace impl
+
+/**
+ * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
+ *
+ * \param T specific message header (such as struct ifinfomsg)
+ * \param BUFSIZE how much space to reserve for payload (not counting the header size)
+ */
+template <class T, unsigned int BUFSIZE = 128>
+struct NetlinkRequest {
+    /**
+     * Create empty message.
+     *
+     * \param type Message type (such as RTM_NEWLINK)
+     * \param flags Message flags (such as NLM_F_REQUEST)
+     */
+    NetlinkRequest(nlmsgtype_t type, uint16_t flags) {
+        mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data));
+        mRequest.nlmsg.nlmsg_type = type;
+        mRequest.nlmsg.nlmsg_flags = flags;
+    }
+
+    /** \return pointer to raw netlink message header. */
+    struct nlmsghdr* header() {
+        return &mRequest.nlmsg;
+    }
+    /** Reference to message-specific header. */
+    T& data() { return mRequest.data; }
+
+    /**
+     * Adds an attribute of a simple type.
+     *
+     * If this method fails (i.e. due to insufficient space), the message will be marked
+     * as bad (\see isGood).
+     *
+     * \param type attribute type (such as IFLA_IFNAME)
+     * \param attr attribute data
+     */
+    template <class A>
+    void addattr(rtattrtype_t type, const A& attr) {
+        if (!mIsGood) return;
+        auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr));
+        if (ap == nullptr) mIsGood = false;
+    }
+
+    template <>
+    void addattr(rtattrtype_t type, const std::string& s) {
+        if (!mIsGood) return;
+        auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1);
+        if (ap == nullptr) mIsGood = false;
+    }
+
+    /** Guard class to frame nested attributes. See nest(int). */
+    struct Nest {
+        Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
+        ~Nest() { mReq.nestEnd(mAttr); }
+
+      private:
+        NetlinkRequest& mReq;
+        struct rtattr* mAttr;
+
+        DISALLOW_COPY_AND_ASSIGN(Nest);
+    };
+
+    /**
+     * Add nested attribute.
+     *
+     * The returned object is a guard for auto-nesting children inside the argument attribute.
+     * When the Nest object goes out of scope, the nesting attribute is closed.
+     *
+     * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
+     * inside IFLA_LINKINFO:
+     *    NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+     *    {
+     *        auto linkinfo = req.nest(IFLA_LINKINFO);
+     *        req.addattr(IFLA_INFO_KIND, "can");
+     *        {
+     *            auto infodata = req.nest(IFLA_INFO_DATA);
+     *            req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct);
+     *        }
+     *    }
+     *    // use req
+     *
+     * \param type attribute type (such as IFLA_LINKINFO)
+     */
+    Nest nest(int type) { return Nest(*this, type); }
+
+    /**
+     * Indicates, whether the message is in a good state.
+     *
+     * The bad state is usually a result of payload buffer being too small.
+     * You can modify BUFSIZE template parameter to fix this.
+     */
+    bool isGood() const { return mIsGood; }
+
+  private:
+    bool mIsGood = true;
+
+    struct {
+        struct nlmsghdr nlmsg;
+        T data;
+        char buf[BUFSIZE];
+    } mRequest = {};
+
+    struct rtattr* nestStart(rtattrtype_t type) {
+        if (!mIsGood) return nullptr;
+        auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type);
+        if (attr == nullptr) mIsGood = false;
+        return attr;
+    }
+
+    void nestEnd(struct rtattr* nest) {
+        if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest);
+    }
+};
+
+}  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
new file mode 100644
index 0000000..7817169
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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 "NetlinkSocket.h"
+
+#include <android-base/logging.h>
+
+namespace android::netdevice {
+
+NetlinkSocket::NetlinkSocket(int protocol) {
+    mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
+    if (!mFd.ok()) {
+        PLOG(ERROR) << "Can't open Netlink socket";
+        mFailed = true;
+        return;
+    }
+
+    struct sockaddr_nl sa = {};
+    sa.nl_family = AF_NETLINK;
+
+    if (bind(mFd.get(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)) < 0) {
+        PLOG(ERROR) << "Can't bind Netlink socket";
+        mFd.reset();
+        mFailed = true;
+    }
+}
+
+bool NetlinkSocket::send(struct nlmsghdr* nlmsg) {
+    if (mFailed) return false;
+
+    nlmsg->nlmsg_pid = 0;  // kernel
+    nlmsg->nlmsg_seq = mSeq++;
+    nlmsg->nlmsg_flags |= NLM_F_ACK;
+
+    struct iovec iov = {nlmsg, nlmsg->nlmsg_len};
+
+    struct sockaddr_nl sa = {};
+    sa.nl_family = AF_NETLINK;
+
+    struct msghdr msg = {};
+    msg.msg_name = &sa;
+    msg.msg_namelen = sizeof(sa);
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+
+    if (sendmsg(mFd.get(), &msg, 0) < 0) {
+        PLOG(ERROR) << "Can't send Netlink message";
+        return false;
+    }
+    return true;
+}
+
+bool NetlinkSocket::receiveAck() {
+    if (mFailed) return false;
+
+    char buf[8192];
+
+    struct sockaddr_nl sa;
+    struct iovec iov = {buf, sizeof(buf)};
+
+    struct msghdr msg = {};
+    msg.msg_name = &sa;
+    msg.msg_namelen = sizeof(sa);
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+
+    const ssize_t status = recvmsg(mFd.get(), &msg, 0);
+    if (status < 0) {
+        PLOG(ERROR) << "Failed to receive Netlink message";
+        return false;
+    }
+    size_t remainingLen = status;
+
+    if (msg.msg_flags & MSG_TRUNC) {
+        LOG(ERROR) << "Failed to receive Netlink message: truncated";
+        return false;
+    }
+
+    for (auto nlmsg = reinterpret_cast<struct nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
+         nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) {
+        // We're looking for error/ack message only, ignoring others.
+        if (nlmsg->nlmsg_type != NLMSG_ERROR) {
+            LOG(WARNING) << "Received unexpected Netlink message (ignored): " << nlmsg->nlmsg_type;
+            continue;
+        }
+
+        // Found error/ack message, return status.
+        auto nlerr = reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(nlmsg));
+        if (nlerr->error != 0) {
+            LOG(ERROR) << "Received Netlink error message: " << nlerr->error;
+            return false;
+        }
+        return true;
+    }
+    // Couldn't find any error/ack messages.
+    return false;
+}
+
+}  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
new file mode 100644
index 0000000..2b40ea2
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "NetlinkRequest.h"
+
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+
+#include <linux/netlink.h>
+
+namespace android::netdevice {
+
+/**
+ * A wrapper around AF_NETLINK sockets.
+ *
+ * This class is not thread safe to use a single instance between multiple threads, but it's fine to
+ * use multiple instances over multiple threads.
+ */
+struct NetlinkSocket {
+    NetlinkSocket(int protocol);
+
+    /**
+     * Send Netlink message to Kernel.
+     *
+     * \param msg Message to send, nlmsg_seq will be set to next sequence number
+     * \return true, if succeeded
+     */
+    template <class T, unsigned int BUFSIZE>
+    bool send(NetlinkRequest<T, BUFSIZE>& req) {
+        if (!req.isGood()) return false;
+        return send(req.header());
+    }
+
+    /**
+     * Receive Netlink ACK message from Kernel.
+     *
+     * \return true if received ACK message, false in case of error
+     */
+    bool receiveAck();
+
+  private:
+    uint32_t mSeq = 0;
+    base::unique_fd mFd;
+    bool mFailed = false;
+
+    bool send(struct nlmsghdr* msg);
+
+    DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
+};
+
+}  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
new file mode 100644
index 0000000..a2a85dc
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 <libnetdevice/libnetdevice.h>
+
+#include "NetlinkRequest.h"
+#include "NetlinkSocket.h"
+#include "common.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include <linux/can.h>
+#include <linux/can/error.h>
+#include <linux/can/netlink.h>
+#include <linux/can/raw.h>
+
+namespace android::netdevice::can {
+
+static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK;
+
+base::unique_fd socket(const std::string& ifname) {
+    struct sockaddr_can addr = {};
+    addr.can_family = AF_CAN;
+    addr.can_ifindex = nametoindex(ifname);
+    if (addr.can_ifindex == 0) {
+        LOG(ERROR) << "Interface " << ifname << " doesn't exists";
+        return {};
+    }
+
+    base::unique_fd sock(::socket(PF_CAN, SOCK_RAW, CAN_RAW));
+    if (!sock.ok()) {
+        LOG(ERROR) << "Failed to create CAN socket";
+        return {};
+    }
+
+    if (setsockopt(sock.get(), SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &kErrMask, sizeof(kErrMask)) < 0) {
+        PLOG(ERROR) << "Can't receive error frames, CAN setsockpt failed";
+        return {};
+    }
+
+    if (0 != fcntl(sock.get(), F_SETFL, O_RDWR | O_NONBLOCK)) {
+        LOG(ERROR) << "Couldn't put CAN socket in non-blocking mode";
+        return {};
+    }
+
+    if (0 != bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
+        LOG(ERROR) << "Can't bind to CAN interface " << ifname;
+        return {};
+    }
+
+    return sock;
+}
+
+bool setBitrate(std::string ifname, uint32_t bitrate) {
+    struct can_bittiming bt = {};
+    bt.bitrate = bitrate;
+
+    NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+
+    const auto ifidx = nametoindex(ifname);
+    if (ifidx == 0) {
+        LOG(ERROR) << "Can't find interface " << ifname;
+        return false;
+    }
+    req.data().ifi_index = ifidx;
+
+    {
+        auto linkinfo = req.nest(IFLA_LINKINFO);
+        req.addattr(IFLA_INFO_KIND, "can");
+        {
+            auto infodata = req.nest(IFLA_INFO_DATA);
+            /* For CAN FD, it would require to add IFLA_CAN_DATA_BITTIMING
+             * and IFLA_CAN_CTRLMODE as well. */
+            req.addattr(IFLA_CAN_BITTIMING, bt);
+        }
+    }
+
+    NetlinkSocket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck();
+}
+
+}  // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp
new file mode 100644
index 0000000..5c62443
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "common.h"
+
+#include <android-base/logging.h>
+
+#include <net/if.h>
+
+namespace android::netdevice {
+
+unsigned int nametoindex(const std::string& ifname) {
+    const auto ifidx = if_nametoindex(ifname.c_str());
+    if (ifidx != 0) return ifidx;
+
+    const auto err = errno;
+    if (err != ENODEV) {
+        LOG(ERROR) << "if_nametoindex(" << ifname << ") failed: " << err;
+    }
+    return 0;
+}
+
+}  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
new file mode 100644
index 0000000..8097f37
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android::netdevice {
+
+/**
+ * Returns the index of a given network interface.
+ *
+ * If the syscall to check the index fails with other error than ENODEV, it gets logged and the
+ * return value indicates the interface doesn't exists.
+ *
+ * \param ifname Interface to check
+ * \return Interface index, or 0 if the interface doesn't exist
+ */
+unsigned int nametoindex(const std::string& ifname);
+
+}  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
new file mode 100644
index 0000000..3886acf
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+
+#include <string>
+
+namespace android::netdevice::can {
+
+/**
+ * Opens and binds SocketCAN socket.
+ *
+ * \param ifname Interface to open a socket against
+ * \return Socket's FD or -1 in case of failure
+ */
+base::unique_fd socket(const std::string& ifname);
+
+/**
+ * Sets CAN interface bitrate.
+ *
+ * \param ifname Interface for which the bitrate is to be set
+ * \return true on success, false on failure
+ */
+bool setBitrate(std::string ifname, uint32_t bitrate);
+
+}  // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
new file mode 100644
index 0000000..3818a31
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+
+namespace android::netdevice {
+
+/**
+ * Checks, if the network interface exists.
+ *
+ * \param ifname Interface to check
+ * \return true if it exists, false otherwise
+ */
+bool exists(std::string ifname);
+
+/**
+ * Checks if network interface is up.
+ *
+ * \param ifname Interface to check
+ * \return true/false if the check succeeded, nullopt otherwise
+ */
+std::optional<bool> isUp(std::string ifname);
+
+/**
+ * Brings network interface up.
+ *
+ * \param ifname Interface to bring up
+ * \return true in case of success, false otherwise
+ */
+bool up(std::string ifname);
+
+/**
+ * Brings network interface down.
+ *
+ * \param ifname Interface to bring down
+ * \return true in case of success, false otherwise
+ */
+bool down(std::string ifname);
+
+/**
+ * Adds virtual link.
+ *
+ * \param dev the name of the new virtual device
+ * \param type the type of the new device
+ * \return true in case of success, false otherwise
+ */
+bool add(std::string dev, std::string type);
+
+/**
+ * Deletes virtual link.
+ *
+ * \param dev the name of the device to remove
+ * \return true in case of success, false otherwise
+ */
+bool del(std::string dev);
+
+}  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
new file mode 100644
index 0000000..b051442
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 <libnetdevice/libnetdevice.h>
+
+#include "NetlinkRequest.h"
+#include "NetlinkSocket.h"
+#include "common.h"
+
+#include <android-base/logging.h>
+
+#include <linux/can.h>
+#include <net/if.h>
+
+namespace android::netdevice {
+
+bool exists(std::string ifname) {
+    return nametoindex(ifname) != 0;
+}
+
+static bool sendIfreq(unsigned long request, struct ifreq& ifr) {
+    /* For general interfaces it would be socket(AF_INET, SOCK_DGRAM, 0),
+     * but SEPolicy forces us to limit our flexibility here. */
+    base::unique_fd sock(socket(PF_CAN, SOCK_RAW, CAN_RAW));
+    if (!sock.ok()) {
+        LOG(ERROR) << "Can't create socket";
+        return false;
+    }
+
+    if (ioctl(sock.get(), request, &ifr) < 0) {
+        PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
+        return false;
+    }
+
+    return true;
+}
+
+static struct ifreq ifreqFromName(const std::string& ifname) {
+    struct ifreq ifr = {};
+    strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
+    return ifr;
+}
+
+std::optional<bool> isUp(std::string ifname) {
+    struct ifreq ifr = ifreqFromName(ifname);
+    if (!sendIfreq(SIOCGIFFLAGS, ifr)) return std::nullopt;
+    return ifr.ifr_flags & IFF_UP;
+}
+
+bool up(std::string ifname) {
+    struct ifreq ifr = ifreqFromName(ifname);
+    if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+    ifr.ifr_flags |= IFF_UP;
+    return sendIfreq(SIOCSIFFLAGS, ifr);
+}
+
+bool down(std::string ifname) {
+    struct ifreq ifr = ifreqFromName(ifname);
+    if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+    ifr.ifr_flags &= ~IFF_UP;
+    return sendIfreq(SIOCSIFFLAGS, ifr);
+}
+
+bool add(std::string dev, std::string type) {
+    NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
+    req.addattr(IFLA_IFNAME, dev);
+
+    {
+        auto linkinfo = req.nest(IFLA_LINKINFO);
+        req.addattr(IFLA_INFO_KIND, type);
+    }
+
+    NetlinkSocket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck();
+}
+
+bool del(std::string dev) {
+    NetlinkRequest<struct ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST);
+    req.addattr(IFLA_IFNAME, dev);
+
+    NetlinkSocket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck();
+}
+
+}  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp
new file mode 100644
index 0000000..b52a54a
--- /dev/null
+++ b/automotive/can/1.0/default/service.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 "CanController.h"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+static void canControllerService() {
+    base::SetDefaultTag("CanController");
+    base::SetMinimumLogSeverity(android::base::VERBOSE);
+    configureRpcThreadpool(16, true);
+    LOG(DEBUG) << "CAN controller service starting...";
+
+    sp<CanController> canController(new CanController);
+    if (canController->registerAsService("socketcan") != OK) {
+        LOG(FATAL) << "Failed to register CAN controller";
+        return;
+    }
+
+    LOG(INFO) << "CAN controller service ready";
+    joinRpcThreadpool();
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation
+
+int main() {
+    ::android::hardware::automotive::can::V1_0::implementation::canControllerService();
+    return 1;  // canBusService (joinRpcThreadpool) shouldn't exit
+}
diff --git a/automotive/can/1.0/hidl-utils/Android.bp b/automotive/can/1.0/hidl-utils/Android.bp
new file mode 100644
index 0000000..63b07c9
--- /dev/null
+++ b/automotive/can/1.0/hidl-utils/Android.bp
@@ -0,0 +1,21 @@
+//
+// 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_library_headers {
+    name: "android.hardware.automotive.can@hidl-utils-lib",
+    export_include_dirs: ["include"],
+    vendor_available: true,
+}
diff --git a/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
new file mode 100644
index 0000000..f63d43c
--- /dev/null
+++ b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+namespace android::hardware::automotive::hidl_utils {
+
+/**
+ * Helper functor to fetch results from multi-return HIDL calls.
+ * It's meant to be used in place of _hidl_cb callbacks.
+ *
+ * Please note extracting these return variables outside of the callback scope requires making
+ * a copy of each return variable. This may be costly for frequently called HIDL methods with
+ * non-negligible return object size. Please be cautious about performance when using this.
+ *
+ * Example usage:
+ *     Result result;
+ *     sp<ISomeInterface> iface;
+ *     hidlObject->someMethod(arg1, arg2, hidl_utils::fill(&result, &iface)).assertOk();
+ *     // use result and iface
+ */
+template <typename... T>
+struct fill : public std::function<void(const T&...)> {
+    /**
+     * Create _hidl_cb functor that copies the call arguments to specified pointers.
+     *
+     * \param args... Targets to copy the call arguments to
+     */
+    fill(T*... args) : mTargets(args...) {}
+
+    void operator()(const T&... args) { copy<0, T...>(args...); }
+
+  private:
+    std::tuple<T*...> mTargets;
+
+    template <int Pos, typename First>
+    inline void copy(const First& first) {
+        *std::get<Pos>(mTargets) = first;
+    }
+
+    template <int Pos, typename First, typename... Rest>
+    inline void copy(const First& first, const Rest&... rest) {
+        *std::get<Pos>(mTargets) = first;
+        copy<Pos + 1, Rest...>(rest...);
+    }
+};
+
+}  // namespace android::hardware::automotive::hidl_utils
diff --git a/automotive/can/1.0/tools/Android.bp b/automotive/can/1.0/tools/Android.bp
new file mode 100644
index 0000000..a6c40d9
--- /dev/null
+++ b/automotive/can/1.0/tools/Android.bp
@@ -0,0 +1,66 @@
+//
+// 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: "canhalctrl",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "canhalctrl.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+    ],
+    header_libs: [
+        "android.hardware.automotive.can@hidl-utils-lib",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@libcanhaltools",
+    ],
+}
+
+cc_binary {
+    name: "canhaldump",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "canhaldump.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+    ],
+    header_libs: [
+        "android.hardware.automotive.can@hidl-utils-lib",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@libcanhaltools",
+    ],
+}
+
+cc_binary {
+    name: "canhalsend",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "canhalsend.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@libcanhaltools",
+    ],
+}
diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp
new file mode 100644
index 0000000..bf1c3b1
--- /dev/null
+++ b/automotive/can/1.0/tools/canhalctrl.cpp
@@ -0,0 +1,178 @@
+/*
+ * 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 <android-base/parseint.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl-utils/hidl-utils.h>
+#include <libcanhaltools/libcanhaltools.h>
+
+#include <iostream>
+#include <string>
+
+namespace android::hardware::automotive::can {
+
+using ICanController = V1_0::ICanController;
+
+static void usage() {
+    std::cerr << "CAN bus HAL Control tool" << std::endl;
+    std::cerr << std::endl << "usage:" << std::endl << std::endl;
+    std::cerr << "canhalctrl up <bus name> <type> <interface> [bitrate]" << std::endl;
+    std::cerr << "where:" << std::endl;
+    std::cerr << " bus name - name under which ICanBus will be published" << std::endl;
+    std::cerr << " type - one of: virtual, socketcan, slcan, indexed" << std::endl;
+    std::cerr << " interface - hardware identifier (like can0, vcan0, /dev/ttyUSB0)" << std::endl;
+    std::cerr << " bitrate - such as 100000, 125000, 250000, 500000" << std::endl;
+    std::cerr << std::endl;
+    std::cerr << "canhalctrl down <bus name>" << std::endl;
+    std::cerr << "where:" << std::endl;
+    std::cerr << " bus name - name under which ICanBus will be published" << std::endl;
+}
+
+static int up(const std::string& busName, ICanController::InterfaceType type,
+              const std::string& interface, uint32_t bitrate) {
+    bool anySupported = false;
+    for (auto&& service : libcanhaltools::getControlServices()) {
+        auto ctrl = ICanController::getService(service);
+        if (ctrl == nullptr) {
+            std::cerr << "Couldn't open ICanController/" << service;
+            continue;
+        }
+
+        if (!libcanhaltools::isSupported(ctrl, type)) continue;
+        anySupported = true;
+
+        ICanController::BusConfig config = {};
+        config.name = busName;
+        config.bitrate = bitrate;
+
+        // 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) {
+            unsigned idx;
+            if (!android::base::ParseUint(interface, &idx, unsigned(UINT8_MAX))) {
+                std::cerr << "Interface index out of range: " << idx;
+                return -1;
+            }
+            config.interfaceId.indexed({uint8_t(idx)});
+        } else {
+            CHECK(false) << "Unexpected interface type: " << toString(type);
+        }
+
+        const auto upresult = ctrl->upInterface(config);
+        if (upresult == ICanController::Result::OK) return 0;
+        std::cerr << "Failed to bring interface up: " << toString(upresult) << std::endl;
+        // Let's continue the loop to try other controllers.
+    }
+
+    if (!anySupported) {
+        std::cerr << "No controller supports " << toString(type) << std::endl;
+    }
+    return -1;
+}
+
+static int down(const std::string& busName) {
+    for (auto&& service : libcanhaltools::getControlServices()) {
+        auto ctrl = ICanController::getService(service);
+        if (ctrl == nullptr) continue;
+
+        if (ctrl->downInterface(busName)) return 0;
+    }
+
+    std::cerr << "Failed to bring interface " << busName << " down (maybe it's down already?)"
+              << std::endl;
+    return -1;
+}
+
+static std::optional<ICanController::InterfaceType> parseInterfaceType(const std::string& str) {
+    if (str == "virtual") return ICanController::InterfaceType::VIRTUAL;
+    if (str == "socketcan") return ICanController::InterfaceType::SOCKETCAN;
+    if (str == "slcan") return ICanController::InterfaceType::SLCAN;
+    if (str == "indexed") return ICanController::InterfaceType::INDEXED;
+    return std::nullopt;
+}
+
+static int main(int argc, char* argv[]) {
+    base::SetDefaultTag("CanHalControl");
+    base::SetMinimumLogSeverity(android::base::VERBOSE);
+
+    if (argc == 0) {
+        usage();
+        return 0;
+    }
+
+    std::string cmd(argv[0]);
+    argv++;
+    argc--;
+
+    if (cmd == "up") {
+        if (argc < 3 || argc > 4) {
+            std::cerr << "Invalid number of arguments to up command: " << argc << std::endl;
+            usage();
+            return -1;
+        }
+
+        const std::string busName(argv[0]);
+        const std::string typeStr(argv[1]);
+        const std::string interface(argv[2]);
+
+        const auto type = parseInterfaceType(typeStr);
+        if (!type) {
+            std::cerr << "Invalid interface type: " << typeStr << std::endl;
+            usage();
+            return -1;
+        }
+
+        uint32_t bitrate = 0;
+        if (argc == 4 && !android::base::ParseUint(argv[3], &bitrate)) {
+            std::cerr << "Invalid bitrate!" << std::endl;
+            usage();
+            return -1;
+        }
+
+        return up(busName, *type, interface, bitrate);
+    } else if (cmd == "down") {
+        if (argc != 1) {
+            std::cerr << "Invalid number of arguments to down command: " << argc << std::endl;
+            usage();
+            return -1;
+        }
+
+        return down(argv[0]);
+    } else {
+        std::cerr << "Invalid command: " << cmd << std::endl;
+        usage();
+        return -1;
+    }
+}
+
+}  // namespace android::hardware::automotive::can
+
+int main(int argc, char* argv[]) {
+    if (argc < 1) return -1;
+    return ::android::hardware::automotive::can::main(--argc, ++argv);
+}
diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp
new file mode 100644
index 0000000..2f5ca61
--- /dev/null
+++ b/automotive/can/1.0/tools/canhaldump.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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 <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanMessageListener.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl-utils/hidl-utils.h>
+
+#include <linux/can.h>
+#include <chrono>
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <thread>
+
+namespace android::hardware::automotive::can {
+
+using namespace std::chrono_literals;
+
+using ICanBus = V1_0::ICanBus;
+using Result = V1_0::Result;
+
+struct CanMessageListener : public V1_0::ICanMessageListener {
+    const std::string name;
+
+    CanMessageListener(std::string name) : name(name) {}
+
+    virtual Return<void> onReceive(const V1_0::CanMessage& message) {
+        int msgIdWidth = 3;
+        if (message.isExtendedId) msgIdWidth = 8;
+        std::cout << "  " << name << "  " << std::hex << std::uppercase << std::setw(msgIdWidth)
+                  << std::setfill('0') << message.id << std::setw(0);
+        std::cout << "   [" << message.payload.size() << "] ";
+        if (message.remoteTransmissionRequest) {
+            std::cout << "remote request";
+        } else {
+            for (const auto byte : message.payload) {
+                std::cout << " " << std::setfill('0') << std::setw(2) << unsigned(byte);
+            }
+        }
+        std::cout << std::nouppercase << std::dec << std::endl;
+        return {};
+    }
+
+    virtual Return<void> onError(V1_0::ErrorEvent error) {
+        std::cout << "  " << name << "  " << toString(error) << std::endl;
+        return {};
+    }
+};
+
+static void usage() {
+    std::cerr << "canhaldump - dump CAN bus traffic" << std::endl;
+    std::cerr << std::endl << "usage:" << std::endl << std::endl;
+    std::cerr << "canhaldump <bus name>" << std::endl;
+    std::cerr << "where:" << std::endl;
+    std::cerr << " bus name - name under which ICanBus is be published" << std::endl;
+}
+
+// TODO(b/135918744): extract to a new library
+static sp<ICanBus> tryOpen(const std::string& busname) {
+    auto bus = ICanBus::tryGetService(busname);
+    if (bus != nullptr) return bus;
+
+    /* Fallback for interfaces not registered in manifest. For testing purposes only,
+     * one should not depend on this in production deployment. */
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    auto ret = manager->get(ICanBus::descriptor, busname).withDefault(nullptr);
+    if (ret == nullptr) return nullptr;
+
+    std::cerr << "WARNING: bus " << busname << " is not registered in device manifest, "
+              << "trying to fetch it directly..." << std::endl;
+
+    return ICanBus::castFrom(ret);
+}
+
+static int candump(const std::string& busname) {
+    auto bus = tryOpen(busname);
+    if (bus == nullptr) {
+        std::cerr << "Bus " << busname << " is not available" << std::endl;
+        return -1;
+    }
+
+    Result result;
+    sp<V1_0::ICloseHandle> chnd;
+    // TODO(b/135918744): extract to library
+    bus->listen({}, new CanMessageListener(busname), hidl_utils::fill(&result, &chnd)).assertOk();
+
+    if (result != Result::OK) {
+        std::cerr << "Listen call failed: " << toString(result) << std::endl;
+        return -1;
+    }
+
+    while (true) std::this_thread::sleep_for(1h);
+}
+
+static int main(int argc, char* argv[]) {
+    base::SetDefaultTag("CanHalDump");
+    base::SetMinimumLogSeverity(android::base::VERBOSE);
+
+    if (argc == 0) {
+        usage();
+        return 0;
+    }
+
+    if (argc != 1) {
+        std::cerr << "Invalid number of arguments" << std::endl;
+        usage();
+        return -1;
+    }
+
+    return candump(argv[0]);
+}
+
+}  // namespace android::hardware::automotive::can
+
+int main(int argc, char* argv[]) {
+    if (argc < 1) return -1;
+    return ::android::hardware::automotive::can::main(--argc, ++argv);
+}
diff --git a/automotive/can/1.0/tools/canhalsend.cpp b/automotive/can/1.0/tools/canhalsend.cpp
new file mode 100644
index 0000000..f0f9d10
--- /dev/null
+++ b/automotive/can/1.0/tools/canhalsend.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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 <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+#include <iostream>
+#include <string>
+
+namespace android::hardware::automotive::can {
+
+using ICanBus = V1_0::ICanBus;
+using Result = V1_0::Result;
+
+static void usage() {
+    std::cerr << "canhalsend - simple command line tool to send raw CAN frames" << std::endl;
+    std::cerr << std::endl << "usage:" << std::endl << std::endl;
+    std::cerr << "canhalsend <bus name> <can id>#<data>" << std::endl;
+    std::cerr << "where:" << std::endl;
+    std::cerr << " bus name - name under which ICanBus is published" << std::endl;
+    std::cerr << " can id - such as 1a5 or 1fab5982" << std::endl;
+    std::cerr << " data - such as deadbeef, 010203, or R for a remote frame" << std::endl;
+}
+
+// TODO(b/135918744): extract to a new library
+static sp<ICanBus> tryOpen(const std::string& busname) {
+    auto bus = ICanBus::tryGetService(busname);
+    if (bus != nullptr) return bus;
+
+    /* Fallback for interfaces not registered in manifest. For testing purposes only,
+     * one should not depend on this in production deployment. */
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    auto ret = manager->get(ICanBus::descriptor, busname).withDefault(nullptr);
+    if (ret == nullptr) return nullptr;
+
+    std::cerr << "WARNING: bus " << busname << " is not registered in device manifest, "
+              << "trying to fetch it directly..." << std::endl;
+
+    return ICanBus::castFrom(ret);
+}
+
+static int cansend(const std::string& busname, const V1_0::CanMessage& msg) {
+    auto bus = tryOpen(busname);
+    if (bus == nullptr) {
+        std::cerr << "Bus " << busname << " is not available" << std::endl;
+        return -1;
+    }
+
+    const auto result = bus->send(msg);
+    if (result != Result::OK) {
+        std::cerr << "Send call failed: " << toString(result) << std::endl;
+        return -1;
+    }
+    return 0;
+}
+
+static std::optional<V1_0::CanMessage> parseCanMessage(const std::string& msg) {
+    const auto hashpos = msg.find("#");
+    if (hashpos == std::string::npos) return std::nullopt;
+
+    const std::string msgidStr = msg.substr(0, hashpos);
+    const std::string payloadStr = msg.substr(hashpos + 1);
+
+    V1_0::CanMessageId msgid;
+    // "0x" must be prepended to msgidStr, since ParseUint doesn't accept a base argument.
+    if (!android::base::ParseUint("0x" + msgidStr, &msgid)) return std::nullopt;
+
+    V1_0::CanMessage canmsg = {};
+    canmsg.id = msgid;
+    if (msgid > 0x7FF) {
+        canmsg.isExtendedId = true;
+    }
+
+    if (android::base::StartsWith(payloadStr, "R")) {
+        canmsg.remoteTransmissionRequest = true;
+
+        /* The CAN bus HAL doesn't define a data length code (DLC) field, since it is inferrred
+         * from the payload size. RTR messages indicate to the receiver how many bytes they are
+         * expecting to receive back via the DLC sent with the RTR frame. */
+        if (payloadStr.size() <= 1) return canmsg;
+
+        unsigned int dlc = 0;
+
+        /* The maximum DLC for CAN-FD is 64 bytes and CAN 2.0 is 8 bytes. Limit the size of the DLC
+         * to something memory safe and let the HAL determine if the DLC is valid. */
+        if (!android::base::ParseUint(payloadStr.substr(1), &dlc, 10000u)) {
+            std::cerr << "Invalid DLC for RTR frame!" << std::endl;
+            return std::nullopt;
+        }
+        canmsg.payload.resize(dlc);
+        return canmsg;
+    }
+
+    std::vector<uint8_t> payload;
+    if (payloadStr.size() % 2 != 0) return std::nullopt;
+    for (size_t i = 0; i < payloadStr.size(); i += 2) {
+        std::string byteStr(payloadStr, i, 2);
+        uint8_t byteBuf;
+        if (!android::base::ParseUint("0x" + byteStr, &byteBuf)) return std::nullopt;
+        payload.emplace_back(byteBuf);
+    }
+    canmsg.payload = payload;
+
+    return canmsg;
+}
+
+static int main(int argc, char* argv[]) {
+    base::SetDefaultTag("CanHalSend");
+    base::SetMinimumLogSeverity(android::base::VERBOSE);
+
+    if (argc == 0) {
+        usage();
+        return 0;
+    }
+
+    if (argc != 2) {
+        std::cerr << "Invalid number of arguments" << std::endl;
+        usage();
+        return -1;
+    }
+
+    std::string busname(argv[0]);
+    const auto canmsg = parseCanMessage(argv[1]);
+    if (!canmsg) {
+        std::cerr << "Failed to parse CAN message argument" << std::endl;
+        return -1;
+    }
+
+    return cansend(busname, *canmsg);
+}
+
+}  // namespace android::hardware::automotive::can
+
+int main(int argc, char* argv[]) {
+    if (argc < 1) return -1;
+    return ::android::hardware::automotive::can::main(--argc, ++argv);
+}
diff --git a/automotive/can/1.0/tools/configurator/Android.bp b/automotive/can/1.0/tools/configurator/Android.bp
new file mode 100644
index 0000000..2c4bc1d
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/Android.bp
@@ -0,0 +1,34 @@
+//
+// 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: "canhalconfigurator",
+    init_rc: ["canhalconfigurator.rc"],
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "canhalconfigurator.cpp",
+        "canprototools.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+        "libprotobuf-cpp-full",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@1.x-config-format",
+        "android.hardware.automotive.can@libcanhaltools",
+    ],
+}
diff --git a/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp b/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp
new file mode 100644
index 0000000..a100f06
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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 "canbus_config.pb.h"
+#include "canprototools.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <libcanhaltools/libcanhaltools.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android::hardware::automotive::can {
+
+using ICanController = V1_0::ICanController;
+
+/**
+ * Takes output from parsed protobuf config and uses it to configure the CAN HAL.
+ *
+ * \param pb_cfg is an instance of the autogenerated protobuf object for our configuration.
+ * \return boolean status, true on success, false on failure.
+ */
+static bool processPbCfg(const config::CanBusConfig& pb_cfg) {
+    for (auto const& bus : pb_cfg.buses()) {
+        if (bus.name().empty()) {
+            LOG(ERROR) << "Invalid config: Bus config must have a valid name field";
+            return false;
+        }
+
+        LOG(INFO) << "Configure " << bus.name();
+        auto bus_cfg = config::fromPbBus(bus);
+        if (!bus_cfg.has_value()) {
+            return false;
+        }
+
+        // TODO(149405589): remove this sleep and associated includes.
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+        if (libcanhaltools::configureIface(*bus_cfg) != ICanController::Result::OK) {
+            LOG(ERROR) << "No controller supports " << bus.name() << std::endl;
+            // TODO(149405589): add retry logic in case a bus fails to come up.
+            continue;
+        }
+        LOG(INFO) << bus.name() << " has been successfully configured!";
+    }
+    return true;
+}
+
+/**
+ * This kicks off the CAN HAL configuration process. This starts the following:
+ *     1. Reading the config file
+ *     2. Setting up CAN buses
+ *     3. Handling services
+ * \param filepath is a string specifying the absolute path of the config file
+ * \return boolean status, true on success, false on failure
+ */
+static bool configuratorStart(const std::string& filepath) {
+    base::SetDefaultTag("CanConfigurator");
+
+    auto pb_cfg = config::parseConfigFile(filepath);
+    if (!pb_cfg.has_value()) {
+        return false;
+    }
+
+    // process the rest of the config file data and configure the CAN buses.
+    if (!processPbCfg(*pb_cfg)) {
+        return false;
+    }
+    LOG(INFO) << "CAN HAL has been configured!";
+    return true;
+}
+
+}  // namespace android::hardware::automotive::can
+
+int main(int argc, char* argv[]) {
+    std::string config_filepath = "/etc/canbus_config.pb";
+
+    // allow for CLI specification of a config file.
+    if (argc == 2) {
+        config_filepath = argv[1];
+    } else if (argc > 2) {
+        std::cerr << "usage: " << argv[0] << " [optional config filepath]";
+        return 1;
+    }
+
+    if (!::android::hardware::automotive::can::configuratorStart(config_filepath)) {
+        return 1;
+    }
+    return 0;
+}
diff --git a/automotive/can/1.0/tools/configurator/canhalconfigurator.rc b/automotive/can/1.0/tools/configurator/canhalconfigurator.rc
new file mode 100644
index 0000000..12c2465
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/canhalconfigurator.rc
@@ -0,0 +1,3 @@
+service canhalconfigurator /system/bin/canhalconfigurator
+  class core
+  oneshot
diff --git a/automotive/can/1.0/tools/configurator/canprototools.cpp b/automotive/can/1.0/tools/configurator/canprototools.cpp
new file mode 100644
index 0000000..0a12bd6
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/canprototools.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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 "canprototools.h"
+
+#include <android-base/logging.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+#include <hidl/HidlTransportSupport.h>
+#include <libcanhaltools/libcanhaltools.h>
+
+#include <fstream>
+
+namespace android::hardware::automotive::can::config {
+
+using ICanController = V1_0::ICanController;
+
+/**
+ * Helper function for parseConfigFile. readString is used to get the fist n characters (n) from an
+ * istream object (s) and return it as a string object.
+ *
+ * \param s istream of the file you intend to read.
+ * \param n streamsize object of the number of characters you'd like.
+ * \return optional string containing up to n characters from the stream(s) you provided.
+ */
+static std::optional<std::string> readString(std::istream& s, std::streamsize n) {
+    char buff[n];
+    auto got = s.read(buff, n).gcount();
+    if (!s.good() && !s.eof()) return std::nullopt;
+    return std::string(buff, 0, std::min(n, got));
+}
+
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath) {
+    std::ifstream cfg_stream(filepath);
+
+    // text headers that would be present in a plaintext proto config file.
+    static const std::array<std::string, 3> text_headers = {"buses", "#", "controller"};
+    auto cfg_file_snippet = readString(cfg_stream, 10);
+
+    if (!cfg_file_snippet.has_value()) {
+        LOG(ERROR) << "Can't open " << filepath << " for reading";
+        return std::nullopt;
+    }
+    cfg_stream.seekg(0);
+
+    // check if any of the textHeaders are at the start of the config file.
+    bool text_format = false;
+    for (auto const& header : text_headers) {
+        if (cfg_file_snippet->compare(0, header.length(), header) == 0) {
+            text_format = true;
+            break;
+        }
+    }
+
+    CanBusConfig config;
+    if (text_format) {
+        google::protobuf::io::IstreamInputStream pb_stream(&cfg_stream);
+        if (!google::protobuf::TextFormat::Parse(&pb_stream, &config)) {
+            LOG(ERROR) << "Failed to parse (text format) " << filepath;
+            return std::nullopt;
+        }
+    } else if (!config.ParseFromIstream(&cfg_stream)) {
+        LOG(ERROR) << "Failed to parse (binary format) " << filepath;
+        return std::nullopt;
+    }
+    return config;
+}
+
+std::optional<ICanController::BusConfig> fromPbBus(const Bus& pb_bus) {
+    ICanController::BusConfig bus_cfg = {};
+    bus_cfg.name = pb_bus.name();
+
+    switch (pb_bus.iface_type_case()) {
+        case Bus::kNative: {
+            const auto ifname = pb_bus.native().ifname();
+            const auto serialno = pb_bus.native().serialno();
+            if (ifname.empty() == serialno.empty()) {
+                LOG(ERROR) << "Invalid config: native type bus must have an iface name xor a "
+                           << "serial number";
+                return std::nullopt;
+            }
+            bus_cfg.bitrate = pb_bus.bitrate();
+            ICanController::BusConfig::InterfaceId::Socketcan socketcan = {};
+            if (!ifname.empty()) socketcan.ifname(ifname);
+            if (!serialno.empty()) socketcan.serialno({serialno.begin(), serialno.end()});
+            bus_cfg.interfaceId.socketcan(socketcan);
+            break;
+        }
+        case Bus::kSlcan: {
+            const auto ttyname = pb_bus.slcan().ttyname();
+            const auto serialno = pb_bus.slcan().serialno();
+            if (ttyname.empty() == serialno.empty()) {
+                LOG(ERROR) << "Invalid config: slcan type bus must have a tty name";
+                return std::nullopt;
+            }
+            bus_cfg.bitrate = pb_bus.bitrate();
+            ICanController::BusConfig::InterfaceId::Slcan slcan = {};
+            if (!ttyname.empty()) slcan.ttyname(ttyname);
+            if (!serialno.empty()) slcan.serialno({serialno.begin(), serialno.end()});
+            bus_cfg.interfaceId.slcan(slcan);
+            break;
+        }
+        case Bus::kVirtual: {
+            // Theoretically, we could just create the next available vcan iface.
+            const auto ifname = pb_bus.virtual_().ifname();
+            if (ifname.empty()) {
+                LOG(ERROR) << "Invalid config: native type bus must have an iface name";
+                return std::nullopt;
+            }
+            bus_cfg.interfaceId.virtualif({ifname});
+            break;
+        }
+        case Bus::kIndexed: {
+            const auto index = pb_bus.indexed().index();
+            if (index > UINT8_MAX) {
+                LOG(ERROR) << "Interface index out of range: " << index;
+                return std::nullopt;
+            }
+            bus_cfg.interfaceId.indexed({uint8_t(index)});
+            break;
+        }
+        default:
+            LOG(ERROR) << "Invalid config: bad interface type for " << bus_cfg.name;
+            return std::nullopt;
+    }
+    return bus_cfg;
+}
+
+std::optional<ICanController::InterfaceType> getHalIftype(const Bus& pb_bus) {
+    switch (pb_bus.iface_type_case()) {
+        case Bus::kNative:
+            return ICanController::InterfaceType::SOCKETCAN;
+        case Bus::kSlcan:
+            return ICanController::InterfaceType::SLCAN;
+        case Bus::kVirtual:
+            return ICanController::InterfaceType::VIRTUAL;
+        case Bus::kIndexed:
+            return ICanController::InterfaceType::INDEXED;
+        default:
+            return std::nullopt;
+    }
+}
+
+}  // namespace android::hardware::automotive::can::config
diff --git a/automotive/can/1.0/tools/configurator/canprototools.h b/automotive/can/1.0/tools/configurator/canprototools.h
new file mode 100644
index 0000000..b7f2b6f
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/canprototools.h
@@ -0,0 +1,49 @@
+/*
+ * 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 "canbus_config.pb.h"
+
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android::hardware::automotive::can::config {
+
+/**
+ * This reads the protobuf config file into a protobuf object. Both text based protobuf files as
+ * well as binary format protobuf files are supported.
+ *
+ * \param filepath string containing the name of the config file to read.
+ * \return a CanBusConfig protobuf object constructed from the config file.
+ */
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath);
+
+/**
+ * Converts protobuf format single-bus config object to a HAL bus config object.
+ *
+ * \param pb_bus is the protobuf object representing a the configuration of one CAN bus.
+ * \return a converted HAL bus config object.
+ */
+std::optional<V1_0::ICanController::BusConfig> fromPbBus(const Bus& pb_bus);
+
+/**
+ * Get the CAN HAL interface type specified by a given protobuf config object.
+ *
+ * \param pb_bus is the protobuf object representing a the configuration of one CAN bus.
+ * \return the CAN HAL interface type.
+ */
+std::optional<V1_0::ICanController::InterfaceType> getHalIftype(const Bus& pb_bus);
+
+}  // namespace android::hardware::automotive::can::config
diff --git a/automotive/can/1.0/tools/configurator/proto/Android.bp b/automotive/can/1.0/tools/configurator/proto/Android.bp
new file mode 100644
index 0000000..05e1205
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/proto/Android.bp
@@ -0,0 +1,28 @@
+//
+// 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.automotive.can@1.x-config-format",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    proto: {
+        export_proto_headers: true,
+        type: "full",
+    },
+    strip: {
+        keep_symbols: true,
+    },
+    srcs: ["canbus_config.proto"],
+}
diff --git a/automotive/can/1.0/tools/configurator/proto/canbus_config.proto b/automotive/can/1.0/tools/configurator/proto/canbus_config.proto
new file mode 100644
index 0000000..9aa33ac
--- /dev/null
+++ b/automotive/can/1.0/tools/configurator/proto/canbus_config.proto
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.can.config;
+
+message IfaceNative {
+    string ifname = 1;
+    repeated string serialno = 2;
+};
+
+message IfaceSlcan {
+    string ttyname = 1;
+    repeated string serialno = 2;
+};
+
+message IfaceVirtual {
+    string ifname = 1;
+};
+
+message IfaceIndexed {
+    uint32 index = 1;
+};
+
+message Bus {
+    string name = 1;  // this is the name presented in the HAL
+    oneof iface_type {
+        IfaceNative native = 2;
+        IfaceSlcan slcan = 3;
+        IfaceVirtual virtual = 4;
+        IfaceIndexed indexed = 5;
+    }
+    uint32 bitrate = 6;
+};
+
+message CanBusConfig {
+    repeated Bus buses = 1;
+};
diff --git a/automotive/can/1.0/tools/libcanhaltools/Android.bp b/automotive/can/1.0/tools/libcanhaltools/Android.bp
new file mode 100644
index 0000000..cee9eef
--- /dev/null
+++ b/automotive/can/1.0/tools/libcanhaltools/Android.bp
@@ -0,0 +1,32 @@
+//
+// 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.automotive.can@libcanhaltools",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    vendor_available: true,
+    srcs: [
+        "libcanhaltools.cpp",
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+    ],
+    header_libs: [
+        "android.hardware.automotive.can@hidl-utils-lib",
+    ],
+}
diff --git a/automotive/can/1.0/tools/libcanhaltools/include/libcanhaltools/libcanhaltools.h b/automotive/can/1.0/tools/libcanhaltools/include/libcanhaltools/libcanhaltools.h
new file mode 100644
index 0000000..bbd1fe5
--- /dev/null
+++ b/automotive/can/1.0/tools/libcanhaltools/include/libcanhaltools/libcanhaltools.h
@@ -0,0 +1,48 @@
+/*
+ * 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/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android::hardware::automotive::can::libcanhaltools {
+
+/**
+ * Fetch the list of registered can controller services.
+ *
+ * \return list of service names identifying the registered can controllers.
+ */
+hidl_vec<hidl_string> getControlServices();
+
+/**
+ * Determine if an can controller supports a specific interface type.
+ *
+ * \param ctrl a pointer to a can controller instance to check for interface support.
+ * \param iftype the interface type we wish to check if ctrl supports.
+ * \return true if iftype is supported by ctrl, false if not supported.
+ */
+bool isSupported(sp<V1_0::ICanController> ctrl, V1_0::ICanController::InterfaceType iftype);
+
+/**
+ * Configures a CAN interface through the CAN HAL and brings it up.
+ *
+ * \param can_config this holds the parameters for configuring a CAN bus.
+ * \return status passed back from the CAN HAL, should be OK on success.
+ */
+V1_0::ICanController::Result configureIface(V1_0::ICanController::BusConfig can_config);
+
+}  // namespace android::hardware::automotive::can::libcanhaltools
diff --git a/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp b/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp
new file mode 100644
index 0000000..9192e2f
--- /dev/null
+++ b/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "libcanhaltools/libcanhaltools.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl-utils/hidl-utils.h>
+
+#include <iostream>
+#include <string>
+
+namespace android::hardware::automotive::can::libcanhaltools {
+
+using ICanBus = V1_0::ICanBus;
+using ICanController = V1_0::ICanController;
+using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator;
+
+hidl_vec<hidl_string> getControlServices() {
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    hidl_vec<hidl_string> services;
+    manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services));
+    CHECK(services.size() > 0) << "No ICanController services registered (missing privileges?)"
+                               << std::endl;
+    return services;
+}
+
+bool isSupported(sp<ICanController> ctrl, ICanController::InterfaceType iftype) {
+    hidl_vec<ICanController::InterfaceType> supported;
+    if (!ctrl->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).isOk()) return false;
+    return supported.contains(iftype);
+}
+
+ICanController::InterfaceType getIftype(ICanController::BusConfig can_config) {
+    switch (can_config.interfaceId.getDiscriminator()) {
+        case IfIdDisc::socketcan:
+            return ICanController::InterfaceType::SOCKETCAN;
+        case IfIdDisc::slcan:
+            return ICanController::InterfaceType::SLCAN;
+        case IfIdDisc::virtualif:
+            return ICanController::InterfaceType::VIRTUAL;
+        case IfIdDisc::indexed:
+            return ICanController::InterfaceType::INDEXED;
+        default:
+            CHECK(false) << "HAL returned unexpected interface type!";
+    }
+}
+
+ICanController::Result configureIface(ICanController::BusConfig can_config) {
+    auto iftype = getIftype(can_config);
+    auto can_controller_list = getControlServices();
+    for (auto const& service : can_controller_list) {
+        auto ctrl = ICanController::getService(service);
+        if (ctrl == nullptr) {
+            LOG(ERROR) << "Couldn't open ICanController/" << service;
+            continue;
+        }
+
+        if (!libcanhaltools::isSupported(ctrl, iftype)) continue;
+
+        const auto up_result = ctrl->upInterface(can_config);
+        if (up_result != ICanController::Result::OK) {
+            LOG(ERROR) << "Failed to bring " << can_config.name << " up: " << toString(up_result)
+                       << std::endl;
+        }
+        return up_result;
+    }
+    return ICanController::Result::NOT_SUPPORTED;
+}
+
+}  // namespace android::hardware::automotive::can::libcanhaltools
diff --git a/automotive/can/1.0/types.hal b/automotive/can/1.0/types.hal
new file mode 100644
index 0000000..5eeed53
--- /dev/null
+++ b/automotive/can/1.0/types.hal
@@ -0,0 +1,142 @@
+/*
+ * 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.automotive.can@1.0;
+
+/**
+ * CAN message ID.
+ *
+ * Does not include any flags like RTR nor ERR, only a plain 11-bit
+ * or 29-bit identifier, as defined in CAN 1.x/2.0x.
+ *
+ * Unused bits must be set to zero.
+ */
+typedef uint32_t CanMessageId;
+
+/**
+ * CAN message being sent or received.
+ */
+struct CanMessage {
+    CanMessageId id;
+
+    /**
+     * CAN message payload, as defined in CAN 1.x and CAN 2.x standards.
+     *
+     * The length of the payload vector directly translates to the length
+     * of the data frame (i.e. includes any padding bytes), so it may be in
+     * a range of:
+     *  - 0-8 bytes for standard CAN;
+     *  - up to 64 bytes for CAN FD.
+     * ISO TP is not supported directly for now.
+     */
+    vec<uint8_t> payload;
+
+    /**
+     * Time in nanoseconds since boot.
+     *
+     * Ignored for outgoing messages.
+     */
+    uint64_t timestamp;
+
+    /**
+     * A request to proactively pull certain data from other ECU in CAN network.
+     *
+     * For details please refer to CAN standard.
+     *
+     * If this flag is set, payload must be empty.
+     */
+    bool remoteTransmissionRequest;
+
+    /**
+     * Flag indicating if the message has an extended ID.
+     *
+     * Extended ID's are 29 bits long, as opposed to the standard 11 bit ID.
+     * It can not simply be inferred from the length of the ID itself, as the
+     * message ID 0x00000123 !=  message ID 0x123.
+     */
+    bool isExtendedId;
+};
+
+/**
+ * Single filter rule for CAN messages.
+ *
+ * A filter is satisfied if:
+ * ((receivedId & mask) == (id & mask)) == !exclude
+ *
+ * In order for set of filters to match, at least one non-exclude filters must match (if there is
+ * one) and all exclude filters must match. In other words:
+ *  - a single matching non-exclude filter makes the whole set matching;
+ *  - a single non-matching excluded filter makes the whole set non-matching.
+ */
+struct CanMessageFilter {
+    CanMessageId id;
+    uint32_t mask;
+    /** Remote Transmission Request; another ECU requests <DLC> bytes of data on this message ID */
+    FilterFlag rtr;
+    /** 29 bit message ID is used instead of 11 bits */
+    FilterFlag extendedFormat;
+    /** 'exclude' *DOES* apply to rtr and extendedFormat! */
+    bool exclude;
+};
+
+
+/**
+ * Types of filter that can be applied to a CanMessageFilter
+ */
+enum FilterFlag : uint8_t {
+    /** Default, FilterFlag doesn't effect what messages filtered */
+    DONT_CARE = 0,
+    /** This FilterFlag MUST be present in received messages to pass though the filter */
+    SET,
+    /** This FilterFlag must NOT be present in received messages to pass though the filter */
+    NOT_SET,
+};
+
+enum Result : uint8_t {
+    OK,
+    UNKNOWN_ERROR,
+    PAYLOAD_TOO_LONG,
+    INTERFACE_DOWN,
+    TRANSMISSION_FAILURE,
+    INVALID_ARGUMENTS,
+};
+
+/**
+ * @see ICanMessageListener#onError
+ */
+enum ErrorEvent : uint8_t {
+    UNKNOWN_ERROR,
+
+    /** A problem with CAN interface HW. */
+    HARDWARE_ERROR,
+
+    /** CAN interface is down. */
+    INTERFACE_DOWN,
+
+    /** TX buffer overflow: client is sending too many packets. */
+    TX_OVERFLOW,
+
+    /** RX buffer overflow: client is not reading packets fast enough. */
+    RX_OVERFLOW,
+
+    /** Received malformed input. */
+    MALFORMED_INPUT,
+
+    /** Bus overload: there is too much traffic on the bus. */
+    BUS_OVERLOAD,
+
+    /** Bus error: shorted Hi/Lo line, bus off etc. */
+    BUS_ERROR,
+};
diff --git a/automotive/can/1.0/vts/functional/Android.bp b/automotive/can/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..d020750
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/Android.bp
@@ -0,0 +1,53 @@
+//
+// 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_defaults {
+    name: "android.hardware.automotive.can@vts-defaults",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "android.hardware.automotive.can@defaults",
+    ],
+    header_libs: [
+        "android.hardware.automotive.can@hidl-utils-lib",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@1.0",
+        "android.hardware.automotive.can@vts-utils-lib",
+        "libgmock",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
+    name: "VtsHalCanControllerV1_0TargetTest",
+    defaults: ["android.hardware.automotive.can@vts-defaults"],
+    srcs: ["VtsHalCanControllerV1_0TargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalCanBusV1_0TargetTest",
+    defaults: ["android.hardware.automotive.can@vts-defaults"],
+    srcs: ["VtsHalCanBusV1_0TargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalCanBusVirtualV1_0TargetTest",
+    defaults: ["android.hardware.automotive.can@vts-defaults"],
+    srcs: ["VtsHalCanBusVirtualV1_0TargetTest.cpp"],
+}
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
new file mode 100644
index 0000000..a8e7c0b
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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 <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <can-vts-utils/can-hal-printers.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+namespace android::hardware::automotive::can::V1_0::vts {
+
+using hardware::hidl_vec;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+    virtual Return<void> onReceive(const can::V1_0::CanMessage&) override { return {}; }
+};
+
+struct CanErrorListener : public can::V1_0::ICanErrorListener {
+    virtual Return<void> onError(ErrorEvent, bool) override { return {}; }
+};
+
+class CanBusHalTest : public ::testing::TestWithParam<std::string> {
+  protected:
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+
+    std::tuple<Result, sp<ICloseHandle>> listen(const hidl_vec<CanMessageFilter>& filter,
+                                                const sp<ICanMessageListener>& listener);
+    sp<ICloseHandle> listenForErrors(const sp<ICanErrorListener>& listener);
+
+    sp<ICanBus> mCanBus;
+};
+
+void CanBusHalTest::SetUp() {
+    mCanBus = ICanBus::getService(GetParam());
+    ASSERT_TRUE(mCanBus) << "Couldn't open CAN Bus: " << GetParam();
+}
+
+void CanBusHalTest::TearDown() {
+    mCanBus.clear();
+}
+
+std::tuple<Result, sp<ICloseHandle>> CanBusHalTest::listen(
+        const hidl_vec<CanMessageFilter>& filter, const sp<ICanMessageListener>& listener) {
+    Result halResult;
+    sp<ICloseHandle> closeHandle;
+    mCanBus->listen(filter, listener, hidl_utils::fill(&halResult, &closeHandle)).assertOk();
+
+    return {halResult, closeHandle};
+}
+
+sp<ICloseHandle> CanBusHalTest::listenForErrors(const sp<ICanErrorListener>& listener) {
+    const auto res = mCanBus->listenForErrors(listener);
+    res.assertOk();
+    return res;
+}
+
+TEST_P(CanBusHalTest, SendNoPayload) {
+    CanMessage msg = {};
+    msg.id = 0x123;
+    ASSERT_NE(mCanBus, nullptr);
+    const auto result = mCanBus->send(msg);
+    ASSERT_EQ(Result::OK, result);
+}
+
+TEST_P(CanBusHalTest, Send8B) {
+    CanMessage msg = {};
+    msg.id = 0x234;
+    msg.payload = {1, 2, 3, 4, 5, 6, 7, 8};
+
+    const auto result = mCanBus->send(msg);
+    ASSERT_EQ(Result::OK, result);
+}
+
+TEST_P(CanBusHalTest, SendZeroId) {
+    CanMessage msg = {};
+    msg.payload = {1, 2, 3};
+
+    const auto result = mCanBus->send(msg);
+    ASSERT_EQ(Result::OK, result);
+}
+
+TEST_P(CanBusHalTest, SendTooLong) {
+    CanMessage msg = {};
+    msg.id = 0x123;
+    msg.payload = hidl_vec<uint8_t>(102400);  // 100kiB
+
+    const auto result = mCanBus->send(msg);
+    ASSERT_EQ(Result::PAYLOAD_TOO_LONG, result);
+}
+
+TEST_P(CanBusHalTest, ListenNoFilter) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+
+    closeHandle->close().assertOk();
+}
+
+TEST_P(CanBusHalTest, ListenSomeFilter) {
+    hidl_vec<CanMessageFilter> filters = {
+            {0x123, 0x1FF, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+            {0x001, 0x00F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x200, 0x100, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+    };
+
+    const auto [result, closeHandle] = listen(filters, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+
+    closeHandle->close().assertOk();
+}
+
+TEST_P(CanBusHalTest, ListenNull) {
+    const auto [result, closeHandle] = listen({}, nullptr);
+    ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
+}
+
+TEST_P(CanBusHalTest, DoubleCloseListener) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+
+    closeHandle->close().assertOk();
+    closeHandle->close().assertOk();
+}
+
+TEST_P(CanBusHalTest, DontCloseListener) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+}
+
+TEST_P(CanBusHalTest, DoubleCloseErrorListener) {
+    auto closeHandle = listenForErrors(new CanErrorListener());
+    ASSERT_NE(nullptr, closeHandle.get());
+
+    closeHandle->close().assertOk();
+    closeHandle->close().assertOk();
+}
+
+TEST_P(CanBusHalTest, DoubleCloseNullErrorListener) {
+    auto closeHandle = listenForErrors(nullptr);
+    ASSERT_NE(nullptr, closeHandle.get());
+
+    closeHandle->close().assertOk();
+    closeHandle->close().assertOk();
+}
+
+TEST_P(CanBusHalTest, DontCloseErrorListener) {
+    auto closeHandle = listenForErrors(new CanErrorListener());
+    ASSERT_NE(nullptr, closeHandle.get());
+}
+
+/**
+ * This test requires that you bring up a valid bus first.
+ *
+ * Before running:
+ * mma -j && adb root && adb remount && adb sync
+ *
+ * Example manual invocation:
+ * adb shell canhalctrl up <NAME_OF_VALID_BUS> socketcan can0 125000
+ * adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest\
+ *     --gtest_filter=*_<NAME_OF_VALID_BUS>
+ */
+INSTANTIATE_TEST_SUITE_P(  //
+        PerInstance, CanBusHalTest, testing::ValuesIn(getAllHalInstanceNames(ICanBus::descriptor)),
+        PrintInstanceNameToString);
+
+}  // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
new file mode 100644
index 0000000..9039435
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -0,0 +1,876 @@
+/*
+ * 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 <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
+#include <can-vts-utils/can-hal-printers.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl-utils/hidl-utils.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <utils/Mutex.h>
+#include <utils/SystemClock.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android::hardware::automotive::can::V1_0::vts {
+
+using namespace std::chrono_literals;
+
+using hardware::hidl_vec;
+using InterfaceType = ICanController::InterfaceType;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+    DISALLOW_COPY_AND_ASSIGN(CanMessageListener);
+
+    CanMessageListener() {}
+
+    virtual Return<void> onReceive(const can::V1_0::CanMessage& msg) override {
+        std::unique_lock<std::mutex> lk(mMessagesGuard);
+        mMessages.push_back(msg);
+        mMessagesUpdated.notify_one();
+        return {};
+    }
+
+    virtual ~CanMessageListener() { mCloseHandle->close(); }
+
+    void assignCloseHandle(sp<ICloseHandle> closeHandle) {
+        EXPECT_TRUE(closeHandle);
+        EXPECT_FALSE(mCloseHandle);
+        mCloseHandle = closeHandle;
+    }
+
+    std::vector<can::V1_0::CanMessage> fetchMessages(std::chrono::milliseconds timeout,
+                                                     unsigned atLeast = 1) {
+        std::unique_lock<std::mutex> lk(mMessagesGuard);
+        mMessagesUpdated.wait_for(lk, timeout, [&] { return mMessages.size() >= atLeast; });
+        const auto messages = mMessages;
+        mMessages.clear();
+        return messages;
+    }
+
+  private:
+    sp<ICloseHandle> mCloseHandle;
+
+    std::mutex mMessagesGuard;
+    std::condition_variable mMessagesUpdated GUARDED_BY(mMessagesGuard);
+    std::vector<can::V1_0::CanMessage> mMessages GUARDED_BY(mMessagesGuard);
+};
+
+struct Bus {
+    DISALLOW_COPY_AND_ASSIGN(Bus);
+
+    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);
+
+        /* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
+         * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+        auto manager = hidl::manager::V1_2::IServiceManager::getService();
+        auto service = manager->get(ICanBus::descriptor, config.name);
+        mBus = ICanBus::castFrom(service);
+        EXPECT_TRUE(mBus) << "ICanBus/" << config.name << " failed to register";
+    }
+
+    virtual ~Bus() { reset(); }
+
+    void reset() {
+        mBus.clear();
+        if (mController) {
+            const auto res = mController->downInterface(mIfname);
+            EXPECT_TRUE(res);
+            mController.clear();
+        }
+    }
+
+    ICanBus* operator->() const { return mBus.get(); }
+    sp<ICanBus> get() { return mBus; }
+
+    sp<CanMessageListener> listen(const hidl_vec<CanMessageFilter>& filter) {
+        sp<CanMessageListener> listener = new CanMessageListener();
+
+        Result result;
+        sp<ICloseHandle> closeHandle;
+        mBus->listen(filter, listener, hidl_utils::fill(&result, &closeHandle)).assertOk();
+        EXPECT_EQ(Result::OK, result);
+        listener->assignCloseHandle(closeHandle);
+
+        return listener;
+    }
+
+    void send(const CanMessage& msg) {
+        EXPECT_NE(mBus, nullptr);
+        if (!mBus) return;
+        const auto result = mBus->send(msg);
+        EXPECT_EQ(Result::OK, result);
+    }
+
+  private:
+    const std::string mIfname;
+    sp<ICanController> mController;
+    sp<ICanBus> mBus;
+};
+
+class CanBusVirtualHalTest : public ::testing::TestWithParam<std::string> {
+  protected:
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+    static void SetUpTestCase();
+
+    Bus makeBus();
+
+  protected:
+    static hidl_vec<hidl_string> mBusNames;
+
+  private:
+    unsigned mLastIface = 0;
+    sp<ICanController> mCanController = nullptr;
+    static bool mTestCaseInitialized;
+};
+
+hidl_vec<hidl_string> CanBusVirtualHalTest::mBusNames;
+bool CanBusVirtualHalTest::mTestCaseInitialized = false;
+
+static CanMessage makeMessage(CanMessageId id, bool rtr, bool extended) {
+    CanMessage msg = {};
+    msg.id = id;
+    msg.remoteTransmissionRequest = rtr;
+    msg.isExtendedId = extended;
+    return msg;
+}
+
+static void clearTimestamps(std::vector<CanMessage>& messages) {
+    std::for_each(messages.begin(), messages.end(), [](auto& msg) { msg.timestamp = 0; });
+}
+
+void CanBusVirtualHalTest::SetUp() {
+    ASSERT_TRUE(mTestCaseInitialized);
+
+    mCanController = ICanController::getService(GetParam());
+    ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << GetParam();
+
+    hidl_vec<InterfaceType> supported;
+    mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).assertOk();
+    if (!supported.contains(InterfaceType::VIRTUAL)) GTEST_SKIP();
+}
+
+void CanBusVirtualHalTest::TearDown() {
+    mCanController.clear();
+}
+
+void CanBusVirtualHalTest::SetUpTestCase() {
+    mBusNames = utils::getBusNames();
+    ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest";
+
+    mTestCaseInitialized = true;
+}
+
+Bus CanBusVirtualHalTest::makeBus() {
+    const auto idx = mLastIface++;
+    EXPECT_LT(idx, mBusNames.size());
+
+    ICanController::BusConfig config = {};
+    config.name = mBusNames[idx];
+    config.interfaceId.virtualif({"vcan50"});
+
+    return Bus(mCanController, config);
+}
+
+TEST_P(CanBusVirtualHalTest, Send) {
+    auto bus = makeBus();
+
+    CanMessage msg = {};
+    msg.id = 0x123;
+    msg.payload = {1, 2, 3};
+
+    bus.send(msg);
+}
+
+TEST_P(CanBusVirtualHalTest, SendAfterClose) {
+    auto bus = makeBus();
+    auto zombie = bus.get();
+    bus.reset();
+
+    const auto result = zombie->send({});
+    ASSERT_EQ(Result::INTERFACE_DOWN, result);
+}
+
+TEST_P(CanBusVirtualHalTest, SendAndRecv) {
+    if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    auto listener = bus2.listen({});
+
+    CanMessage msg = {};
+    msg.id = 0x123;
+    msg.payload = {1, 2, 3};
+    bus1.send(msg);
+
+    auto messages = listener->fetchMessages(100ms);
+    ASSERT_EQ(1u, messages.size());
+    ASSERT_NEAR(uint64_t(elapsedRealtimeNano()), messages[0].timestamp,
+                std::chrono::nanoseconds(100ms).count());
+    clearTimestamps(messages);
+    ASSERT_EQ(msg, messages[0]);
+}
+
+TEST_P(CanBusVirtualHalTest, DownOneOfTwo) {
+    if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    bus2.reset();
+
+    bus1.send({});
+}
+
+TEST_P(CanBusVirtualHalTest, FilterPositive) {
+    if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    /* clang-format off */
+    /*        id,            mask,           rtr,                   eff,          exclude */
+    hidl_vec<CanMessageFilter> filterPositive = {
+            {0x334,           0x73F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+            {0x49D,           0x700, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+            {0x325,           0x7FC, FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   false},
+            {0x246,           0x7FF, FilterFlag::SET,       FilterFlag::DONT_CARE, false},
+            {0x1A2,           0x7FB, FilterFlag::SET,       FilterFlag::NOT_SET,   false},
+            {0x607,           0x7C9, FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, false},
+            {0x7F4,           0x777, FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   false},
+            {0x1BF19EAF, 0x10F0F0F0, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+            {0x12E99200, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       false},
+            {0x06B70270, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::DONT_CARE, false},
+            {0x096CFD2B, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       false},
+            {0x1BDCB008, 0x0F0F0F0F, FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, false},
+            {0x08318B46, 0x10F0F0F0, FilterFlag::NOT_SET,   FilterFlag::SET,       false},
+            {0x06B,           0x70F, FilterFlag::DONT_CARE, FilterFlag::SET,       false},
+            {0x750,           0x70F, FilterFlag::SET,       FilterFlag::SET,       false},
+            {0x5CF,           0x70F, FilterFlag::NOT_SET,   FilterFlag::SET,       false},
+    };
+    /* clang-format on */
+    auto listenerPositive = bus2.listen(filterPositive);
+
+    // 334:73F, DNC, DNC
+    bus1.send(makeMessage(0x3F4, false, false));
+    bus1.send(makeMessage(0x334, false, true));
+    bus1.send(makeMessage(0x374, true, false));
+    bus1.send(makeMessage(0x3F4, true, true));
+
+    // 49D:700, DNC, DNC
+    bus1.send(makeMessage(0x404, false, false));
+    bus1.send(makeMessage(0x4A5, false, true));
+    bus1.send(makeMessage(0x4FF, true, false));
+    bus1.send(makeMessage(0x46B, true, true));
+
+    // 325:7FC, DNC, NS
+    bus1.send(makeMessage(0x324, false, false));
+    bus1.send(makeMessage(0x325, false, true));  // filtered out
+    bus1.send(makeMessage(0x326, true, false));
+    bus1.send(makeMessage(0x327, true, true));  // filtered out
+
+    // 246:7FF, SET, DNC
+    bus1.send(makeMessage(0x246, false, false));  // filtered out
+    bus1.send(makeMessage(0x246, false, true));   // filtered out
+    bus1.send(makeMessage(0x246, true, false));
+    bus1.send(makeMessage(0x246, true, true));
+
+    // 1A2:7FB, SET, NS
+    bus1.send(makeMessage(0x1A2, false, false));  // filtered out
+    bus1.send(makeMessage(0x1A6, false, true));   // filtered out
+    bus1.send(makeMessage(0x1A2, true, false));
+    bus1.send(makeMessage(0x1A6, true, true));  // filtered out
+
+    // 607:7C9, NS, DNC
+    bus1.send(makeMessage(0x607, false, false));
+    bus1.send(makeMessage(0x613, false, true));
+    bus1.send(makeMessage(0x625, true, false));  // filtered out
+    bus1.send(makeMessage(0x631, true, true));   // filtered out
+
+    // 7F4:777, NS, NS
+    bus1.send(makeMessage(0x774, false, false));
+    bus1.send(makeMessage(0x7F4, false, true));  // filtered out
+    bus1.send(makeMessage(0x77C, true, false));  // filtered out
+    bus1.send(makeMessage(0x7FC, true, false));  // filtered out
+
+    // 1BF19EAF:10F0F0F0, DNC, DNC
+    bus1.send(makeMessage(0x11F293A4, false, false));
+    bus1.send(makeMessage(0x15F697A8, false, true));
+    bus1.send(makeMessage(0x19FA9BAC, true, false));
+    bus1.send(makeMessage(0x1DFE9FA0, true, true));
+
+    // 12E99200:1FFFFFFF, DNC, SET
+    bus1.send(makeMessage(0x12E99200, false, false));  // filtered out
+    bus1.send(makeMessage(0x12E99200, false, true));
+    bus1.send(makeMessage(0x12E99200, true, false));  // filtered out
+    bus1.send(makeMessage(0x12E99200, true, true));
+
+    // 06B70270:1FFFFFFF, SET, DNC
+    bus1.send(makeMessage(0x06B70270, false, false));  // filtered out
+    bus1.send(makeMessage(0x06B70270, false, true));   // filtered out
+    bus1.send(makeMessage(0x06B70270, true, false));
+    bus1.send(makeMessage(0x06B70270, true, true));
+
+    // 096CFD2B:1FFFFFFF, SET, SET
+    bus1.send(makeMessage(0x096CFD2B, false, false));  // filtered out
+    bus1.send(makeMessage(0x096CFD2B, false, true));   // filtered out
+    bus1.send(makeMessage(0x096CFD2B, true, false));   // filtered out
+    bus1.send(makeMessage(0x096CFD2B, true, true));
+
+    // 1BDCB008:0F0F0F0F, NS, DNC
+    bus1.send(makeMessage(0x1B2C3048, false, false));
+    bus1.send(makeMessage(0x0B5C6078, false, true));
+    bus1.send(makeMessage(0x1B8C90A8, true, false));  // filtered out
+    bus1.send(makeMessage(0x0BBCC0D8, true, true));   // filtered out
+
+    // 08318B46:10F0F0F0, NS, SET
+    bus1.send(makeMessage(0x0F3E8D4C, false, false));  // filtered out
+    bus1.send(makeMessage(0x0B3A8948, false, true));
+    bus1.send(makeMessage(0x07368544, true, false));  // filtered out
+    bus1.send(makeMessage(0x03328140, true, true));   // filtered out
+
+    // 06B:70F, DNC, SET
+    bus1.send(makeMessage(0x00B, false, false));  // filtered out
+    bus1.send(makeMessage(0x04B, false, true));
+    bus1.send(makeMessage(0x08B, true, false));  // filtered out
+    bus1.send(makeMessage(0x0FB, true, true));
+
+    // 750:70F, SET, SET
+    bus1.send(makeMessage(0x7F0, false, false));  // filtered out
+    bus1.send(makeMessage(0x780, false, true));   // filtered out
+    bus1.send(makeMessage(0x740, true, false));   // filtered out
+    bus1.send(makeMessage(0x700, true, true));
+
+    // 5CF:70F, NS, SET
+    bus1.send(makeMessage(0x51F, false, false));  // filtered out
+    bus1.send(makeMessage(0x53F, false, true));
+    bus1.send(makeMessage(0x57F, true, false));  // filtered out
+    bus1.send(makeMessage(0x5FF, true, true));   // filtered out
+
+    std::vector<can::V1_0::CanMessage> expectedPositive{
+            makeMessage(0x3F4, false, false),       // 334:73F, DNC, DNC
+            makeMessage(0x334, false, true),        // 334:73F, DNC, DNC
+            makeMessage(0x374, true, false),        // 334:73F, DNC, DNC
+            makeMessage(0x3F4, true, true),         // 334:73F, DNC, DNC
+            makeMessage(0x404, false, false),       // 49D:700, DNC, DNC
+            makeMessage(0x4A5, false, true),        // 49D:700, DNC, DNC
+            makeMessage(0x4FF, true, false),        // 49D:700, DNC, DNC
+            makeMessage(0x46B, true, true),         // 49D:700, DNC, DNC
+            makeMessage(0x324, false, false),       // 325:7FC, DNC, NS
+            makeMessage(0x326, true, false),        // 325:7FC, DNC, NS
+            makeMessage(0x246, true, false),        // 246:7FF, SET, DNC
+            makeMessage(0x246, true, true),         // 246:7FF, SET, DNC
+            makeMessage(0x1A2, true, false),        // 1A2:7FB, SET, NS
+            makeMessage(0x607, false, false),       // 607:7C9, NS, DNC
+            makeMessage(0x613, false, true),        // 607:7C9, NS, DNC
+            makeMessage(0x774, false, false),       // 7F4:777, NS, NS
+            makeMessage(0x11F293A4, false, false),  // 1BF19EAF:10F0F0F0, DNC, DNC
+            makeMessage(0x15F697A8, false, true),   // 1BF19EAF:10F0F0F0, DNC, DNC
+            makeMessage(0x19FA9BAC, true, false),   // 1BF19EAF:10F0F0F0, DNC, DNC
+            makeMessage(0x1DFE9FA0, true, true),    // 1BF19EAF:10F0F0F0, DNC, DNC
+            makeMessage(0x12E99200, false, true),   // 12E99200:1FFFFFFF, DNC, SET
+            makeMessage(0x12E99200, true, true),    // 12E99200:1FFFFFFF, DNC, SET
+            makeMessage(0x06B70270, true, false),   // 06B70270:1FFFFFFF, SET, DNC
+            makeMessage(0x06B70270, true, true),    // 06B70270:1FFFFFFF, SET, DNC
+            makeMessage(0x096CFD2B, true, true),    // 096CFD2B:1FFFFFFF, SET, SET
+            makeMessage(0x1B2C3048, false, false),  // 1BDCB008:0F0F0F0F, NS, DNC
+            makeMessage(0x0B5C6078, false, true),   // 1BDCB008:0F0F0F0F, NS, DNC
+            makeMessage(0x0B3A8948, false, true),   // 08318B46:10F0F0F0, NS, SET
+            makeMessage(0x04B, false, true),        // 06B:70F, DNC, SET
+            makeMessage(0x0FB, true, true),         // 06B:70F, DNC, SET
+            makeMessage(0x700, true, true),         // 750:70F, SET, SET
+            makeMessage(0x53F, false, true),        // 5CF:70F, NS, SET
+    };
+
+    auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size());
+    clearTimestamps(messagesPositive);
+    ASSERT_EQ(expectedPositive, messagesPositive);
+}
+
+TEST_P(CanBusVirtualHalTest, FilterNegative) {
+    if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    /* clang-format off */
+    /*        id,             mask,           rtr,                   eff          exclude */
+    hidl_vec<CanMessageFilter> filterNegative = {
+            {0x063,           0x7F3, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x0A1,           0x78F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x18B,           0x7E3, FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x1EE,           0x7EC, FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x23F,           0x7A5, FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x31F,           0x77F, FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x341,           0x77F, FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x196573DB, 0x1FFFFF7F, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x1CFCB417, 0x1FFFFFEC, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x17CCC433, 0x1FFFFFEC, FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x0BC2F508, 0x1FFFFFC3, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x1179B5D2, 0x1FFFFFC3, FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x082AF63D, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x66D,           0x76F, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x748,           0x7CC, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x784,           0x7CC, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+    };
+    /* clang-format on */
+
+    auto listenerNegative = bus2.listen(filterNegative);
+
+    // 063:7F3, DNC, DNC: ~06[3,7,B,F]
+    bus1.send(makeMessage(0x063, false, false));  // filtered out
+    bus1.send(makeMessage(0x060, false, true));
+    bus1.send(makeMessage(0x05B, true, false));
+    bus1.send(makeMessage(0x06F, true, true));  // filtered out
+
+    // 0A1:78F, DNC, DNC: ~0[8-F]1
+    bus1.send(makeMessage(0x081, false, false));  // filtered out
+    bus1.send(makeMessage(0x031, false, true));
+    bus1.send(makeMessage(0x061, true, false));
+    bus1.send(makeMessage(0x071, true, true));
+
+    // 18B:7E3, DNC, NS: ~1[8-9][7,B,F]
+    bus1.send(makeMessage(0x18B, false, false));  // filtered out
+    bus1.send(makeMessage(0x188, false, true));
+    bus1.send(makeMessage(0x123, true, false));
+    bus1.send(makeMessage(0x1D5, true, true));
+
+    // 1EE:7EC, SET, DNC: ~1[E-F][C-F]
+    bus1.send(makeMessage(0x17E, false, false));
+    bus1.send(makeMessage(0x138, false, true));
+    bus1.send(makeMessage(0x123, true, false));
+    bus1.send(makeMessage(0x1EC, true, true));  // filtered out
+
+    // 23F:7A5, SET, NS: ~2[2,3,6,7][5,7,D,F]
+    bus1.send(makeMessage(0x222, false, false));
+    bus1.send(makeMessage(0x275, false, true));
+    bus1.send(makeMessage(0x23f, true, false));  // filtered out
+    bus1.send(makeMessage(0x241, true, false));
+    bus1.send(makeMessage(0x2FF, true, true));
+
+    // 31F:77F, NS, DNC: ~3[1,9]F
+    bus1.send(makeMessage(0x32F, false, false));
+    bus1.send(makeMessage(0x31F, false, true));  // filtered out
+    bus1.send(makeMessage(0x36F, false, true));
+    bus1.send(makeMessage(0x31F, true, false));
+    bus1.send(makeMessage(0x3F3, true, true));
+
+    // 341:77F, NS, NS: ~3[4,C]1
+    bus1.send(makeMessage(0x341, false, false));  // filtered out
+    bus1.send(makeMessage(0x352, false, false));
+    bus1.send(makeMessage(0x3AA, false, true));
+    bus1.send(makeMessage(0x3BC, true, false));
+    bus1.send(makeMessage(0x3FF, true, true));
+
+    // 196573DB:1FFFFF7F, DNC, DNC: ~196573[5,D]B
+    bus1.send(makeMessage(0x1965733B, false, false));
+    bus1.send(makeMessage(0x1965734B, false, true));
+    bus1.send(makeMessage(0x1965735B, true, false));  // filtered out
+    bus1.send(makeMessage(0x1965736B, true, true));
+
+    // 1CFCB417:1FFFFFEC, DNC, SET: ~1CFCB4[0-1][4-7]
+    bus1.send(makeMessage(0x1CFCB407, false, false));
+    bus1.send(makeMessage(0x1CFCB4FF, false, true));
+    bus1.send(makeMessage(0x1CFCB414, true, false));
+    bus1.send(makeMessage(0x1CFCB407, true, true));  // filtered out
+
+    // 17CCC433:1FFFFFEC, SET, DNC: ~17CCC4[2-3][0-3]
+    bus1.send(makeMessage(0x17CCC430, false, false));
+    bus1.send(makeMessage(0x17CCC423, false, true));
+    bus1.send(makeMessage(0x17CCC420, true, false));  // filtered out
+    bus1.send(makeMessage(0x17CCC444, true, true));
+
+    // 0BC2F508:1FFFFFC3, SET, SET: ~5[0-3][0,4,8,C]
+    bus1.send(makeMessage(0x0BC2F504, false, false));
+    bus1.send(makeMessage(0x0BC2F518, false, true));
+    bus1.send(makeMessage(0x0BC2F52C, true, false));
+    bus1.send(makeMessage(0x0BC2F500, true, true));  // filtered out
+    bus1.send(makeMessage(0x0BC2F543, true, true));
+
+    // 1179B5D2:1FFFFFC3, NS, DNC: ~5[C-F][2,6,A,E]
+    bus1.send(makeMessage(0x1179B5BB, false, false));
+    bus1.send(makeMessage(0x1179B5EA, false, true));  // filtered out
+    bus1.send(makeMessage(0x1179B5C2, true, false));
+    bus1.send(makeMessage(0x1179B5DA, true, true));
+
+    // 082AF63D:1FFFFF6F, NS, SET: ~6[2,3,A,B]D
+    bus1.send(makeMessage(0x082AF62D, false, false));
+    bus1.send(makeMessage(0x082AF63D, false, true));  // filtered out
+    bus1.send(makeMessage(0x082AF60D, false, true));
+    bus1.send(makeMessage(0x082AF6AD, true, false));
+    bus1.send(makeMessage(0x082AF6BD, true, true));
+
+    // 66D:76F, DNC, SET: ~6[6,7,E,F]D
+    bus1.send(makeMessage(0x66D, false, false));
+    bus1.send(makeMessage(0x68D, false, true));
+    bus1.send(makeMessage(0x67D, true, false));
+    bus1.send(makeMessage(0x6ED, true, true));  // filtered out
+
+    // 748:7CC, SET, SET: ~0x7[4-7][8-F]
+    bus1.send(makeMessage(0x749, false, false));
+    bus1.send(makeMessage(0x75A, false, true));
+    bus1.send(makeMessage(0x76B, true, false));
+    bus1.send(makeMessage(0x748, true, true));  // filtered out
+    bus1.send(makeMessage(0x788, true, true));
+
+    // 784:7CC, NS, SET: ~0x7[8-F][4-7]
+    bus1.send(makeMessage(0x795, false, false));
+    bus1.send(makeMessage(0x784, false, true));  // filtered out
+    bus1.send(makeMessage(0x71B, false, true));
+    bus1.send(makeMessage(0x769, true, false));
+    bus1.send(makeMessage(0x784, true, true));
+
+    std::vector<can::V1_0::CanMessage> expectedNegative{
+            makeMessage(0x060, false, true),        // 063:7F3, DNC, DNC
+            makeMessage(0x05B, true, false),        // 063:7F3, DNC, DNC
+            makeMessage(0x031, false, true),        // 0A1:78F, DNC, DNC
+            makeMessage(0x061, true, false),        // 0A1:78F, DNC, DNC
+            makeMessage(0x071, true, true),         // 0A1:78F, DNC, DNC
+            makeMessage(0x188, false, true),        // 18B:7E3, DNC, NS
+            makeMessage(0x123, true, false),        // 18B:7E3, DNC, NS
+            makeMessage(0x1D5, true, true),         // 18B:7E3, DNC, NS
+            makeMessage(0x17E, false, false),       // 1EE:7EC, SET, DNC
+            makeMessage(0x138, false, true),        // 1EE:7EC, SET, DNC
+            makeMessage(0x123, true, false),        // 1EE:7EC, SET, DNC
+            makeMessage(0x222, false, false),       // 23F:7A5, SET, NS
+            makeMessage(0x275, false, true),        // 23F:7A5, SET, NS
+            makeMessage(0x241, true, false),        // 23F:7A5, SET, NS
+            makeMessage(0x2FF, true, true),         // 23F:7A5, SET, NS
+            makeMessage(0x32F, false, false),       // 31F:77F, NS, DNC
+            makeMessage(0x36F, false, true),        // 31F:77F, NS, DNC
+            makeMessage(0x31F, true, false),        // 31F:77F, NS, DNC
+            makeMessage(0x3F3, true, true),         // 31F:77F, NS, DNC
+            makeMessage(0x352, false, false),       // 341:77F, NS, NS
+            makeMessage(0x3AA, false, true),        // 341:77F, NS, NS
+            makeMessage(0x3BC, true, false),        // 341:77F, NS, NS
+            makeMessage(0x3FF, true, true),         // 341:77F, NS, NS
+            makeMessage(0x1965733B, false, false),  // 196573DB:1FFFFF7F, DNC, DNC
+            makeMessage(0x1965734B, false, true),   // 196573DB:1FFFFF7F, DNC, DNC
+            makeMessage(0x1965736B, true, true),    // 196573DB:1FFFFF7F, DNC, DNC
+            makeMessage(0x1CFCB407, false, false),  // 1CFCB417:1FFFFFEC, DNC, SET
+            makeMessage(0x1CFCB4FF, false, true),   // 1CFCB417:1FFFFFEC, DNC, SET
+            makeMessage(0x1CFCB414, true, false),   // 1CFCB417:1FFFFFEC, DNC, SET
+            makeMessage(0x17CCC430, false, false),  // 17CCC433:1FFFFFEC, SET, DNC
+            makeMessage(0x17CCC423, false, true),   // 17CCC433:1FFFFFEC, SET, DNC
+            makeMessage(0x17CCC444, true, true),    // 17CCC433:1FFFFFEC, SET, DNC
+            makeMessage(0x0BC2F504, false, false),  // 0BC2F508:1FFFFFC3, SET, SET
+            makeMessage(0x0BC2F518, false, true),   // 0BC2F508:1FFFFFC3, SET, SET
+            makeMessage(0x0BC2F52C, true, false),   // 0BC2F508:1FFFFFC3, SET, SET
+            makeMessage(0x0BC2F543, true, true),    // 0BC2F508:1FFFFFC3, SET, SET
+            makeMessage(0x1179B5BB, false, false),  // 1179B5D2:1FFFFFC3, NS, DNC
+            makeMessage(0x1179B5C2, true, false),   // 1179B5D2:1FFFFFC3, NS, DNC
+            makeMessage(0x1179B5DA, true, true),    // 1179B5D2:1FFFFFC3, NS, DNC
+            makeMessage(0x082AF62D, false, false),  // 082AF63D:1FFFFF6F, NS, SET
+            makeMessage(0x082AF60D, false, true),   // 082AF63D:1FFFFF6F, NS, SET
+            makeMessage(0x082AF6AD, true, false),   // 082AF63D:1FFFFF6F, NS, SET
+            makeMessage(0x082AF6BD, true, true),    // 082AF63D:1FFFFF6F, NS, SET
+            makeMessage(0x66D, false, false),       // 66D:76F, DNC, SET
+            makeMessage(0x68D, false, true),        // 66D:76F, DNC, SET
+            makeMessage(0x67D, true, false),        // 66D:76F, DNC, SET
+            makeMessage(0x749, false, false),       // 748:7CC, SET, SET
+            makeMessage(0x75A, false, true),        // 748:7CC, SET, SET
+            makeMessage(0x76B, true, false),        // 748:7CC, SET, SET
+            makeMessage(0x788, true, true),         // 748:7CC, SET, SET
+            makeMessage(0x795, false, false),       // 784:7CC, NS, SET
+            makeMessage(0x71B, false, true),        // 784:7CC, NS, SET
+            makeMessage(0x769, true, false),        // 784:7CC, NS, SET
+            makeMessage(0x784, true, true),         // 784:7CC, NS, SET
+    };
+
+    auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size());
+    clearTimestamps(messagesNegative);
+    ASSERT_EQ(expectedNegative, messagesNegative);
+}
+
+TEST_P(CanBusVirtualHalTest, FilterMixed) {
+    if (mBusNames.size() < 2u) GTEST_SKIP() << "Not testable with less than two CAN buses.";
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    /* clang-format off */
+    /*        id,           mask,             rtr,                   eff          exclude */
+    hidl_vec<CanMessageFilter> filterMixed = {
+            {0x000,      0x700,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+            {0x0D5,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x046,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x11D89097, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x0AB,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x00D,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x0F82400E, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x08F,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x0BE,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x0A271011, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x0BE,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x100,      0x700,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   false},
+            {0x138,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x1BF,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x13AB6165, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x17A,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x13C,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x102C5197, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x19B,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x1B8,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x0D6D5185, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x1B8,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x096A2200, 0x1FFFFF00, FilterFlag::DONT_CARE, FilterFlag::SET,       false},
+            {0x201,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x22A,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x1D1C3238, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x2C0,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x23C,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x016182C6, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x27B,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x2A5,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x160EB24B, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x2A5,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x300,      0x700,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, false},
+            {0x339,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x3D4,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x182263BE, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x327,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x36B,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x1A1D8374, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x319,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x39E,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x1B657332, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x39E,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x06C5D400, 0x1FFFFF00, FilterFlag::NOT_SET,   FilterFlag::SET,       false},
+            {0x492,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x4EE,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x07725454, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x4D5,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x402,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x139714A7, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x464,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x454,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x0EF4B46F, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x454,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x500,      0x700,      FilterFlag::SET,       FilterFlag::DONT_CARE, false},
+            {0x503,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x566,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x137605E7, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x564,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x58E,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x05F9052D, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x595,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x563,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x13358537, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x563,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x600,      0x700,      FilterFlag::SET,       FilterFlag::NOT_SET,   false},
+            {0x64D,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x620,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x1069A676, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x62D,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x6C4,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x14C76629, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x689,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x6A4,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x0BCCA6C2, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x6A4,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+
+            {0x04BB1700, 0x1FFFFF00, FilterFlag::SET,       FilterFlag::SET,       false},
+            {0x784,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, true},
+            {0x7F9,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::NOT_SET,   true},
+            {0x0200F77D, 0x1FFFFFFF, FilterFlag::DONT_CARE, FilterFlag::SET,       true},
+            {0x783,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::DONT_CARE, true},
+            {0x770,      0x7FF,      FilterFlag::NOT_SET,   FilterFlag::NOT_SET,   true},
+            {0x06602719, 0x1FFFFFFF, FilterFlag::NOT_SET,   FilterFlag::SET,       true},
+            {0x76B,      0x7FF,      FilterFlag::SET,       FilterFlag::DONT_CARE, true},
+            {0x7DF,      0x7FF,      FilterFlag::SET,       FilterFlag::NOT_SET,   true},
+            {0x1939E736, 0x1FFFFFFF, FilterFlag::SET,       FilterFlag::SET,       true},
+            {0x7DF,      0x7FF,      FilterFlag::DONT_CARE, FilterFlag::DONT_CARE, false},
+    };
+    /* clang-format on */
+
+    auto listenerMixed = bus2.listen(filterMixed);
+
+    bus1.send(makeMessage(0x000, true, true));  // positive filter
+    bus1.send(makeMessage(0x0D5, false, false));
+    bus1.send(makeMessage(0x046, true, false));
+    bus1.send(makeMessage(0x046, false, false));
+    bus1.send(makeMessage(0x11D89097, true, true));
+    bus1.send(makeMessage(0x11D89097, false, true));
+    bus1.send(makeMessage(0x0AB, false, false));
+    bus1.send(makeMessage(0x0AB, false, true));
+    bus1.send(makeMessage(0x00D, false, false));
+    bus1.send(makeMessage(0x0F82400E, false, true));
+    bus1.send(makeMessage(0x08F, true, false));
+    bus1.send(makeMessage(0x08F, true, true));
+    bus1.send(makeMessage(0x0BE, true, false));
+    bus1.send(makeMessage(0x0A271011, true, true));
+    bus1.send(makeMessage(0x0BE, false, true));   // not filtered
+    bus1.send(makeMessage(0x100, false, false));  // positive filter
+    bus1.send(makeMessage(0x138, false, true));
+    bus1.send(makeMessage(0x138, true, false));
+    bus1.send(makeMessage(0x1BF, false, false));
+    bus1.send(makeMessage(0x1BF, true, false));
+    bus1.send(makeMessage(0x13AB6165, false, true));
+    bus1.send(makeMessage(0x13AB6165, true, true));
+    bus1.send(makeMessage(0x17A, false, false));
+    bus1.send(makeMessage(0x17A, false, true));
+    bus1.send(makeMessage(0x13C, false, false));
+    bus1.send(makeMessage(0x102C5197, false, true));
+    bus1.send(makeMessage(0x19B, true, false));
+    bus1.send(makeMessage(0x19B, true, true));
+    bus1.send(makeMessage(0x1B8, true, false));
+    bus1.send(makeMessage(0x0D6D5185, true, true));
+    bus1.send(makeMessage(0x1B8, false, true));       // not filtered
+    bus1.send(makeMessage(0x096A2200, false, true));  // positive filter
+    bus1.send(makeMessage(0x201, false, true));
+    bus1.send(makeMessage(0x201, true, false));
+    bus1.send(makeMessage(0x22A, false, false));
+    bus1.send(makeMessage(0x22A, true, false));
+    bus1.send(makeMessage(0x1D1C3238, false, true));
+    bus1.send(makeMessage(0x1D1C3238, true, true));
+    bus1.send(makeMessage(0x2C0, false, false));
+    bus1.send(makeMessage(0x2C0, false, true));
+    bus1.send(makeMessage(0x23C, false, false));
+    bus1.send(makeMessage(0x016182C6, false, true));
+    bus1.send(makeMessage(0x27B, true, false));
+    bus1.send(makeMessage(0x27B, true, true));
+    bus1.send(makeMessage(0x2A5, true, false));
+    bus1.send(makeMessage(0x160EB24B, true, true));
+    bus1.send(makeMessage(0x2A5, false, true));   // not filtereed
+    bus1.send(makeMessage(0x300, false, false));  // positive filter
+    bus1.send(makeMessage(0x339, false, true));
+    bus1.send(makeMessage(0x339, false, false));
+    bus1.send(makeMessage(0x3D4, true, false));
+    bus1.send(makeMessage(0x182263BE, false, true));
+    bus1.send(makeMessage(0x182263BE, true, true));
+    bus1.send(makeMessage(0x327, false, false));
+    bus1.send(makeMessage(0x327, false, true));
+    bus1.send(makeMessage(0x36B, false, false));
+    bus1.send(makeMessage(0x1A1D8374, false, true));
+    bus1.send(makeMessage(0x319, true, false));
+    bus1.send(makeMessage(0x319, true, true));
+    bus1.send(makeMessage(0x39E, true, false));
+    bus1.send(makeMessage(0x1B657332, true, true));
+    bus1.send(makeMessage(0x39E, false, true));       // not filtered
+    bus1.send(makeMessage(0x06C5D400, false, true));  // positive filter
+    bus1.send(makeMessage(0x492, false, true));
+    bus1.send(makeMessage(0x492, true, false));
+    bus1.send(makeMessage(0x4EE, false, false));
+    bus1.send(makeMessage(0x4EE, true, false));
+    bus1.send(makeMessage(0x07725454, false, true));
+    bus1.send(makeMessage(0x07725454, true, true));
+    bus1.send(makeMessage(0x4D5, false, false));
+    bus1.send(makeMessage(0x4D5, false, true));
+    bus1.send(makeMessage(0x402, false, false));
+    bus1.send(makeMessage(0x139714A7, false, true));
+    bus1.send(makeMessage(0x464, true, false));
+    bus1.send(makeMessage(0x464, true, true));
+    bus1.send(makeMessage(0x454, true, false));
+    bus1.send(makeMessage(0x0EF4B46F, true, true));
+    bus1.send(makeMessage(0x454, false, true));  // not filtered
+    bus1.send(makeMessage(0x500, true, false));  // positive filter
+    bus1.send(makeMessage(0x503, false, true));
+    bus1.send(makeMessage(0x503, true, false));
+    bus1.send(makeMessage(0x566, false, false));
+    bus1.send(makeMessage(0x566, true, false));
+    bus1.send(makeMessage(0x137605E7, false, true));
+    bus1.send(makeMessage(0x137605E7, true, true));
+    bus1.send(makeMessage(0x564, false, false));
+    bus1.send(makeMessage(0x564, false, true));
+    bus1.send(makeMessage(0x58E, false, false));
+    bus1.send(makeMessage(0x05F9052D, false, true));
+    bus1.send(makeMessage(0x595, true, false));
+    bus1.send(makeMessage(0x595, true, true));
+    bus1.send(makeMessage(0x563, true, false));
+    bus1.send(makeMessage(0x13358537, true, true));
+    bus1.send(makeMessage(0x563, false, true));  // not filtered
+    bus1.send(makeMessage(0x600, true, false));  // positive filter
+    bus1.send(makeMessage(0x64D, false, true));
+    bus1.send(makeMessage(0x64D, true, false));
+    bus1.send(makeMessage(0x620, false, false));
+    bus1.send(makeMessage(0x620, true, false));
+    bus1.send(makeMessage(0x1069A676, false, true));
+    bus1.send(makeMessage(0x1069A676, true, true));
+    bus1.send(makeMessage(0x62D, false, false));
+    bus1.send(makeMessage(0x62D, false, true));
+    bus1.send(makeMessage(0x6C4, false, false));
+    bus1.send(makeMessage(0x14C76629, false, true));
+    bus1.send(makeMessage(0x689, true, false));
+    bus1.send(makeMessage(0x689, true, true));
+    bus1.send(makeMessage(0x6A4, true, false));
+    bus1.send(makeMessage(0x0BCCA6C2, true, true));
+    bus1.send(makeMessage(0x6A4, false, true));      // not filtered
+    bus1.send(makeMessage(0x04BB1700, true, true));  // positive filter
+    bus1.send(makeMessage(0x784, false, true));
+    bus1.send(makeMessage(0x784, true, false));
+    bus1.send(makeMessage(0x7F9, false, false));
+    bus1.send(makeMessage(0x7F9, true, false));
+    bus1.send(makeMessage(0x0200F77D, false, true));
+    bus1.send(makeMessage(0x0200F77D, true, true));
+    bus1.send(makeMessage(0x783, false, false));
+    bus1.send(makeMessage(0x783, false, true));
+    bus1.send(makeMessage(0x770, false, false));
+    bus1.send(makeMessage(0x06602719, false, true));
+    bus1.send(makeMessage(0x76B, true, false));
+    bus1.send(makeMessage(0x76B, true, true));
+    bus1.send(makeMessage(0x7DF, true, false));
+    bus1.send(makeMessage(0x1939E736, true, true));
+    bus1.send(makeMessage(0x7DF, false, true));  // not filtered
+
+    std::vector<can::V1_0::CanMessage> expectedMixed{
+            makeMessage(0x000, true, true),  // 0x000:0x700, DONT_CARE, DONT_CARE
+            makeMessage(0x0BE, false, true),
+            makeMessage(0x100, false, false),  // 0x100:0x700, DONT_CARE, NOT_SET
+            makeMessage(0x1B8, false, true),
+            makeMessage(0x096A2200, false, true),  // 0x096A2200:0x1FFFFF00, DONT_CARE, SET
+            makeMessage(0x2A5, false, true),
+            makeMessage(0x300, false, false),  // 0x300:0x700, NOT_SET, DONT_CARE
+            makeMessage(0x39E, false, true),
+            makeMessage(0x06C5D400, false, true),  // 0x06C5D400:0x1FFFFF00, NOT_SET, SET
+            makeMessage(0x454, false, true),
+            makeMessage(0x500, true, false),  // 0x500:0x700, SET, DONT_CARE
+            makeMessage(0x563, false, true),
+            makeMessage(0x600, true, false),  // 0x600:0x700, SET, NOT_SET
+            makeMessage(0x6A4, false, true),
+            makeMessage(0x04BB1700, true, true),  // 0x04BB1700:0x1FFFFF00, SET, SET
+            makeMessage(0x7DF, false, true),
+    };
+
+    auto messagesMixed = listenerMixed->fetchMessages(100ms, expectedMixed.size());
+    clearTimestamps(messagesMixed);
+    ASSERT_EQ(expectedMixed, messagesMixed);
+}
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanBusVirtualV1_0TargetTest/VtsHalCanBusVirtualV1_0TargetTest
+ */
+INSTANTIATE_TEST_SUITE_P(  //
+        PerInstance, CanBusVirtualHalTest,
+        testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
+        PrintInstanceNameToString);
+
+}  // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
new file mode 100644
index 0000000..8ef5758
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -0,0 +1,301 @@
+/*
+ * 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 <android-base/strings.h>
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+#include <android/hardware/automotive/can/1.0/types.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
+#include <can-vts-utils/can-hal-printers.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+namespace android::hardware::automotive::can::V1_0::vts {
+
+using hardware::hidl_vec;
+using InterfaceType = ICanController::InterfaceType;
+using IfId = ICanController::BusConfig::InterfaceId;
+
+class CanControllerHalTest : public ::testing::TestWithParam<std::string> {
+  protected:
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+    static void SetUpTestCase();
+
+    hidl_vec<InterfaceType> getSupportedInterfaceTypes();
+    bool isSupported(InterfaceType iftype);
+
+    bool up(InterfaceType iftype, const std::string srvname, std::string ifname,
+            ICanController::Result expected);
+    void assertRegistered(const std::string srvname, bool expectRegistered);
+
+    sp<ICanController> mCanController;
+    static hidl_vec<hidl_string> mBusNames;
+
+  private:
+    static bool mTestCaseInitialized;
+};
+
+hidl_vec<hidl_string> CanControllerHalTest::mBusNames;
+bool CanControllerHalTest::mTestCaseInitialized = false;
+
+void CanControllerHalTest::SetUp() {
+    ASSERT_TRUE(mTestCaseInitialized);
+
+    mCanController = ICanController::getService(GetParam());
+    ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << GetParam();
+}
+
+void CanControllerHalTest::TearDown() {
+    mCanController.clear();
+}
+
+void CanControllerHalTest::SetUpTestCase() {
+    mBusNames = utils::getBusNames();
+    ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest";
+
+    mTestCaseInitialized = true;
+}
+
+hidl_vec<InterfaceType> CanControllerHalTest::getSupportedInterfaceTypes() {
+    hidl_vec<InterfaceType> iftypesResult;
+    mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult)).assertOk();
+    return iftypesResult;
+}
+
+bool CanControllerHalTest::isSupported(InterfaceType iftype) {
+    const auto supported = getSupportedInterfaceTypes();
+    return std::find(supported.begin(), supported.end(), iftype) != supported.end();
+}
+
+bool CanControllerHalTest::up(InterfaceType iftype, std::string srvname, std::string ifname,
+                              ICanController::Result expected) {
+    ICanController::BusConfig config = {};
+    config.name = srvname;
+
+    // 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);
+
+    if (!isSupported(iftype)) {
+        LOG(INFO) << iftype << " interfaces not supported";
+        EXPECT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
+        return false;
+    }
+
+    EXPECT_EQ(expected, upresult);
+    return true;
+}
+
+void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) {
+    /* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
+     * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    auto busService = manager->get(ICanBus::descriptor, srvname);
+    ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
+            << "ICanBus/" << srvname << (expectRegistered ? " is not " : " is ") << "registered"
+            << " (should be otherwise)";
+}
+
+TEST_P(CanControllerHalTest, SupportsSomething) {
+    const auto supported = getSupportedInterfaceTypes();
+    ASSERT_GT(supported.size(), 0u);
+}
+
+TEST_P(CanControllerHalTest, BringUpDown) {
+    const std::string name = mBusNames[0];
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::OK)) GTEST_SKIP();
+    assertRegistered(name, true);
+
+    const auto dnresult = mCanController->downInterface(name);
+    ASSERT_TRUE(dnresult);
+
+    assertRegistered(name, false);
+}
+
+TEST_P(CanControllerHalTest, DownDummy) {
+    const auto result = mCanController->downInterface("imnotup");
+    ASSERT_FALSE(result);
+}
+
+TEST_P(CanControllerHalTest, UpTwice) {
+    const std::string name = mBusNames[0];
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan72", ICanController::Result::OK)) GTEST_SKIP();
+    assertRegistered(name, true);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan73", ICanController::Result::INVALID_STATE)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, true);
+
+    const auto result = mCanController->downInterface(name);
+    ASSERT_TRUE(result);
+    assertRegistered(name, false);
+}
+
+TEST_P(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},
+    };
+
+    for (const auto [iftype, cfg] : compatMatrix) {
+        LOG(INFO) << "Compatibility testing: " << iftype << " / " << cfg;
+
+        ICanController::BusConfig config = {};
+        config.name = "compattestsrv";
+        config.bitrate = 125000;
+        config.interfaceId = cfg;
+
+        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 (upresult == ICanController::Result::OK) {
+            const auto dnresult = mCanController->downInterface(config.name);
+            ASSERT_TRUE(dnresult);
+            continue;
+        }
+    }
+}
+
+TEST_P(CanControllerHalTest, FailEmptyName) {
+    const std::string name = "";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::BAD_SERVICE_NAME)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, false);
+}
+
+TEST_P(CanControllerHalTest, FailBadName) {
+    // 33 characters (name can be at most 32 characters long)
+    const std::string name = "ab012345678901234567890123456789c";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::BAD_SERVICE_NAME)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, false);
+}
+
+TEST_P(CanControllerHalTest, FailBadVirtualAddress) {
+    const std::string name = mBusNames[0];
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_INTERFACE_ID)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, false);
+}
+
+TEST_P(CanControllerHalTest, FailBadSocketcanAddress) {
+    const std::string name = mBusNames[0];
+
+    assertRegistered(name, false);
+    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_P(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);
+}
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest
+ */
+INSTANTIATE_TEST_SUITE_P(  //
+        PerInstance, CanControllerHalTest,
+        testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
+        PrintInstanceNameToString);
+
+}  // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/can/1.0/vts/utils/Android.bp b/automotive/can/1.0/vts/utils/Android.bp
new file mode 100644
index 0000000..d03ead3
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/Android.bp
@@ -0,0 +1,30 @@
+//
+// 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_library_static {
+    name: "android.hardware.automotive.can@vts-utils-lib",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "bus-enumerator.cpp",
+    ],
+    export_include_dirs: ["include"],
+    header_libs: [
+        "android.hardware.automotive.can@hidl-utils-lib",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@1.0",
+    ],
+}
diff --git a/automotive/can/1.0/vts/utils/bus-enumerator.cpp b/automotive/can/1.0/vts/utils/bus-enumerator.cpp
new file mode 100644
index 0000000..c012dd2
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/bus-enumerator.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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/hidl/manager/1.2/IServiceManager.h>
+#include <can-vts-utils/bus-enumerator.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android::hardware::automotive::can::V1_0::vts::utils {
+
+hidl_vec<hidl_string> getBusNames() {
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    hidl_vec<hidl_string> services;
+    manager->listManifestByInterface(ICanBus::descriptor, hidl_utils::fill(&services));
+    return services;
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::vts::utils
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h
new file mode 100644
index 0000000..ef385eb
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/bus-enumerator.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/ICanBus.h>
+
+namespace android::hardware::automotive::can::V1_0::vts::utils {
+
+hidl_vec<hidl_string> getBusNames();
+
+}  // namespace android::hardware::automotive::can::V1_0::vts::utils
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
new file mode 100644
index 0000000..383b54c
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android::hardware::automotive::can::V1_0 {
+
+/**
+ * Define gTest printer for a given HIDL type, but skip definition for Return<T>.
+ */
+#define DEFINE_CAN_HAL_PRINTER_SIMPLE(T, converter) \
+    std::ostream& operator<<(std::ostream& os, const T& v) { return os << converter(v); }
+
+/**
+ * Define gTest printer for a given HIDL type.
+ */
+#define DEFINE_CAN_HAL_PRINTER(T, converter)    \
+    DEFINE_CAN_HAL_PRINTER_SIMPLE(T, converter) \
+    std::ostream& operator<<(std::ostream& os, const Return<T>& v) { return os << converter(v); }
+
+DEFINE_CAN_HAL_PRINTER(CanMessage, toString)
+DEFINE_CAN_HAL_PRINTER(ErrorEvent, toString)
+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)
+
+#undef DEFINE_CAN_HAL_PRINTER
+#undef DEFINE_CAN_HAL_PRINTER_SIMPLE
+
+}  // namespace android::hardware::automotive::can::V1_0
diff --git a/automotive/evs/1.0/IEvsCamera.hal b/automotive/evs/1.0/IEvsCamera.hal
index dbcaf92..464dafb 100644
--- a/automotive/evs/1.0/IEvsCamera.hal
+++ b/automotive/evs/1.0/IEvsCamera.hal
@@ -16,7 +16,6 @@
 
 package android.hardware.automotive.evs@1.0;
 
-import types;
 import IEvsCameraStream;
 
 
@@ -28,8 +27,8 @@
     /**
      * Returns the ID of this camera.
      *
-     * Returns the description of this camera. This must be the same value as reported
-     * by EvsEnumerator::getCamerList().
+     * @return info The description of this camera.  This must be the same value as
+     *              reported by EvsEnumerator::getCameraList().
      */
     getCameraInfo() generates (CameraDesc info);
 
@@ -43,16 +42,20 @@
      * in which case buffers should be added or removed from the chain as appropriate.
      * If no call is made to this entry point, the IEvsCamera must support at least one
      * frame by default. More is acceptable.
-     * BUFFER_NOT_AVAILABLE is returned if the implementation cannot support the
-     * requested number of concurrent frames.
+     *
+     * @param  bufferCount Number of buffers the client of IEvsCamera may hold concurrently.
+     * @return result EvsResult::OK is returned if this call is successful.
      */
     setMaxFramesInFlight(uint32_t bufferCount) generates (EvsResult result);
 
     /**
-     * Request delivery of EVS camera frames from this camera.
+     * Request to start EVS camera stream from this camera.
      *
-     * The IEvsCameraStream must begin receiving periodic calls with new image
-     * frames until stopVideoStream() is called.
+     * The IEvsCameraStream must begin receiving calls with various events
+     * including new image frame ready until stopVideoStream() is called.
+     *
+     * @param  receiver IEvsCameraStream implementation.
+     * @return result EvsResult::OK is returned if this call is successful.
      */
     startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
 
@@ -64,6 +67,8 @@
      * A small, finite number of buffers are available (possibly as small
      * as one), and if the supply is exhausted, no further frames may be
      * delivered until a buffer is returned.
+     *
+     * @param  buffer A buffer to be returned.
      */
     oneway doneWithFrame(BufferDesc buffer);
 
@@ -83,6 +88,11 @@
      * The values allowed for opaqueIdentifier are driver specific,
      * but no value passed in may crash the driver. The driver should
      * return 0 for any unrecognized opaqueIdentifier.
+     *
+     * @param  opaqueIdentifier An unique identifier of the information to
+     *                          request.
+     * @return value            Requested information.  Zero is returned if the
+     *                          driver does not recognize a given identifier.
      */
     getExtendedInfo(uint32_t opaqueIdentifier) generates (int32_t value);
 
@@ -94,6 +104,11 @@
      * 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.
      */
     setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) generates (EvsResult result);
 };
diff --git a/automotive/evs/1.0/IEvsCameraStream.hal b/automotive/evs/1.0/IEvsCameraStream.hal
index 4e743b2..ec18f6a 100644
--- a/automotive/evs/1.0/IEvsCameraStream.hal
+++ b/automotive/evs/1.0/IEvsCameraStream.hal
@@ -31,6 +31,8 @@
      * When the last frame in the stream has been delivered, a NULL bufferHandle
      * must be delivered, signifying the end of the stream. No further frame
      * deliveries may happen thereafter.
+     *
+     * @param buffer a buffer descriptor of a delivered image frame.
      */
     oneway deliverFrame(BufferDesc buffer);
 };
diff --git a/automotive/evs/1.0/IEvsDisplay.hal b/automotive/evs/1.0/IEvsDisplay.hal
index 12541f3..72f767e 100644
--- a/automotive/evs/1.0/IEvsDisplay.hal
+++ b/automotive/evs/1.0/IEvsDisplay.hal
@@ -16,8 +16,6 @@
 
 package android.hardware.automotive.evs@1.0;
 
-import types;
-
 
 /**
  * Represents a single camera and is the primary interface for capturing images.
@@ -28,6 +26,9 @@
      * Returns basic information about the EVS display provided by the system.
      *
      * See the description of the DisplayDesc structure for details.
+     *
+     * @return info The description of this display.  Please see the description
+     *              of the DisplayDesc structure for details.
      */
      getDisplayInfo() generates (DisplayDesc info);
 
@@ -42,6 +43,9 @@
      * video. When the display is no longer required, the client is expected to request
      * the NOT_VISIBLE state after passing the last video frame.
      * Returns INVALID_ARG if the requested state is not a recognized value.
+     *
+     * @param  state  Desired new DisplayState.
+     * @return result EvsResult::OK is returned if this call is successful.
      */
      setDisplayState(DisplayState state) generates (EvsResult result);
 
@@ -54,6 +58,8 @@
      * the logic responsible for changing display states should generally live above
      * the device layer, making it undesirable for the HAL implementation to spontaneously
      * change display states.
+     *
+     * @return state Current DisplayState of this Display.
      */
      getDisplayState() generates (DisplayState state);
 
@@ -61,9 +67,11 @@
     /**
      * This call returns a handle to a frame buffer associated with the display.
      *
-     * The returned buffer may be locked and written to by software and/or GL. This buffer
-     * must be returned via a call to returnTargetBufferForDisplay() even if the
-     * display is no longer visible.
+     * @return buffer A handle to a frame buffer.  The returned buffer may be
+     *                locked and written to by software and/or GL.  This buffer
+     *                must be returned via a call to
+     *                returnTargetBufferForDisplay() even if the display is no
+     *                longer visible.
      */
      getTargetBuffer() generates (BufferDesc buffer);
 
@@ -75,6 +83,9 @@
      * There is no maximum time the caller may hold onto the buffer before making this
      * call. The buffer may be returned at any time and in any DisplayState, but all
      * buffers are expected to be returned before the IEvsDisplay interface is destroyed.
+     *
+     * @param  buffer A buffer handle to the frame that is ready for display.
+     * @return result EvsResult::OK is returned if this call is successful.
      */
     returnTargetBufferForDisplay(BufferDesc buffer) generates (EvsResult result);
 };
diff --git a/automotive/evs/1.0/IEvsEnumerator.hal b/automotive/evs/1.0/IEvsEnumerator.hal
index ee51e7e..e5633df 100644
--- a/automotive/evs/1.0/IEvsEnumerator.hal
+++ b/automotive/evs/1.0/IEvsEnumerator.hal
@@ -16,7 +16,6 @@
 
 package android.hardware.automotive.evs@1.0;
 
-import types;
 import IEvsCamera;
 import IEvsDisplay;
 
@@ -28,6 +27,8 @@
 
     /**
      * Returns a list of all EVS cameras available to the system
+     *
+     * @return cameras A list of cameras availale for EVS service.
      */
     getCameraList() generates (vec<CameraDesc> cameras);
 
@@ -37,9 +38,9 @@
      * Given a camera's unique cameraId from CameraDesc, returns the
      * IEvsCamera interface associated with the specified camera. When
      * done using the camera, the caller may release it by calling closeCamera().
-     * Note: Reliance on the sp<> going out of scope is not recommended
-     * because the resources may not be released right away due to asynchronos
-     * behavior in the hardware binder (ref b/36122635).
+     *
+     * @param  cameraId  A unique identifier of the camera.
+     * @return carCamera EvsCamera object associated with a given cameraId.
      */
     openCamera(string cameraId) generates (IEvsCamera carCamera);
 
@@ -48,6 +49,8 @@
      *
      * When the IEvsCamera object is no longer required, it must be released.
      * NOTE: Video streaming must be cleanly stopped before making this call.
+     *
+     * @param  carCamera EvsCamera object to be closed.
      */
     closeCamera(IEvsCamera carCamera);
 
@@ -60,8 +63,8 @@
      * 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().
-     * TODO(b/36122635) Reliance on the sp<> going out of scope is not recommended because the
-     * resources may not be released right away due to asynchronos behavior in the hardware binder.
+     *
+     * @return display EvsDisplay object to be used.
      */
     openDisplay() generates (IEvsDisplay display);
 
@@ -70,6 +73,8 @@
      *
      * When the IEvsDisplay object is no longer required, it must be released.
      * NOTE: All buffers must have been returned to the display before making this call.
+     *
+     * @param  display EvsDisplay object to be closed.
      */
     closeDisplay(IEvsDisplay display);
 
@@ -80,6 +85,8 @@
      * the actual state of the active display.  This call is replicated on the IEvsEnumerator
      * interface in order to allow secondary clients to monitor the state of the EVS display
      * without acquiring exclusive ownership of the display.
+     *
+     * @return state Current DisplayState of this Display.
      */
     getDisplayState() generates (DisplayState state);
 };
diff --git a/automotive/evs/1.0/default/Android.bp b/automotive/evs/1.0/default/Android.bp
index 69bb721..6e28ab1 100644
--- a/automotive/evs/1.0/default/Android.bp
+++ b/automotive/evs/1.0/default/Android.bp
@@ -27,4 +27,8 @@
         "-O0",
         "-g",
     ],
+
+    vintf_fragments: [
+        "manifest_android.hardware.automotive.evs@1.0-service.xml",
+    ],
 }
diff --git a/automotive/evs/1.0/default/ServiceNames.h b/automotive/evs/1.0/default/ServiceNames.h
index 1178da5..84b1697 100644
--- a/automotive/evs/1.0/default/ServiceNames.h
+++ b/automotive/evs/1.0/default/ServiceNames.h
@@ -14,4 +14,4 @@
  * limitations under the License.
  */
 
-const static char kEnumeratorServiceName[] = "EvsEnumeratorHw";
+const static char kEnumeratorServiceName[] = "hw/0";
diff --git a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
index 117c249..8dcd969 100644
--- a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
+++ b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
@@ -2,3 +2,4 @@
     class hal
     user automotive_evs
     group automotive_evs
+    disabled # do not start automatically
diff --git a/automotive/evs/1.0/default/manifest_android.hardware.automotive.evs@1.0-service.xml b/automotive/evs/1.0/default/manifest_android.hardware.automotive.evs@1.0-service.xml
new file mode 100644
index 0000000..39aec43
--- /dev/null
+++ b/automotive/evs/1.0/default/manifest_android.hardware.automotive.evs@1.0-service.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest version="1.0" type="device" >
+    <hal format="hidl">
+        <name>android.hardware.automotive.evs</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IEvsEnumerator</name>
+            <instance>hw/0</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/automotive/evs/1.0/types.hal b/automotive/evs/1.0/types.hal
index 7cebf6d..1efd5eb 100644
--- a/automotive/evs/1.0/types.hal
+++ b/automotive/evs/1.0/types.hal
@@ -24,8 +24,15 @@
  * EVS camera in the system.
  */
 struct CameraDesc {
+    /* Unique identifier for camera devices.  This may be a path to detected
+     * camera device; for example, "/dev/video0".
+     */
     string      cameraId;
-    uint32_t    vendorFlags;    // Opaque value from driver
+
+    /* Opaque value from driver.  Vendor may use this field to store additional
+     * information; for example, sensor and bridge chip id.
+     */
+    uint32_t    vendorFlags;
 };
 
 
@@ -38,8 +45,11 @@
  * presentation device.
  */
 struct DisplayDesc {
+    /* Unique identifier for the display */
     string      displayId;
-    uint32_t    vendorFlags;    // Opaque value from driver
+
+    /* Opaque value from driver */
+    uint32_t    vendorFlags;
 };
 
 
@@ -56,14 +66,31 @@
  *        Specifically consider if format and/or usage should become enumerated types.
  */
 struct BufferDesc {
-    uint32_t    width;      // Units of pixels
-    uint32_t    height;     // Units of pixels
-    uint32_t    stride;     // Units of pixels to match gralloc
-    uint32_t    pixelSize;  // Units of bytes
-    uint32_t    format;     // May contain values from android_pixel_format_t
-    uint32_t    usage;      // May contain values from from Gralloc.h
-    uint32_t    bufferId;   // Opaque value from driver
-    handle      memHandle;  // gralloc memory buffer handle
+    /* A frame width in the units of pixels */
+    uint32_t    width;
+
+    /* A frame height in the units of pixels */
+    uint32_t    height;
+
+    /* A frame stride in the units of pixels, to match gralloc */
+    uint32_t    stride;
+
+    /* The size of a pixel in the units of bytes */
+    uint32_t    pixelSize;
+
+    /* The image format of the frame; may contain values from
+     * android_pixel_format_t
+     */
+    uint32_t    format;
+
+    /* May contain values from Gralloc.h */
+    uint32_t    usage;
+
+    /* Opaque value from driver */
+    uint32_t    bufferId;
+
+    /* Gralloc memory buffer handle */
+    handle      memHandle;
 };
 
 
@@ -77,12 +104,23 @@
  * presentation device.
  */
 enum DisplayState : uint32_t {
-    NOT_OPEN = 0,           // Display has not been requested by any application
-    NOT_VISIBLE,            // Display is inhibited
-    VISIBLE_ON_NEXT_FRAME,  // Will become visible with next frame
-    VISIBLE,                // Display is currently active
-    DEAD,                   // Driver is in an undefined state.  Interface should be closed.
-    NUM_STATES              // Must be last
+    /* Display has not been requested by any application yet */
+    NOT_OPEN = 0,
+
+    /* Display is inhibited */
+    NOT_VISIBLE,
+
+    /* Will become visible with next frame */
+    VISIBLE_ON_NEXT_FRAME,
+
+    /* Display is currently active */
+    VISIBLE,
+
+    /* Driver is in an undefined state.  Interface should be closed. */
+    DEAD,
+
+    /* Must be the last */
+    NUM_STATES
 };
 
 
diff --git a/automotive/evs/1.0/vts/functional/Android.bp b/automotive/evs/1.0/vts/functional/Android.bp
index c4cbb2d..74d5122 100644
--- a/automotive/evs/1.0/vts/functional/Android.bp
+++ b/automotive/evs/1.0/vts/functional/Android.bp
@@ -19,7 +19,6 @@
     srcs: [
         "VtsHalEvsV1_0TargetTest.cpp",
         "FrameHandler.cpp",
-        "FormatConvert.cpp"
     ],
     defaults: ["VtsHalTargetTestDefaults"],
     shared_libs: [
@@ -27,6 +26,7 @@
     ],
     static_libs: [
         "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@common-default-lib",
     ],
     test_suites: ["vts"],
     cflags: [
diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.cpp b/automotive/evs/1.0/vts/functional/FormatConvert.cpp
deleted file mode 100644
index 3d82d32..0000000
--- a/automotive/evs/1.0/vts/functional/FormatConvert.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VtsHalEvsTest"
-
-#include "FormatConvert.h"
-
-
-// Round up to the nearest multiple of the given alignment value
-template<unsigned alignment>
-int align(int value) {
-    static_assert((alignment && !(alignment & (alignment - 1))),
-                  "alignment must be a power of 2");
-
-    unsigned mask = alignment - 1;
-    return (value + mask) & ~mask;
-}
-
-
-// Limit the given value to the provided range.  :)
-static inline float clamp(float v, float min, float max) {
-    if (v < min) return min;
-    if (v > max) return max;
-    return v;
-}
-
-
-static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin,
-                          bool bgrxFormat = false) {
-    // Don't use this if you want to see the best performance.  :)
-    // Better to do this in a pixel shader if we really have to, but on actual
-    // embedded hardware we expect to be able to texture directly from the YUV data
-    float U = Uin - 128.0f;
-    float V = Vin - 128.0f;
-
-    float Rf = Y + 1.140f*V;
-    float Gf = Y - 0.395f*U - 0.581f*V;
-    float Bf = Y + 2.032f*U;
-    unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
-    unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
-    unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
-
-    if (!bgrxFormat) {
-        return (R      ) |
-               (G <<  8) |
-               (B << 16) |
-               0xFF000000;  // Fill the alpha channel with ones
-    } else {
-        return (R << 16) |
-               (G <<  8) |
-               (B      ) |
-               0xFF000000;  // Fill the alpha channel with ones
-    }
-}
-
-
-void copyNV21toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels,
-                     bool bgrxFormat)
-{
-    // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-    // U/V array.  It assumes an even width and height for the overall image, and a horizontal
-    // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-    unsigned strideLum = align<16>(width);
-    unsigned sizeY = strideLum * height;
-    unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
-    unsigned offsetUV = sizeY;
-
-    uint8_t* srcY = src;
-    uint8_t* srcUV = src+offsetUV;
-
-    for (unsigned r = 0; r < height; r++) {
-        // Note that we're walking the same UV row twice for even/odd luminance rows
-        uint8_t* rowY  = srcY  + r*strideLum;
-        uint8_t* rowUV = srcUV + (r/2 * strideColor);
-
-        uint32_t* rowDest = dst + r*dstStridePixels;
-
-        for (unsigned c = 0; c < width; c++) {
-            unsigned uCol = (c & ~1);   // uCol is always even and repeats 1:2 with Y values
-            unsigned vCol = uCol | 1;   // vCol is always odd
-            rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol], bgrxFormat);
-        }
-    }
-}
-
-
-void copyYV12toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels,
-                     bool bgrxFormat)
-{
-    // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
-    // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
-    // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
-    // and V arrays.
-    unsigned strideLum = align<16>(width);
-    unsigned sizeY = strideLum * height;
-    unsigned strideColor = align<16>(strideLum/2);
-    unsigned sizeColor = strideColor * height/2;
-    unsigned offsetU = sizeY;
-    unsigned offsetV = sizeY + sizeColor;
-
-    uint8_t* srcY = src;
-    uint8_t* srcU = src+offsetU;
-    uint8_t* srcV = src+offsetV;
-
-    for (unsigned r = 0; r < height; r++) {
-        // Note that we're walking the same U and V rows twice for even/odd luminance rows
-        uint8_t* rowY = srcY + r*strideLum;
-        uint8_t* rowU = srcU + (r/2 * strideColor);
-        uint8_t* rowV = srcV + (r/2 * strideColor);
-
-        uint32_t* rowDest = dst + r*dstStridePixels;
-
-        for (unsigned c = 0; c < width; c++) {
-            rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c], bgrxFormat);
-        }
-    }
-}
-
-
-void copyYUYVtoRGB32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStridePixels,
-                     uint32_t* dst, unsigned dstStridePixels,
-                     bool bgrxFormat)
-{
-    uint32_t* srcWords = (uint32_t*)src;
-
-    const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
-    const int dstRowPadding32 = dstStridePixels   - width;    // 4 bytes per pixel, 4 bytes per word
-
-    for (unsigned r = 0; r < height; r++) {
-        for (unsigned c = 0; c < width/2; c++) {
-            // Note:  we're walking two pixels at a time here (even/odd)
-            uint32_t srcPixel = *srcWords++;
-
-            uint8_t Y1 = (srcPixel)       & 0xFF;
-            uint8_t U  = (srcPixel >> 8)  & 0xFF;
-            uint8_t Y2 = (srcPixel >> 16) & 0xFF;
-            uint8_t V  = (srcPixel >> 24) & 0xFF;
-
-            // On the RGB output, we're writing one pixel at a time
-            *(dst+0) = yuvToRgbx(Y1, U, V, bgrxFormat);
-            *(dst+1) = yuvToRgbx(Y2, U, V, bgrxFormat);
-            dst += 2;
-        }
-
-        // Skip over any extra data or end of row alignment padding
-        srcWords += srcRowPadding32;
-        dst += dstRowPadding32;
-    }
-}
-
-
-void copyNV21toBGR32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
-    return copyNV21toRGB32(width, height, src, dst, dstStridePixels, true);
-}
-
-
-void copyYV12toBGR32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
-    return copyYV12toRGB32(width, height, src, dst, dstStridePixels, true);
-}
-
-
-void copyYUYVtoBGR32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStridePixels,
-                     uint32_t* dst, unsigned dstStridePixels)
-{
-    return copyYUYVtoRGB32(width, height, src, srcStridePixels, dst, dstStridePixels, true);
-}
-
-
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
-                                   void* src, unsigned srcStridePixels,
-                                   void* dst, unsigned dstStridePixels,
-                                   unsigned pixelSize) {
-    for (unsigned row = 0; row < height; row++) {
-        // Copy the entire row of pixel data
-        memcpy(dst, src, width * pixelSize);
-
-        // Advance to the next row (keeping in mind that stride here is in units of pixels)
-        src = (uint8_t*)src + srcStridePixels * pixelSize;
-        dst = (uint8_t*)dst + dstStridePixels * pixelSize;
-    }
-}
diff --git a/automotive/evs/1.0/vts/functional/FormatConvert.h b/automotive/evs/1.0/vts/functional/FormatConvert.h
deleted file mode 100644
index 4a94f99..0000000
--- a/automotive/evs/1.0/vts/functional/FormatConvert.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef EVS_VTS_FORMATCONVERT_H
-#define EVS_VTS_FORMATCONVERT_H
-
-#include <queue>
-#include <stdint.h>
-
-
-// Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx/BGRx
-// values.  The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-// U/V array.  It assumes an even width and height for the overall image, and a horizontal
-// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyNV21toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels,
-                     bool bgrxFormat = false);
-
-void copyNV21toBGR32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels);
-
-
-// Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx/BGRx values.
-// The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
-// by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
-// and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
-// and V arrays.
-void copyYV12toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels,
-                     bool bgrxFormat = false);
-
-void copyYV12toBGR32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels);
-
-// Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx/BGRx
-// values.  The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
-// U/V array.  It assumes an even width and height for the overall image, and a horizontal
-// stride that is an even multiple of 16 bytes for both the Y and UV arrays.
-void copyYUYVtoRGB32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStrideBytes,
-                     uint32_t* dst, unsigned dstStrideBytes,
-                     bool bgrxFormat = false);
-
-void copyYUYVtoBGR32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStrideBytes,
-                     uint32_t* dst, unsigned dstStrideBytes);
-
-
-// Given an simple rectangular image buffer with an integer number of bytes per pixel,
-// copy the pixel values into a new rectangular buffer (potentially with a different stride).
-// This is typically used to copy RGBx data into an RGBx output buffer.
-void copyMatchedInterleavedFormats(unsigned width, unsigned height,
-                                   void* src, unsigned srcStridePixels,
-                                   void* dst, unsigned dstStridePixels,
-                                   unsigned pixelSize);
-
-#endif // EVS_VTS_FORMATCONVERT_H
diff --git a/automotive/evs/1.0/vts/functional/FrameHandler.cpp b/automotive/evs/1.0/vts/functional/FrameHandler.cpp
index bc3790f..6a01a44 100644
--- a/automotive/evs/1.0/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.0/vts/functional/FrameHandler.cpp
@@ -240,46 +240,47 @@
     tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
 
     if (srcPixels && tgtPixels) {
+        using namespace ::android::hardware::automotive::evs::common;
         if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) {
             if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) {   // 420SP == NV21
-                copyNV21toRGB32(width, height,
-                                srcPixels,
-                                tgtPixels, tgtBuffer.stride);
+                Utils::copyNV21toRGB32(width, height,
+                                       srcPixels,
+                                       tgtPixels, tgtBuffer.stride);
             } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
-                copyYV12toRGB32(width, height,
-                                srcPixels,
-                                tgtPixels, tgtBuffer.stride);
+                Utils::copyYV12toRGB32(width, height,
+                                       srcPixels,
+                                       tgtPixels, tgtBuffer.stride);
             } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
-                copyYUYVtoRGB32(width, height,
-                                srcPixels, srcBuffer.stride,
-                                tgtPixels, tgtBuffer.stride);
+                Utils::copyYUYVtoRGB32(width, height,
+                                       srcPixels, srcBuffer.stride,
+                                       tgtPixels, tgtBuffer.stride);
             } else if (srcBuffer.format == tgtBuffer.format) {  // 32bit RGBA
-                copyMatchedInterleavedFormats(width, height,
-                                              srcPixels, srcBuffer.stride,
-                                              tgtPixels, tgtBuffer.stride,
-                                              tgtBuffer.pixelSize);
+                Utils::copyMatchedInterleavedFormats(width, height,
+                                                     srcPixels, srcBuffer.stride,
+                                                     tgtPixels, tgtBuffer.stride,
+                                                     tgtBuffer.pixelSize);
             } else {
                 ALOGE("Camera buffer format is not supported");
                 success = false;
             }
         } else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) {
             if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) {   // 420SP == NV21
-                copyNV21toBGR32(width, height,
-                                srcPixels,
-                                tgtPixels, tgtBuffer.stride);
+                Utils::copyNV21toBGR32(width, height,
+                                       srcPixels,
+                                       tgtPixels, tgtBuffer.stride);
             } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
-                copyYV12toBGR32(width, height,
-                                srcPixels,
-                                tgtPixels, tgtBuffer.stride);
+                Utils::copyYV12toBGR32(width, height,
+                                       srcPixels,
+                                       tgtPixels, tgtBuffer.stride);
             } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
-                copyYUYVtoBGR32(width, height,
-                                srcPixels, srcBuffer.stride,
-                                tgtPixels, tgtBuffer.stride);
+                Utils::copyYUYVtoBGR32(width, height,
+                                       srcPixels, srcBuffer.stride,
+                                       tgtPixels, tgtBuffer.stride);
             } else if (srcBuffer.format == tgtBuffer.format) {  // 32bit RGBA
-                copyMatchedInterleavedFormats(width, height,
-                                              srcPixels, srcBuffer.stride,
-                                              tgtPixels, tgtBuffer.stride,
-                                              tgtBuffer.pixelSize);
+                Utils::copyMatchedInterleavedFormats(width, height,
+                                                     srcPixels, srcBuffer.stride,
+                                                     tgtPixels, tgtBuffer.stride,
+                                                     tgtBuffer.pixelSize);
             } else {
                 ALOGE("Camera buffer format is not supported");
                 success = false;
diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp
new file mode 100644
index 0000000..443422e
--- /dev/null
+++ b/automotive/evs/1.1/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.evs@1.1",
+    root: "android.hardware",
+    srcs: [
+        "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",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
new file mode 100644
index 0000000..3e7ac2b
--- /dev/null
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -0,0 +1,236 @@
+/*
+ * 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.automotive.evs@1.1;
+
+import @1.0::IEvsCamera;
+import @1.0::IEvsDisplay;
+import @1.0::EvsResult;
+import IEvsCameraStream;
+
+/**
+ * Represents a single camera and is the primary interface for capturing images.
+ */
+interface IEvsCamera extends @1.0::IEvsCamera {
+    /**
+     * Returns the description of this camera.
+     *
+     * @return info The description of this camera.  This must be the same value as
+     *              reported by EvsEnumerator::getCameraList_1_1().
+     */
+    getCameraInfo_1_1() generates (CameraDesc info);
+
+    /**
+     * Returns the description of the physical camera device that backs this
+     * logical camera.
+     *
+     * If a requested device does not either exist or back this logical device,
+     * this method returns a null camera descriptor.  And, if this is called on
+     * a physical camera device, this method is the same as getCameraInfo_1_1()
+     * method if a given device ID is matched.  Otherwise, this will return a
+     * null camera descriptor.
+     *
+     * @param  deviceId Physical camera device identifier string.
+     * @return info     The description of a member physical camera device.
+     *                  This must be the same value as reported by
+     *                  EvsEnumerator::getCameraList_1_1().
+     */
+    getPhysicalCameraInfo(string deviceId) generates (CameraDesc info);
+
+    /**
+     * Requests to pause EVS camera stream events.
+     *
+     * Like stopVideoStream(), events may continue to arrive for some time
+     * after this call returns. Delivered frame buffers must be returned.
+     *
+     * @return result EvsResult::OK is returned if this call is successful.
+     */
+    pauseVideoStream() generates (EvsResult result);
+
+    /**
+     * Requests to resume EVS camera stream.
+     *
+     * @return result EvsResult::OK is returned if this call is successful.
+     */
+    resumeVideoStream() generates (EvsResult result);
+
+    /**
+     * Returns frame that were delivered by to the IEvsCameraStream.
+     *
+     * When done consuming a frame delivered to the IEvsCameraStream
+     * interface, it must be returned to the IEvsCamera for reuse.
+     * A small, finite number of buffers are available (possibly as small
+     * as one), and if the supply is exhausted, no further frames may be
+     * delivered until a buffer is returned.
+     *
+     * @param  buffer Buffers to be returned.
+     * @return result Return EvsResult::OK if this call is successful.
+     */
+    doneWithFrame_1_1(vec<BufferDesc> buffer) generates (EvsResult result);
+
+    /**
+     * Requests to be a master client.
+     *
+     * When multiple clients subscribe to a single camera hardware and one of
+     * them adjusts a camera parameter such as the contrast, it may disturb
+     * other clients' operations.  Therefore, the client must call this method
+     * to be a master client.  Once it becomes a master, it will be able to
+     * change camera parameters until either it dies or explicitly gives up the
+     * role.
+     *
+     * @return result EvsResult::OK if a master role is granted.
+     *                EvsResult::OWNERSHIP_LOST if there is already a
+     *                master client.
+     */
+    setMaster() generates (EvsResult result);
+
+    /**
+     * Sets to be a master client forcibly.
+     *
+     * The client, which owns the display, has a high priority and can take over
+     * a master role from other clients without the display.
+     *
+     * @param  display IEvsDisplay handle.  If a given display is in either
+     *                 NOT_VISIBLE, VISIBLE_ON_NEXT_FRAME, or VISIBLE state, the
+     *                 calling client is considered as the high priority client
+     *                 and therefore allowed to take over a master role from
+     *                 existing master client.
+     *
+     * @return result  EvsResult::OK if a master role is granted.
+     *                 EvsResult::INVALID_ARG if a given display handle is null
+     *                 or in valid states.
+     */
+    forceMaster(IEvsDisplay display) generates (EvsResult result);
+
+    /**
+     * Retires from a master client role.
+     *
+     * @return result EvsResult::OK if this call is successful.
+     *                EvsResult::INVALID_ARG if the caller client is not a
+     *                master client.
+     */
+    unsetMaster() generates (EvsResult result);
+
+    /**
+     * Retrieves a list of parameters this camera supports.
+     *
+     * @return params A list of CameraParam that this camera supports.
+     */
+    getParameterList() generates (vec<CameraParam> params);
+
+    /**
+     * Requests a valid value range of a camera parameter
+     *
+     * @param  id    The identifier of camera parameter, CameraParam enum.
+     *
+     * @return min   The lower bound of valid parameter value range.
+     * @return max   The upper bound of valid parameter value range.
+     * @return step  The resolution of values in valid range.
+     */
+    getIntParameterRange(CameraParam id)
+        generates (int32_t min, int32_t max, int32_t step);
+
+    /**
+     * Requests to set a camera parameter.
+     *
+     * Only a request from the master client will be processed successfully.
+     * When this method is called on a logical camera device, it will be forwarded
+     * to each physical device and, if it fails to program any physical device,
+     * it will return an error code with the same number of effective values as
+     * the number of backing camera devices.
+     *
+     * @param  id             The identifier of camera parameter, CameraParam enum.
+     *         value          A desired parameter value.
+     * @return result         EvsResult::OK if it succeeds to set a parameter.
+     *                        EvsResult::INVALID_ARG if either the request is
+     *                        not made by a master client, or a requested
+     *                        parameter is not supported.
+     *                        EvsResult::UNDERLYING_SERVICE_ERROR if it fails to
+     *                        program a value by any other reason.
+     *         effectiveValue Programmed parameter values.  This may differ
+     *                        from what the client gives if, for example, the
+     *                        driver does not support a target parameter.
+     */
+    setIntParameter(CameraParam id, int32_t value)
+        generates (EvsResult result, vec<int32_t> effectiveValue);
+
+    /**
+     * Retrieves values of given camera parameter.
+     *
+     * @param  id     The identifier of camera parameter, CameraParam enum.
+     * @return result EvsResult::OK if it succeeds to read a parameter.
+     *                EvsResult::INVALID_ARG if either a requested parameter is
+     *                not supported.
+     *         value  Values of requested camera parameter, the same number of
+     *                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);
+
+    /**
+     * Import external buffers to capture frames
+     *
+     * This API must be called with a physical camera device identifier.
+     *
+     * @param  buffers  A list of buffers allocated by the caller.  EvsCamera
+     *                  will use these buffers to capture frames, in addition to
+     *                  other buffers already in its buffer pool.
+     * @return result   EvsResult::OK if it succeeds to import buffers.
+     *                  EvsResult::UNDERLYING_SERVICE_ERROR if this is called
+     *                  for logical camera devices or EVS fails to import
+     *                  buffers.
+     *         delta    The amount of buffer pool size changes after importing
+     *                  given buffers.
+     */
+    importExternalBuffers(vec<BufferDesc> buffers)
+        generates (EvsResult result, int32_t delta);
+};
diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal
new file mode 100644
index 0000000..aa35c62
--- /dev/null
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -0,0 +1,53 @@
+/*
+ * 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.automotive.evs@1.1;
+
+import @1.0::IEvsCameraStream;
+import @1.1::BufferDesc;
+import @1.1::EvsEventDesc;
+
+/**
+ * Implemented on client side to receive asynchronous streaming event deliveries.
+ */
+interface IEvsCameraStream extends @1.0::IEvsCameraStream {
+
+    /**
+     * Receives calls from the HAL each time video frames is ready for inspection.
+     * Buffer handles received by this method must be returned via calls to
+     * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call
+     * to IEvsCamera::stopVideoStream(), this callback may continue to happen for
+     * some time as the pipeline drains. Each frame must still be returned.
+     * When the last frame in the stream has been delivered, STREAM_STOPPED
+     * event must be delivered.  No further frame deliveries may happen
+     * thereafter.
+     *
+     * A camera device will deliver the same number of frames as number of
+     * backing physical camera devices; it means, a physical camera device
+     * sends always a single frame and a logical camera device sends multiple
+     * frames as many as number of backing physical camera devices.
+     *
+     * @param buffer Buffer descriptors of delivered image frames.
+     */
+    oneway deliverFrame_1_1(vec<BufferDesc> buffer);
+
+    /**
+     * Receives calls from the HAL each time an event happens.
+     *
+     * @param  event EVS event with possible event information.
+     */
+    oneway notify(EvsEventDesc event);
+};
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
new file mode 100644
index 0000000..d604e4f
--- /dev/null
+++ b/automotive/evs/1.1/IEvsEnumerator.hal
@@ -0,0 +1,109 @@
+/*
+ * 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.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 and ultrasonics array discovery
+ */
+interface IEvsEnumerator extends @1.0::IEvsEnumerator {
+    /**
+     * Returns a list of all EVS cameras available to the system
+     *
+     * @return cameras A list of cameras availale for EVS service.
+     */
+    getCameraList_1_1() generates (vec<CameraDesc> cameras);
+
+    /**
+     * Gets the IEvsCamera associated with a cameraId from a CameraDesc
+     *
+     * Given a camera's unique cameraId from CameraDesc, returns the
+     * IEvsCamera interface associated with the specified camera. When
+     * done using the camera, the caller may release it by calling closeCamera().
+     *
+     * @param  cameraId  A unique identifier of the camera.
+     * @param  streamCfg A stream configuration the client wants to use.
+     * @return evsCamera EvsCamera object associated with a given cameraId.
+     *                   Returned object would be null if a camera device does
+     *                   not support a given stream configuration or is already
+     *                   configured differently by another client.
+     */
+    openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera);
+
+    /**
+     * Tells whether this is EVS manager or HAL implementation.
+     *
+     * @return result False for EVS manager implementations and true for all others.
+     */
+    isHardware() generates (bool result);
+
+    /**
+     * Returns a list of all EVS displays available to the system
+     *
+     * @return displayIds Identifiers of available displays.
+     */
+    getDisplayIdList() generates (vec<uint8_t> displayIds);
+
+    /**
+     * Get exclusive access to IEvsDisplay for the system
+     *
+     * There can be more than one EVS display objects for the system and this function
+     * requests access to the display identified by a given ID. If the target EVS display
+     * is not available or is already in use the old instance shall be closed and give
+     * the new caller exclusive access.
+     * When done using the display, the caller may release it by calling closeDisplay().
+     *
+     * @param  id      Target display identifier.
+     * @return display EvsDisplay object to be used.
+     */
+    openDisplay_1_1(uint8_t id) generates (IEvsDisplay display);
+
+    /**
+     * 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
new file mode 100644
index 0000000..6e5695d
--- /dev/null
+++ b/automotive/evs/1.1/default/Android.bp
@@ -0,0 +1,59 @@
+cc_binary {
+    name: "android.hardware.automotive.evs@1.1-service",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    relative_install_path: "hw",
+    srcs: [
+        "service.cpp",
+        "EvsCamera.cpp",
+        "EvsEnumerator.cpp",
+        "EvsDisplay.cpp",
+        "ConfigManager.cpp",
+        "ConfigManagerUtil.cpp",
+        "EvsUltrasonicsArray.cpp",
+    ],
+    init_rc: ["android.hardware.automotive.evs@1.1-service.rc"],
+
+    shared_libs: [
+        "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: [
+        "-O0",
+        "-g",
+    ],
+
+    required: [
+        "evs_default_configuration.xml",
+    ],
+
+    vintf_fragments: [
+        "manifest_android.hardware.automotive.evs@1.1-service.xml",
+    ],
+}
+
+prebuilt_etc {
+    name: "evs_default_configuration.xml",
+    soc_specific: true,
+    src: "resources/evs_default_configuration.xml",
+    sub_dir: "automotive/evs",
+}
diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp
new file mode 100644
index 0000000..986793e
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.cpp
@@ -0,0 +1,512 @@
+/*
+ * 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 <sstream>
+#include <fstream>
+#include <thread>
+
+#include <hardware/gralloc.h>
+#include <utils/SystemClock.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+#include "ConfigManager.h"
+
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+
+
+ConfigManager::~ConfigManager() {
+    /* Nothing to do */
+}
+
+
+void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) {
+    if (aCameraElem == nullptr) {
+        ALOGW("XML file does not have required camera element");
+        return;
+    }
+
+    const XMLElement *curElem = aCameraElem->FirstChildElement();
+    while (curElem != nullptr) {
+        if (!strcmp(curElem->Name(), "group")) {
+            /* camera group identifier */
+            const char *id = curElem->FindAttribute("id")->Value();
+
+            /* create a camera group to be filled */
+            CameraGroupInfo *aCamera = new CameraGroupInfo();
+
+            /* read camera device information */
+            if (!readCameraDeviceInfo(aCamera, curElem)) {
+                ALOGW("Failed to read a camera information of %s", id);
+                delete aCamera;
+                continue;
+            }
+
+            /* camera group synchronization */
+            const char *sync = curElem->FindAttribute("synchronized")->Value();
+            if (!strcmp(sync, "CALIBRATED")) {
+                aCamera->synchronized =
+                    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED;
+            } else if (!strcmp(sync, "APPROXIMATE")) {
+                aCamera->synchronized =
+                    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE;
+            } else {
+                aCamera->synchronized = 0; // Not synchronized
+            }
+
+            /* add a group to hash map */
+            mCameraGroupInfos.insert_or_assign(id, unique_ptr<CameraGroupInfo>(aCamera));
+        } else if (!strcmp(curElem->Name(), "device")) {
+            /* camera unique identifier */
+            const char *id = curElem->FindAttribute("id")->Value();
+
+            /* camera mount location */
+            const char *pos = curElem->FindAttribute("position")->Value();
+
+            /* create a camera device to be filled */
+            CameraInfo *aCamera = new CameraInfo();
+
+            /* read camera device information */
+            if (!readCameraDeviceInfo(aCamera, curElem)) {
+                ALOGW("Failed to read a camera information of %s", id);
+                delete aCamera;
+                continue;
+            }
+
+            /* store read camera module information */
+            mCameraInfo.insert_or_assign(id, unique_ptr<CameraInfo>(aCamera));
+
+            /* assign a camera device to a position group */
+            mCameraPosition[pos].emplace(id);
+        } else {
+            /* ignore other device types */
+            ALOGD("Unknown element %s is ignored", curElem->Name());
+        }
+
+        curElem = curElem->NextSiblingElement();
+    }
+}
+
+
+bool
+ConfigManager::readCameraDeviceInfo(CameraInfo *aCamera,
+                                    const XMLElement *aDeviceElem) {
+    if (aCamera == nullptr || aDeviceElem == nullptr) {
+        return false;
+    }
+
+    /* size information to allocate camera_metadata_t */
+    size_t totalEntries = 0;
+    size_t totalDataSize = 0;
+
+    /* read device capabilities */
+    totalEntries +=
+        readCameraCapabilities(aDeviceElem->FirstChildElement("caps"),
+                               aCamera,
+                               totalDataSize);
+
+
+    /* read camera metadata */
+    totalEntries +=
+        readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"),
+                           aCamera,
+                           totalDataSize);
+
+    /* construct camera_metadata_t */
+    if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
+        ALOGW("Either failed to allocate memory or "
+              "allocated memory was not large enough");
+    }
+
+    return true;
+}
+
+
+size_t
+ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+                                      CameraInfo *aCamera,
+                                      size_t &dataSize) {
+    if (aCapElem == nullptr || aCamera == nullptr) {
+        return 0;
+    }
+
+    string token;
+    const XMLElement *curElem = nullptr;
+
+    /* a list of supported camera parameters/controls */
+    curElem = aCapElem->FirstChildElement("supported_controls");
+    if (curElem != nullptr) {
+        const XMLElement *ctrlElem = curElem->FirstChildElement("control");
+        while (ctrlElem != nullptr) {
+            const char *nameAttr = ctrlElem->FindAttribute("name")->Value();;
+            const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value());
+            const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value());
+
+            int32_t stepVal = 1;
+            const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step");
+            if (stepAttr != nullptr) {
+                stepVal = stoi(stepAttr->Value());
+            }
+
+            CameraParam aParam;
+            if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr,
+                                                           aParam)) {
+                aCamera->controls.emplace(
+                    aParam,
+                    make_tuple(minVal, maxVal, stepVal)
+                );
+            }
+
+            ctrlElem = ctrlElem->NextSiblingElement("control");
+        }
+    }
+
+    /* a list of camera stream configurations */
+    curElem = aCapElem->FirstChildElement("stream");
+    while (curElem != nullptr) {
+        /* read 5 attributes */
+        const XMLAttribute *idAttr     = curElem->FindAttribute("id");
+        const XMLAttribute *widthAttr  = curElem->FindAttribute("width");
+        const XMLAttribute *heightAttr = curElem->FindAttribute("height");
+        const XMLAttribute *fmtAttr    = curElem->FindAttribute("format");
+        const XMLAttribute *fpsAttr    = curElem->FindAttribute("framerate");
+
+        const int32_t id = stoi(idAttr->Value());
+        int32_t framerate = 0;
+        if (fpsAttr != nullptr) {
+            framerate = stoi(fpsAttr->Value());
+        }
+
+        int32_t pixFormat;
+        if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+                                                    pixFormat)) {
+            RawStreamConfiguration cfg = {
+                id,
+                stoi(widthAttr->Value()),
+                stoi(heightAttr->Value()),
+                pixFormat,
+                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+                framerate
+            };
+            aCamera->streamConfigurations.insert_or_assign(id, cfg);
+        }
+
+        curElem = curElem->NextSiblingElement("stream");
+    }
+
+    dataSize = calculate_camera_metadata_entry_data_size(
+                   get_camera_metadata_tag_type(
+                       ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+                   ),
+                   aCamera->streamConfigurations.size() * kStreamCfgSz
+               );
+
+    /* a single camera metadata entry contains multiple stream configurations */
+    return dataSize > 0 ? 1 : 0;
+}
+
+
+size_t
+ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
+                                  CameraInfo *aCamera,
+                                  size_t &dataSize) {
+    if (aParamElem == nullptr || aCamera == nullptr) {
+        return 0;
+    }
+
+    const XMLElement *curElem = aParamElem->FirstChildElement("parameter");
+    size_t numEntries = 0;
+    camera_metadata_tag_t tag;
+    while (curElem != nullptr) {
+        if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(),
+                                                     tag)) {
+            switch(tag) {
+                case ANDROID_LENS_DISTORTION:
+                case ANDROID_LENS_POSE_ROTATION:
+                case ANDROID_LENS_POSE_TRANSLATION:
+                case ANDROID_LENS_INTRINSIC_CALIBRATION: {
+                    /* float[] */
+                    size_t count = 0;
+                    void   *data = ConfigManagerUtil::convertFloatArray(
+                                        curElem->FindAttribute("size")->Value(),
+                                        curElem->FindAttribute("value")->Value(),
+                                        count
+                                   );
+
+                    aCamera->cameraMetadata.insert_or_assign(
+                        tag, make_pair(make_unique<void *>(data), count)
+                    );
+
+                    ++numEntries;
+                    dataSize += calculate_camera_metadata_entry_data_size(
+                                    get_camera_metadata_tag_type(tag), count
+                                );
+
+                    break;
+                }
+
+                case ANDROID_REQUEST_AVAILABLE_CAPABILITIES: {
+                    camera_metadata_enum_android_request_available_capabilities_t *data =
+                        new camera_metadata_enum_android_request_available_capabilities_t[1];
+                    if (ConfigManagerUtil::convertToCameraCapability(
+                            curElem->FindAttribute("value")->Value(), *data)) {
+                                        curElem->FindAttribute("value")->Value(),
+                        aCamera->cameraMetadata.insert_or_assign(
+                            tag, make_pair(make_unique<void *>(data), 1)
+                        );
+
+                        ++numEntries;
+                        dataSize += calculate_camera_metadata_entry_data_size(
+                                        get_camera_metadata_tag_type(tag), 1
+                                    );
+                    }
+                    break;
+                }
+
+                case ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS: {
+                    /* a comma-separated list of physical camera devices */
+                    size_t len = strlen(curElem->FindAttribute("value")->Value());
+                    char *data = new char[len + 1];
+                    memcpy(data,
+                           curElem->FindAttribute("value")->Value(),
+                           len * sizeof(char));
+
+                    /* replace commas with null char */
+                    char *p = data;
+                    while (*p != '\0') {
+                        if (*p == ',') {
+                            *p = '\0';
+                        }
+                        ++p;
+                    }
+
+                    aCamera->cameraMetadata.insert_or_assign(
+                        tag, make_pair(make_unique<void *>(data), len)
+                    );
+
+                    ++numEntries;
+                    dataSize += calculate_camera_metadata_entry_data_size(
+                                    get_camera_metadata_tag_type(tag), len
+                                );
+                    break;
+                }
+
+                default:
+                    ALOGW("Parameter %s is not supported",
+                          curElem->FindAttribute("name")->Value());
+                    break;
+            }
+        }
+
+        curElem = curElem->NextSiblingElement("parameter");
+    }
+
+    return numEntries;
+}
+
+
+bool
+ConfigManager::constructCameraMetadata(CameraInfo *aCamera,
+                                       const size_t totalEntries,
+                                       const size_t totalDataSize) {
+    if (aCamera == nullptr || !aCamera->allocate(totalEntries, totalDataSize)) {
+        ALOGE("Failed to allocate memory for camera metadata");
+        return false;
+    }
+
+    const size_t numStreamConfigs = aCamera->streamConfigurations.size();
+    unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
+    int32_t *ptr = data.get();
+    for (auto &cfg : aCamera->streamConfigurations) {
+        for (auto i = 0; i < kStreamCfgSz; ++i) {
+          *ptr++ = cfg.second[i];
+        }
+    }
+    int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+                                            ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                                            data.get(),
+                                            numStreamConfigs * kStreamCfgSz);
+
+    if (err) {
+        ALOGE("Failed to add stream configurations to metadata, ignored");
+        return false;
+    }
+
+    bool success = true;
+    for (auto &[tag, entry] : aCamera->cameraMetadata) {
+        /* try to add new camera metadata entry */
+        int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+                                                tag,
+                                                entry.first.get(),
+                                                entry.second);
+        if (err) {
+            ALOGE("Failed to add an entry with a tag 0x%X", tag);
+
+            /* may exceed preallocated capacity */
+            ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+                  (long)get_camera_metadata_entry_count(aCamera->characteristics),
+                  (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
+                  (long)get_camera_metadata_data_count(aCamera->characteristics),
+                  (long)get_camera_metadata_data_capacity(aCamera->characteristics));
+            ALOGE("\tCurrent metadata entry requires %ld bytes",
+                  (long)calculate_camera_metadata_entry_data_size(tag, entry.second));
+
+            success = false;
+        }
+    }
+
+    ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+          (long)get_camera_metadata_entry_count(aCamera->characteristics),
+          (long)get_camera_metadata_entry_capacity(aCamera->characteristics),
+          (long)get_camera_metadata_data_count(aCamera->characteristics),
+          (long)get_camera_metadata_data_capacity(aCamera->characteristics));
+
+    return success;
+}
+
+
+void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) {
+    if (aSysElem == nullptr) {
+        return;
+    }
+
+    /*
+     * Please note that this function assumes that a given system XML element
+     * and its child elements follow DTD.  If it does not, it will cause a
+     * segmentation fault due to the failure of finding expected attributes.
+     */
+
+    /* read number of cameras available in the system */
+    const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras");
+    if (xmlElem != nullptr) {
+        mSystemInfo.numCameras =
+            stoi(xmlElem->FindAttribute("value")->Value());
+    }
+}
+
+
+void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) {
+    if (aDisplayElem == nullptr) {
+        ALOGW("XML file does not have required camera element");
+        return;
+    }
+
+    const XMLElement *curDev = aDisplayElem->FirstChildElement("device");
+    while (curDev != nullptr) {
+        const char *id = curDev->FindAttribute("id")->Value();
+        //const char *pos = curDev->FirstAttribute("position")->Value();
+
+        unique_ptr<DisplayInfo> dpy(new DisplayInfo());
+        if (dpy == nullptr) {
+            ALOGE("Failed to allocate memory for DisplayInfo");
+            return;
+        }
+
+        const XMLElement *cap = curDev->FirstChildElement("caps");
+        if (cap != nullptr) {
+            const XMLElement *curStream = cap->FirstChildElement("stream");
+            while (curStream != nullptr) {
+                /* read 4 attributes */
+                const XMLAttribute *idAttr     = curStream->FindAttribute("id");
+                const XMLAttribute *widthAttr  = curStream->FindAttribute("width");
+                const XMLAttribute *heightAttr = curStream->FindAttribute("height");
+                const XMLAttribute *fmtAttr    = curStream->FindAttribute("format");
+
+                const int32_t id = stoi(idAttr->Value());
+                int32_t pixFormat;
+                if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+                                                            pixFormat)) {
+                    RawStreamConfiguration cfg = {
+                        id,
+                        stoi(widthAttr->Value()),
+                        stoi(heightAttr->Value()),
+                        pixFormat,
+                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
+                        0   // unused
+                    };
+                    dpy->streamConfigurations.insert_or_assign(id, cfg);
+                }
+
+                curStream = curStream->NextSiblingElement("stream");
+            }
+        }
+
+        mDisplayInfo.insert_or_assign(id, std::move(dpy));
+        curDev = curDev->NextSiblingElement("device");
+    }
+
+    return;
+}
+
+
+bool ConfigManager::readConfigDataFromXML() noexcept {
+    XMLDocument xmlDoc;
+
+    const int64_t parsingStart = android::elapsedRealtimeNano();
+
+    /* load and parse a configuration file */
+    xmlDoc.LoadFile(mConfigFilePath);
+    if (xmlDoc.ErrorID() != XML_SUCCESS) {
+        ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr());
+        return false;
+    }
+
+    /* retrieve the root element */
+    const XMLElement *rootElem = xmlDoc.RootElement();
+    if (strcmp(rootElem->Name(), "configuration")) {
+        ALOGE("A configuration file is not in the required format.  "
+              "See /etc/automotive/evs/evs_configuration.dtd");
+        return false;
+    }
+
+    /*
+     * parse camera information; this needs to be done before reading system
+     * information
+     */
+    readCameraInfo(rootElem->FirstChildElement("camera"));
+
+    /* parse system information */
+    readSystemInfo(rootElem->FirstChildElement("system"));
+
+    /* parse display information */
+    readDisplayInfo(rootElem->FirstChildElement("display"));
+
+    const int64_t parsingEnd = android::elapsedRealtimeNano();
+    ALOGI("Parsing configuration file takes %lf (ms)",
+          (double)(parsingEnd - parsingStart) / 1000000.0);
+
+
+    return true;
+}
+
+
+std::unique_ptr<ConfigManager> ConfigManager::Create(const char *path) {
+    unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
+
+    /*
+     * Read a configuration from XML file
+     *
+     * If this is too slow, ConfigManager::readConfigDataFromBinary() and
+     * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object
+     * to the filesystem and construct CameraInfo instead; this was
+     * evaluated as 10x faster.
+     */
+    if (!cfgMgr->readConfigDataFromXML()) {
+        return nullptr;
+    } else {
+        return cfgMgr;
+    }
+}
+
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
new file mode 100644
index 0000000..870af1c
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -0,0 +1,318 @@
+/*
+ * 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 CONFIG_MANAGER_H
+#define CONFIG_MANAGER_H
+
+#include <vector>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <tinyxml2.h>
+
+#include <system/camera_metadata.h>
+#include <log/log.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+#include "ConfigManagerUtil.h"
+
+using namespace std;
+using namespace tinyxml2;
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+/*
+ * Plese note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 6;
+typedef std::array<int32_t, kStreamCfgSz> RawStreamConfiguration;
+
+class ConfigManager {
+public:
+    static std::unique_ptr<ConfigManager> Create(const char *path = "");
+    ConfigManager(const ConfigManager&) = delete;
+    ConfigManager& operator=(const ConfigManager&) = delete;
+
+    virtual ~ConfigManager();
+
+    /* Camera device's capabilities and metadata */
+    class CameraInfo {
+    public:
+        CameraInfo() :
+            characteristics(nullptr) {
+            /* Nothing to do */
+        }
+
+        virtual ~CameraInfo() {
+            free_camera_metadata(characteristics);
+        }
+
+        /* Allocate memory for camera_metadata_t */
+        bool allocate(size_t entry_cap, size_t data_cap) {
+            if (characteristics != nullptr) {
+                ALOGE("Camera metadata is already allocated");
+                return false;
+            }
+
+            characteristics = allocate_camera_metadata(entry_cap, data_cap);
+            return characteristics != nullptr;
+        }
+
+        /*
+         * List of supported controls that the master client can program.
+         * Paraemters are stored with its valid range
+         */
+        unordered_map<CameraParam,
+                      tuple<int32_t, int32_t, int32_t>> controls;
+
+        /*
+         * List of supported output stream configurations; each array stores
+         * format, width, height, and direction values in the order.
+         */
+        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+
+        /*
+         * Internal storage for camera metadata.  Each entry holds a pointer to
+         * data and number of elements
+         */
+        unordered_map<camera_metadata_tag_t,
+                      pair<unique_ptr<void *>, size_t>> cameraMetadata;
+
+        /* Camera module characteristics */
+        camera_metadata_t *characteristics;
+    };
+
+    class CameraGroupInfo : public CameraInfo {
+    public:
+        CameraGroupInfo() {}
+
+        /* ID of member camera devices */
+        unordered_set<string> devices;
+
+        /* The capture operation of member camera devices are synchronized */
+        bool synchronized = false;
+    };
+
+    class SystemInfo {
+    public:
+        /* number of available cameras */
+        int32_t numCameras = 0;
+    };
+
+    class DisplayInfo {
+    public:
+        /*
+         * List of supported input stream configurations; each array stores
+         * format, width, height, and direction values in the order.
+         */
+        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+    };
+
+    /*
+     * Return system information
+     *
+     * @return SystemInfo
+     *         Constant reference of SystemInfo.
+     */
+    const SystemInfo &getSystemInfo() {
+        return mSystemInfo;
+    }
+
+    /*
+     * Return a list of cameras
+     *
+     * This function assumes that it is not being called frequently.
+     *
+     * @return vector<string>
+     *         A vector that contains unique camera device identifiers.
+     */
+    vector<string> getCameraList() {
+        vector<string> aList;
+        for (auto &v : mCameraInfo) {
+            aList.emplace_back(v.first);
+        }
+
+        return aList;
+    }
+
+
+    /*
+     * Return a list of cameras
+     *
+     * @return CameraGroupInfo
+     *         A pointer to a camera group identified by a given id.
+     */
+    unique_ptr<CameraGroupInfo>& getCameraGroupInfo(const string& gid) {
+        return mCameraGroupInfos[gid];
+    }
+
+
+    /*
+     * Return a camera metadata
+     *
+     * @param  cameraId
+     *         Unique camera node identifier in string
+     *
+     * @return unique_ptr<CameraInfo>
+     *         A pointer to CameraInfo that is associated with a given camera
+     *         ID.  This returns a null pointer if this does not recognize a
+     *         given camera identifier.
+     */
+    unique_ptr<CameraInfo>& getCameraInfo(const string cameraId) noexcept {
+        return mCameraInfo[cameraId];
+    }
+
+private:
+    /* Constructors */
+    ConfigManager(const char *xmlPath) :
+        mConfigFilePath(xmlPath) {
+    }
+
+    /* System configuration */
+    SystemInfo mSystemInfo;
+
+    /* Internal data structure for camera device information */
+    unordered_map<string, unique_ptr<CameraInfo>> mCameraInfo;
+
+    /* Internal data structure for camera device information */
+    unordered_map<string, unique_ptr<DisplayInfo>> mDisplayInfo;
+
+    /* Camera groups are stored in <groud id, CameraGroupInfo> hash map */
+    unordered_map<string, unique_ptr<CameraGroupInfo>> mCameraGroupInfos;
+
+    /*
+     * Camera positions are stored in <position, camera id set> hash map.
+     * The position must be one of front, rear, left, and right.
+     */
+    unordered_map<string, unordered_set<string>>  mCameraPosition;
+
+    /* A path to XML configuration file */
+    const char *mConfigFilePath;
+
+    /*
+     * Parse a given EVS configuration file and store the information
+     * internally.
+     *
+     * @return bool
+     *         True if it completes parsing a file successfully.
+     */
+    bool readConfigDataFromXML() noexcept;
+
+    /*
+     * read the information of the vehicle
+     *
+     * @param  aSysElem
+     *         A pointer to "system" XML element.
+     */
+    void readSystemInfo(const XMLElement * const aSysElem);
+
+    /*
+     * read the information of camera devices
+     *
+     * @param  aCameraElem
+     *         A pointer to "camera" XML element that may contain multiple
+     *         "device" elements.
+     */
+    void readCameraInfo(const XMLElement * const aCameraElem);
+
+    /*
+     * read display device information
+     *
+     * @param  aDisplayElem
+     *         A pointer to "display" XML element that may contain multiple
+     *         "device" elements.
+     */
+    void readDisplayInfo(const XMLElement * const aDisplayElem);
+
+    /*
+     * read camera device information
+     *
+     * @param  aCamera
+     *         A pointer to CameraInfo that will be completed by this
+     *         method.
+     *         aDeviceElem
+     *         A pointer to "device" XML element that contains camera module
+     *         capability info and its characteristics.
+     *
+     * @return bool
+     *         Return false upon any failure in reading and processing camera
+     *         device information.
+     */
+    bool readCameraDeviceInfo(CameraInfo *aCamera,
+                              const XMLElement *aDeviceElem);
+
+    /*
+     * read camera metadata
+     *
+     * @param  aCapElem
+     *         A pointer to "cap" XML element.
+     * @param  aCamera
+     *         A pointer to CameraInfo that is being filled by this method.
+     * @param  dataSize
+     *         Required size of memory to store camera metadata found in this
+     *         method.  This is calculated in this method and returned to the
+     *         caller for camera_metadata allocation.
+     *
+     * @return size_t
+     *         Number of camera metadata entries
+     */
+    size_t readCameraCapabilities(const XMLElement * const aCapElem,
+                                  CameraInfo *aCamera,
+                                  size_t &dataSize);
+
+    /*
+     * read camera metadata
+     *
+     * @param  aParamElem
+     *         A pointer to "characteristics" XML element.
+     * @param  aCamera
+     *         A pointer to CameraInfo that is being filled by this method.
+     * @param  dataSize
+     *         Required size of memory to store camera metadata found in this
+     *         method.
+     *
+     * @return size_t
+     *         Number of camera metadata entries
+     */
+    size_t readCameraMetadata(const XMLElement * const aParamElem,
+                              CameraInfo *aCamera,
+                              size_t &dataSize);
+
+    /*
+     * construct camera_metadata_t from camera capabilities and metadata
+     *
+     * @param  aCamera
+     *         A pointer to CameraInfo that is being filled by this method.
+     * @param  totalEntries
+     *         Number of camera metadata entries to be added.
+     * @param  totalDataSize
+     *         Sum of sizes of camera metadata entries to be added.
+     *
+     * @return bool
+     *         False if either it fails to allocate memory for camera metadata
+     *         or its size is not large enough to add all found camera metadata
+     *         entries.
+     */
+    bool constructCameraMetadata(CameraInfo *aCamera,
+                                 const size_t totalEntries,
+                                 const size_t totalDataSize);
+};
+#endif // CONFIG_MANAGER_H
+
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
new file mode 100644
index 0000000..d10f236
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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 "ConfigManagerUtil.h"
+
+#include <string>
+#include <sstream>
+#include <linux/videodev2.h>
+
+#include <log/log.h>
+#include <system/graphics-base-v1.0.h>
+
+
+bool ConfigManagerUtil::convertToEvsCameraParam(const string &id,
+                                                CameraParam &camParam) {
+    string trimmed = ConfigManagerUtil::trimString(id);
+    bool success = true;
+
+    if (!trimmed.compare("BRIGHTNESS")) {
+        camParam =  CameraParam::BRIGHTNESS;
+    } else if (!trimmed.compare("CONTRAST")) {
+        camParam =  CameraParam::CONTRAST;
+    } else if (!trimmed.compare("AUTOGAIN")) {
+        camParam =  CameraParam::AUTOGAIN;
+    } else if (!trimmed.compare("GAIN")) {
+        camParam =  CameraParam::GAIN;
+    } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) {
+        camParam =  CameraParam::AUTO_WHITE_BALANCE;
+    } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) {
+        camParam =  CameraParam::WHITE_BALANCE_TEMPERATURE;
+    } else if (!trimmed.compare("SHARPNESS")) {
+        camParam =  CameraParam::SHARPNESS;
+    } else if (!trimmed.compare("AUTO_EXPOSURE")) {
+        camParam =  CameraParam::AUTO_EXPOSURE;
+    } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) {
+        camParam =  CameraParam::ABSOLUTE_EXPOSURE;
+    } else if (!trimmed.compare("ABSOLUTE_FOCUS")) {
+        camParam =  CameraParam::ABSOLUTE_FOCUS;
+    } else if (!trimmed.compare("AUTO_FOCUS")) {
+        camParam =  CameraParam::AUTO_FOCUS;
+    } else if (!trimmed.compare("ABSOLUTE_ZOOM")) {
+        camParam =  CameraParam::ABSOLUTE_ZOOM;
+    } else {
+        success = false;
+    }
+
+    return success;
+}
+
+
+bool ConfigManagerUtil::convertToPixelFormat(const string &format,
+                                             int32_t &pixFormat) {
+    string trimmed = ConfigManagerUtil::trimString(format);
+    bool success = true;
+
+    if (!trimmed.compare("RGBA_8888")) {
+        pixFormat =  HAL_PIXEL_FORMAT_RGBA_8888;
+    } else if (!trimmed.compare("YCRCB_420_SP")) {
+        pixFormat =  HAL_PIXEL_FORMAT_YCRCB_420_SP;
+    } else if (!trimmed.compare("YCBCR_422_I")) {
+        pixFormat =  HAL_PIXEL_FORMAT_YCBCR_422_I;
+    } else {
+        success = false;
+    }
+
+    return success;
+}
+
+
+bool ConfigManagerUtil::convertToMetadataTag(const char *name,
+                                             camera_metadata_tag &aTag) {
+    if (!strcmp(name, "LENS_DISTORTION")) {
+        aTag =  ANDROID_LENS_DISTORTION;
+    } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) {
+        aTag =  ANDROID_LENS_INTRINSIC_CALIBRATION;
+    } else if (!strcmp(name, "LENS_POSE_ROTATION")) {
+        aTag =  ANDROID_LENS_POSE_ROTATION;
+    } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) {
+        aTag =  ANDROID_LENS_POSE_TRANSLATION;
+    } else if (!strcmp(name, "REQUEST_AVAILABLE_CAPABILITIES")) {
+        aTag =  ANDROID_REQUEST_AVAILABLE_CAPABILITIES;
+    } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA_PHYSICAL_IDS")) {
+        aTag =  ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS;
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+
+bool ConfigManagerUtil::convertToCameraCapability(
+    const char *name,
+    camera_metadata_enum_android_request_available_capabilities_t &cap) {
+
+    if (!strcmp(name, "DEPTH_OUTPUT")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT;
+    } else if (!strcmp(name, "LOGICAL_MULTI_CAMERA")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA;
+    } else if (!strcmp(name, "MONOCHROME")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME;
+    } else if (!strcmp(name, "SECURE_IMAGE_DATA")) {
+        cap = ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA;
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+
+float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals,
+                                            size_t &count, const char delimiter) {
+    string size_string(sz);
+    string value_string(vals);
+
+    count = stoi(size_string);
+    float *result = new float[count];
+    stringstream values(value_string);
+
+    int32_t idx = 0;
+    string token;
+    while (getline(values, token, delimiter)) {
+        result[idx++] = stof(token);
+    }
+
+    return result;
+}
+
+
+string ConfigManagerUtil::trimString(const string &src, const string &ws) {
+    const auto s = src.find_first_not_of(ws);
+    if (s == string::npos) {
+        return "";
+    }
+
+    const auto e = src.find_last_not_of(ws);
+    const auto r = e - s + 1;
+
+    return src.substr(s, r);
+}
+
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h
new file mode 100644
index 0000000..1710cac
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.h
@@ -0,0 +1,69 @@
+/*
+ * 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 CONFIG_MANAGER_UTIL_H
+#define CONFIG_MANAGER_UTIL_H
+
+#include <utility>
+#include <string>
+#include <system/camera_metadata.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+using namespace std;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+
+class ConfigManagerUtil {
+public:
+    /**
+     * Convert a given string into V4L2_CID_*
+     */
+    static bool convertToEvsCameraParam(const string &id,
+                                        CameraParam &camParam);
+    /**
+     * Convert a given string into android.hardware.graphics.common.PixelFormat
+     */
+    static bool convertToPixelFormat(const string &format,
+                                     int32_t &pixelFormat);
+    /**
+     * Convert a given string into corresponding camera metadata data tag defined in
+     * system/media/camera/include/system/camera_metadta_tags.h
+     */
+    static bool convertToMetadataTag(const char *name,
+                                     camera_metadata_tag &aTag);
+    /**
+     * Convert a given string into a floating value array
+     */
+    static float *convertFloatArray(const char *sz,
+                                    const char *vals,
+                                    size_t &count,
+                                    const char delimiter = ',');
+    /**
+     * Trim a string
+     */
+    static string trimString(const string &src,
+                             const string &ws = " \n\r\t\f\v");
+
+    /**
+     * Convert a given string to corresponding camera capabilities
+     */
+    static bool convertToCameraCapability(
+        const char *name,
+        camera_metadata_enum_android_request_available_capabilities_t &cap);
+
+};
+
+#endif // CONFIG_MANAGER_UTIL_H
+
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
new file mode 100644
index 0000000..0e69ed4
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -0,0 +1,724 @@
+/*
+ * 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 "android.hardware.automotive.evs@1.1-service"
+
+#include "EvsCamera.h"
+#include "EvsEnumerator.h"
+
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+// Special camera names for which we'll initialize alternate test data
+const char EvsCamera::kCameraName_Backup[] = "backup";
+
+
+// Arbitrary limit on number of graphics buffers allowed to be allocated
+// Safeguards against unreasonable resource consumption and provides a testable limit
+const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
+
+
+EvsCamera::EvsCamera(const char *id,
+                     unique_ptr<ConfigManager::CameraInfo> &camInfo) :
+        mFramesAllowed(0),
+        mFramesInUse(0),
+        mStreamState(STOPPED),
+        mCameraInfo(camInfo) {
+
+    ALOGD("EvsCamera instantiated");
+
+    /* set a camera id */
+    mDescription.v1.cameraId = id;
+
+    /* set camera metadata */
+    mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics,
+                                        get_camera_metadata_size(camInfo->characteristics));
+}
+
+
+EvsCamera::~EvsCamera() {
+    ALOGD("EvsCamera being destroyed");
+    forceShutdown();
+}
+
+
+//
+// This gets called if another caller "steals" ownership of the camera
+//
+void EvsCamera::forceShutdown()
+{
+    ALOGD("EvsCamera forceShutdown");
+
+    // Make sure our output stream is cleaned up
+    // (It really should be already)
+    stopVideoStream();
+
+    // Claim the lock while we work on internal state
+    std::lock_guard <std::mutex> lock(mAccessLock);
+
+    // Drop all the graphics buffers we've been using
+    if (mBuffers.size() > 0) {
+        GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+        for (auto&& rec : mBuffers) {
+            if (rec.inUse) {
+                ALOGE("Error - releasing buffer despite remote ownership");
+            }
+            alloc.free(rec.handle);
+            rec.handle = nullptr;
+        }
+        mBuffers.clear();
+    }
+
+    // Put this object into an unrecoverable error state since somebody else
+    // is going to own the underlying camera now
+    mStreamState = DEAD;
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+Return<void> EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
+    ALOGD("getCameraInfo");
+
+    // Send back our self description
+    _hidl_cb(mDescription.v1);
+    return Void();
+}
+
+
+Return<EvsResult> EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) {
+    ALOGD("setMaxFramesInFlight");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    // If we've been displaced by another owner of the camera, then we can't do anything else
+    if (mStreamState == DEAD) {
+        ALOGE("ignoring setMaxFramesInFlight call when camera has been lost.");
+        return EvsResult::OWNERSHIP_LOST;
+    }
+
+    // We cannot function without at least one video buffer to send data
+    if (bufferCount < 1) {
+        ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested");
+        return EvsResult::INVALID_ARG;
+    }
+
+    // Update our internal state
+    if (setAvailableFrames_Locked(bufferCount)) {
+        return EvsResult::OK;
+    } else {
+        return EvsResult::BUFFER_NOT_AVAILABLE;
+    }
+}
+
+
+Return<EvsResult> EvsCamera::startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream)  {
+    ALOGD("startVideoStream");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    // If we've been displaced by another owner of the camera, then we can't do anything else
+    if (mStreamState == DEAD) {
+        ALOGE("ignoring startVideoStream call when camera has been lost.");
+        return EvsResult::OWNERSHIP_LOST;
+    }
+    if (mStreamState != STOPPED) {
+        ALOGE("ignoring startVideoStream 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)) {
+            ALOGE("Failed to start stream because we couldn't get a graphics buffer");
+            return EvsResult::BUFFER_NOT_AVAILABLE;
+        }
+    }
+
+    // Record the user's callback for use when we have a frame ready
+    mStream = IEvsCameraStream_1_1::castFrom(stream).withDefault(nullptr);
+    if (mStream == nullptr) {
+        ALOGE("Default implementation does not support v1.0 IEvsCameraStream");
+        return EvsResult::INVALID_ARG;
+    }
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = std::thread([this](){ generateFrames(); });
+
+    return EvsResult::OK;
+}
+
+
+Return<void> EvsCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
+    std::lock_guard <std::mutex> lock(mAccessLock);
+    returnBuffer(buffer.bufferId, buffer.memHandle);
+
+    return Void();
+}
+
+
+Return<void> EvsCamera::stopVideoStream()  {
+    ALOGD("stopVideoStream");
+    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 Void();
+}
+
+
+Return<int32_t> EvsCamera::getExtendedInfo(uint32_t opaqueIdentifier)  {
+    ALOGD("getExtendedInfo");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    // For any single digit value, return the index itself as a test value
+    if (opaqueIdentifier <= 9) {
+        return opaqueIdentifier;
+    }
+
+    // Return zero by default as required by the spec
+    return 0;
+}
+
+
+Return<EvsResult> EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int32_t /*opaqueValue*/)  {
+    ALOGD("setExtendedInfo");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    // If we've been displaced by another owner of the camera, then we can't do anything else
+    if (mStreamState == DEAD) {
+        ALOGE("ignoring setExtendedInfo call when camera has been lost.");
+        return EvsResult::OWNERSHIP_LOST;
+    }
+
+    // We don't store any device specific information in this implementation
+    return EvsResult::INVALID_ARG;
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+Return<void> EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
+    ALOGD("getCameraInfo_1_1");
+
+    // Send back our self description
+    _hidl_cb(mDescription);
+    return Void();
+}
+
+
+Return<void> EvsCamera::getPhysicalCameraInfo(const hidl_string& id,
+                                              getCameraInfo_1_1_cb _hidl_cb) {
+    ALOGD("%s", __FUNCTION__);
+
+    // This works exactly same as getCameraInfo_1_1() in default implementation.
+    (void)id;
+    _hidl_cb(mDescription);
+    return Void();
+}
+
+
+Return<EvsResult> EvsCamera::doneWithFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers)  {
+    std::lock_guard <std::mutex> lock(mAccessLock);
+
+    for (auto&& buffer : buffers) {
+        returnBuffer(buffer.bufferId, buffer.buffer.nativeHandle);
+    }
+
+    return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsCamera::pauseVideoStream() {
+    // Default implementation does not support this.
+    return EvsResult::UNDERLYING_SERVICE_ERROR;
+}
+
+
+Return<EvsResult> EvsCamera::resumeVideoStream() {
+    // Default implementation does not support this.
+    return EvsResult::UNDERLYING_SERVICE_ERROR;
+}
+
+
+Return<EvsResult> EvsCamera::setMaster() {
+    // Default implementation does not expect multiple subscribers and therefore
+    // return a success code always.
+    return EvsResult::OK;
+}
+
+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;
+}
+
+
+Return<EvsResult> EvsCamera::unsetMaster() {
+    // Default implementation does not expect multiple subscribers and therefore
+    // return a success code always.
+    return EvsResult::OK;
+}
+
+
+Return<void> EvsCamera::getParameterList(getParameterList_cb _hidl_cb) {
+    hidl_vec<CameraParam> hidlCtrls;
+    hidlCtrls.resize(mCameraInfo->controls.size());
+    unsigned idx = 0;
+    for (auto& [cid, cfg] : mCameraInfo->controls) {
+        hidlCtrls[idx++] = cid;
+    }
+
+    _hidl_cb(hidlCtrls);
+    return Void();
+}
+
+
+Return<void> EvsCamera::getIntParameterRange(CameraParam id,
+                                             getIntParameterRange_cb _hidl_cb) {
+    auto range = mCameraInfo->controls[id];
+    _hidl_cb(get<0>(range), get<1>(range), get<2>(range));
+    return Void();
+}
+
+
+Return<void> EvsCamera::setIntParameter(CameraParam id, int32_t value,
+                                        setIntParameter_cb _hidl_cb) {
+    // Default implementation does not support this.
+    (void)id;
+    (void)value;
+    _hidl_cb(EvsResult::INVALID_ARG, 0);
+    return Void();
+}
+
+
+Return<void> EvsCamera::getIntParameter(CameraParam id,
+                                        getIntParameter_cb _hidl_cb) {
+    // Default implementation does not support this.
+    (void)id;
+    _hidl_cb(EvsResult::INVALID_ARG, 0);
+    return Void();
+}
+
+
+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();
+}
+
+
+Return<void>
+EvsCamera::importExternalBuffers(const hidl_vec<BufferDesc_1_1>& /* buffers */,
+                                 importExternalBuffers_cb _hidl_cb) {
+    ALOGW("%s is not implemented yet.", __FUNCTION__);
+    _hidl_cb(EvsResult::UNDERLYING_SERVICE_ERROR, 0);
+    return {};
+}
+
+
+bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) {
+    if (bufferCount < 1) {
+        ALOGE("Ignoring request to set buffer count to zero");
+        return false;
+    }
+    if (bufferCount > MAX_BUFFERS_IN_FLIGHT) {
+        ALOGE("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;
+        ALOGI("Allocating %d buffers for camera frames", 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
+            ALOGE("Rolling back to previous frame queue size");
+            decreaseAvailableFrames_Locked(added);
+            return false;
+        }
+    } else if (mFramesAllowed > bufferCount) {
+        // A decrease is required
+        unsigned framesToRelease = mFramesAllowed - bufferCount;
+        ALOGI("Returning %d camera frame buffers", 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.
+            ALOGE("Buffer queue shrink failed -- too many buffers currently in use?");
+        }
+    }
+
+    return true;
+}
+
+
+unsigned EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
+    // Acquire the graphics buffer allocator
+    GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+
+    unsigned added = 0;
+
+    while (added < numToAdd) {
+        buffer_handle_t memHandle = nullptr;
+        status_t result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage,
+                                         &memHandle, &mStride, 0, "EvsCamera");
+        if (result != NO_ERROR) {
+            ALOGE("Error %d allocating %d x %d graphics buffer", result, mWidth, mHeight);
+            break;
+        }
+        if (!memHandle) {
+            ALOGE("We didn't get a buffer handle back from the allocator");
+            break;
+        }
+
+        // Find a place to store the new buffer
+        bool stored = false;
+        for (auto&& rec : mBuffers) {
+            if (rec.handle == nullptr) {
+                // Use this existing entry
+                rec.handle = memHandle;
+                rec.inUse = false;
+                stored = true;
+                break;
+            }
+        }
+        if (!stored) {
+            // Add a BufferRecord wrapping this handle to our set of available buffers
+            mBuffers.emplace_back(memHandle);
+        }
+
+        mFramesAllowed++;
+        added++;
+    }
+
+    return added;
+}
+
+
+unsigned EvsCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
+    // Acquire the graphics buffer allocator
+    GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
+
+    unsigned removed = 0;
+
+    for (auto&& rec : mBuffers) {
+        // Is this record not in use, but holding a buffer that we can free?
+        if ((rec.inUse == false) && (rec.handle != nullptr)) {
+            // Release buffer and update the record so we can recognize it as "empty"
+            alloc.free(rec.handle);
+            rec.handle = nullptr;
+
+            mFramesAllowed--;
+            removed++;
+
+            if (removed == numToRemove) {
+                break;
+            }
+        }
+    }
+
+    return removed;
+}
+
+
+// This is the asynchronous frame generation thread that runs in parallel with the
+// main serving thread.  There is one for each active camera instance.
+void EvsCamera::generateFrames() {
+    ALOGD("Frame generation loop started");
+
+    unsigned idx;
+
+    while (true) {
+        bool timeForFrame = false;
+        nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        // 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
+                ALOGW("Skipped a frame because too many are in flight\n");
+            } else {
+                // Identify an available buffer to fill
+                for (idx = 0; idx < mBuffers.size(); idx++) {
+                    if (!mBuffers[idx].inUse) {
+                        if (mBuffers[idx].handle != nullptr) {
+                            // Found an available record, so stop looking
+                            break;
+                        }
+                    }
+                }
+                if (idx >= mBuffers.size()) {
+                    // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
+                    ALOGE("Failed to find an available buffer slot\n");
+                } else {
+                    // We're going to make the frame busy
+                    mBuffers[idx].inUse = true;
+                    mFramesInUse++;
+                    timeForFrame = true;
+                }
+            }
+        }
+
+        if (timeForFrame) {
+            // Assemble the buffer description we'll transmit below
+            BufferDesc_1_1 newBuffer = {};
+            AHardwareBuffer_Desc* pDesc =
+                reinterpret_cast<AHardwareBuffer_Desc *>(&newBuffer.buffer.description);
+            pDesc->width = mWidth;
+            pDesc->height = mHeight;
+            pDesc->layers = 1;
+            pDesc->format = mFormat;
+            pDesc->usage = mUsage;
+            pDesc->stride = mStride;
+            newBuffer.buffer.nativeHandle = mBuffers[idx].handle;
+            newBuffer.pixelSize = sizeof(uint32_t);
+            newBuffer.bufferId = idx;
+            newBuffer.deviceId = mDescription.v1.cameraId;
+            newBuffer.timestamp = elapsedRealtimeNano();
+
+            // Write test data into the image buffer
+            fillTestFrame(newBuffer);
+
+            // Issue the (asynchronous) callback to the client -- can't be holding the lock
+            hidl_vec<BufferDesc_1_1> frames;
+            frames.resize(1);
+            frames[0] = newBuffer;
+            auto result = mStream->deliverFrame_1_1(frames);
+            if (result.isOk()) {
+                ALOGD("Delivered %p as id %d",
+                      newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId);
+            } 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.
+                ALOGE("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);
+                mBuffers[idx].inUse = false;
+                mFramesInUse--;
+
+                break;
+            }
+        }
+
+        // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement
+        static const int kTargetFrameRate = 12;
+        static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate;
+        const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        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()) {
+        ALOGE("Error delivering end of stream marker");
+    }
+
+    return;
+}
+
+
+void EvsCamera::fillTestFrame(const BufferDesc_1_1& buff) {
+    // Lock our output buffer for writing
+    uint32_t *pixels = nullptr;
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&buff.buffer.description);
+    GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+    mapper.lock(buff.buffer.nativeHandle,
+                GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
+                android::Rect(pDesc->width, pDesc->height),
+                (void **) &pixels);
+
+    // If we failed to lock the pixel buffer, we're about to crash, but log it first
+    if (!pixels) {
+        ALOGE("Camera failed to gain access to image buffer for writing");
+    }
+
+    // Fill in the test pixels
+    for (unsigned row = 0; row < pDesc->height; row++) {
+        for (unsigned col = 0; col < pDesc->width; col++) {
+            // Index into the row to check the pixel at this column.
+            // We expect 0xFF in the LSB channel, a vertical gradient in the
+            // second channel, a horitzontal gradient in the third channel, and
+            // 0xFF in the MSB.
+            // The exception is the very first 32 bits which is used for the
+            // time varying frame signature to avoid getting fooled by a static image.
+            uint32_t expectedPixel = 0xFF0000FF           | // MSB and LSB
+                                     ((row & 0xFF) <<  8) | // vertical gradient
+                                     ((col & 0xFF) << 16);  // horizontal gradient
+            if ((row | col) == 0) {
+                static uint32_t sFrameTicker = 0;
+                expectedPixel = (sFrameTicker) & 0xFF;
+                sFrameTicker++;
+            }
+            pixels[col] = expectedPixel;
+        }
+        // Point to the next row
+        // NOTE:  stride retrieved from gralloc is in units of pixels
+        pixels = pixels + pDesc->stride;
+    }
+
+    // Release our output buffer
+    mapper.unlock(buff.buffer.nativeHandle);
+}
+
+
+void EvsCamera::fillTestFrame(const BufferDesc_1_0& buff) {
+    BufferDesc_1_1 newBufDesc = {};
+    AHardwareBuffer_Desc desc = {
+        buff.width,   // width
+        buff.height,  // height
+        1,            // layers, always 1 for EVS
+        buff.format,  // One of AHardwareBuffer_Format
+        buff.usage,   // Combination of AHardwareBuffer_UsageFlags
+        buff.stride,  // Row stride in pixels
+        0,            // Reserved
+        0             // Reserved
+    };
+    memcpy(&desc, &newBufDesc.buffer.description, sizeof(desc));
+    newBufDesc.buffer.nativeHandle = buff.memHandle;
+    newBufDesc.pixelSize = buff.pixelSize;
+    newBufDesc.bufferId = buff.bufferId;
+
+    return fillTestFrame(newBufDesc);
+}
+
+
+void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memHandle) {
+    std::lock_guard <std::mutex> lock(mAccessLock);
+
+    if (memHandle == nullptr) {
+        ALOGE("ignoring doneWithFrame called with null handle");
+    } else if (bufferId >= mBuffers.size()) {
+        ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)",
+              bufferId, mBuffers.size()-1);
+    } else if (!mBuffers[bufferId].inUse) {
+        ALOGE("ignoring doneWithFrame called on frame %d which is already free",
+              bufferId);
+    } else {
+        // Mark the frame as available
+        mBuffers[bufferId].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 (bufferId >= mFramesAllowed) {
+            // Find an empty slot lower in the array (which should always exist in this case)
+            for (auto&& rec : mBuffers) {
+                if (rec.handle == nullptr) {
+                    rec.handle = mBuffers[bufferId].handle;
+                    mBuffers[bufferId].handle = nullptr;
+                    break;
+                }
+            }
+        }
+    }
+}
+
+
+sp<EvsCamera> EvsCamera::Create(const char *deviceName) {
+    unique_ptr<ConfigManager::CameraInfo> nullCamInfo = nullptr;
+
+    return Create(deviceName, nullCamInfo);
+}
+
+
+sp<EvsCamera> EvsCamera::Create(const char *deviceName,
+                                unique_ptr<ConfigManager::CameraInfo> &camInfo,
+                                const Stream *streamCfg) {
+    sp<EvsCamera> evsCamera = new EvsCamera(deviceName, camInfo);
+    if (evsCamera == nullptr) {
+        return nullptr;
+    }
+
+    /* default implementation does not use a given configuration */
+    (void)streamCfg;
+
+    /* Use the first resolution from the list for the testing */
+    auto it = camInfo->streamConfigurations.begin();
+    evsCamera->mWidth = it->second[1];
+    evsCamera->mHeight = it->second[2];
+    evsCamera->mDescription.v1.vendorFlags = 0xFFFFFFFF; // Arbitrary test value
+
+    evsCamera->mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+    evsCamera->mUsage  = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
+                         GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+
+    return evsCamera;
+}
+
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
new file mode 100644
index 0000000..6163a34
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -0,0 +1,163 @@
+/*
+ * 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_EVS_V1_1_EVSCAMERA_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERA_H
+
+#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.1/IEvsDisplay.h>
+#include <ui/GraphicBuffer.h>
+
+#include <thread>
+
+#include "ConfigManager.h"
+
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+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 IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+// From EvsEnumerator.h
+class EvsEnumerator;
+
+
+class EvsCamera : public IEvsCamera {
+public:
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
+    Return<void>      getCameraInfo(getCameraInfo_cb _hidl_cb)  override;
+    Return<EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override;
+    Return<EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& stream) override;
+    Return<void>      stopVideoStream() override;
+    Return<void>      doneWithFrame(const BufferDesc_1_0& buffer) override;
+
+    Return<int32_t>   getExtendedInfo(uint32_t opaqueIdentifier) override;
+    Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+    Return<void>      getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb)  override;
+    Return<void>      getPhysicalCameraInfo(const hidl_string& id,
+                                            getPhysicalCameraInfo_cb _hidl_cb)  override;
+    Return<EvsResult> pauseVideoStream() override;
+    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_1_0>& display) override;
+    Return<EvsResult> unsetMaster() override;
+    Return<void>      getParameterList(getParameterList_cb _hidl_cb) override;
+    Return<void>      getIntParameterRange(CameraParam id,
+                                           getIntParameterRange_cb _hidl_cb) override;
+    Return<void>      setIntParameter(CameraParam id, int32_t value,
+                                      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;
+    Return<void>      importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
+                                            importExternalBuffers_cb _hidl_cb) override;
+
+    static sp<EvsCamera> Create(const char *deviceName);
+    static sp<EvsCamera> Create(const char *deviceName,
+                                unique_ptr<ConfigManager::CameraInfo> &camInfo,
+                                const Stream *streamCfg = nullptr);
+    EvsCamera(const EvsCamera&) = delete;
+    EvsCamera& operator=(const EvsCamera&) = delete;
+
+    virtual ~EvsCamera() override;
+    void forceShutdown();   // This gets called if another caller "steals" ownership of the camera
+
+    const CameraDesc& getDesc() { return mDescription; };
+
+    static const char kCameraName_Backup[];
+
+private:
+    EvsCamera(const char *id,
+              unique_ptr<ConfigManager::CameraInfo> &camInfo);
+    // 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 generateFrames();
+    void fillTestFrame(const BufferDesc_1_0& buff);
+    void fillTestFrame(const BufferDesc_1_1& buff);
+    void returnBuffer(const uint32_t bufferId, const buffer_handle_t memHandle);
+
+    sp<EvsEnumerator> mEnumerator;  // The enumerator object that created this camera
+
+    CameraDesc mDescription = {};   // The properties of this camera
+
+    std::thread mCaptureThread;     // The thread we'll use to synthesize frames
+
+    uint32_t mWidth  = 0;           // Horizontal pixel count in the buffers
+    uint32_t mHeight = 0;           // Vertical pixel count in the buffers
+    uint32_t mFormat = 0;           // Values from android_pixel_format_t
+    uint64_t mUsage  = 0;           // Values from from Gralloc.h
+    uint32_t mStride = 0;           // Bytes per line in the buffers
+
+    sp<IEvsCameraStream_1_1> mStream = nullptr;  // The callback used to deliver each frame
+
+    struct BufferRecord {
+        buffer_handle_t handle;
+        bool inUse;
+
+        explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false) {};
+    };
+
+    std::vector <BufferRecord> mBuffers;  // Graphics buffers to transfer images
+    unsigned mFramesAllowed;              // How many buffers are we currently using
+    unsigned mFramesInUse;                // How many buffers are currently outstanding
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+    StreamStateValues mStreamState;
+
+    // Synchronization necessary to deconflict mCaptureThread from the main service thread
+    std::mutex mAccessLock;
+
+    // Static camera module information
+    unique_ptr<ConfigManager::CameraInfo> &mCameraInfo;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERA_H
diff --git a/automotive/evs/1.1/default/EvsDisplay.cpp b/automotive/evs/1.1/default/EvsDisplay.cpp
new file mode 100644
index 0000000..2b5a4a9
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsDisplay.cpp
@@ -0,0 +1,356 @@
+/*
+ * 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 "android.hardware.automotive.evs@1.1-service"
+
+#include "EvsDisplay.h"
+
+#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 {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+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
+    // NOTE:  These are arbitrary values chosen for testing
+    mInfo.displayId             = "Mock Display";
+    mInfo.vendorFlags           = 3870;
+
+    // Assemble the buffer description we'll use for our render target
+    mBuffer.width       = 320;
+    mBuffer.height      = 240;
+    mBuffer.format      = HAL_PIXEL_FORMAT_RGBA_8888;
+    mBuffer.usage       = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
+    mBuffer.bufferId    = 0x3870;  // Arbitrary magic number for self recognition
+    mBuffer.pixelSize   = 4;
+}
+
+
+EvsDisplay::~EvsDisplay() {
+    ALOGD("EvsDisplay being destroyed");
+    forceShutdown();
+}
+
+
+/**
+ * This gets called if another caller "steals" ownership of the display
+ */
+void EvsDisplay::forceShutdown()
+{
+    ALOGD("EvsDisplay forceShutdown");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    // If the buffer isn't being held by a remote client, release it now as an
+    // optimization to release the resources more quickly than the destructor might
+    // get called.
+    if (mBuffer.memHandle) {
+        // Report if we're going away while a buffer is outstanding
+        if (mFrameBusy) {
+            ALOGE("EvsDisplay going down while client is holding a buffer");
+        }
+
+        // Drop the graphics buffer we've been using
+        GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+        alloc.free(mBuffer.memHandle);
+        mBuffer.memHandle = nullptr;
+    }
+
+    // Put this object into an unrecoverable error state since somebody else
+    // is going to own the display now.
+    mRequestedState = DisplayState::DEAD;
+}
+
+
+/**
+ * Returns basic information about the EVS display provided by the system.
+ * See the description of the DisplayDesc structure for details.
+ */
+Return<void> EvsDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb)  {
+    ALOGD("getDisplayInfo");
+
+    // Send back our self description
+    _hidl_cb(mInfo);
+    return Void();
+}
+
+
+/**
+ * Clients may set the display state to express their desired state.
+ * The HAL implementation must gracefully accept a request for any state
+ * while in any other state, although the response may be to ignore the request.
+ * The display is defined to start in the NOT_VISIBLE state upon initialization.
+ * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and
+ * then begin providing video.  When the display is no longer required, the client
+ * is expected to request the NOT_VISIBLE state after passing the last video frame.
+ */
+Return<EvsResult> EvsDisplay::setDisplayState(DisplayState state) {
+    ALOGD("setDisplayState");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    if (mRequestedState == DisplayState::DEAD) {
+        // This object no longer owns the display -- it's been superceeded!
+        return EvsResult::OWNERSHIP_LOST;
+    }
+
+    // Ensure we recognize the requested state so we don't go off the rails
+    if (state < DisplayState::NUM_STATES) {
+        // Record the requested state
+        mRequestedState = state;
+        return EvsResult::OK;
+    }
+    else {
+        // Turn off the display if asked for an unrecognized state
+        mRequestedState = DisplayState::NOT_VISIBLE;
+        return EvsResult::INVALID_ARG;
+    }
+}
+
+
+/**
+ * The HAL implementation should report the actual current state, which might
+ * transiently differ from the most recently requested state.  Note, however, that
+ * the logic responsible for changing display states should generally live above
+ * the device layer, making it undesirable for the HAL implementation to
+ * spontaneously change display states.
+ */
+Return<DisplayState> EvsDisplay::getDisplayState()  {
+    ALOGD("getDisplayState");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    return mRequestedState;
+}
+
+
+/**
+ * This call returns a handle to a frame buffer associated with the display.
+ * This buffer may be locked and written to by software and/or GL.  This buffer
+ * must be returned via a call to returnTargetBufferForDisplay() even if the
+ * display is no longer visible.
+ */
+// TODO: We need to know if/when our client dies so we can get the buffer back! (blocked b/31632518)
+Return<void> EvsDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb)  {
+    ALOGD("getTargetBuffer");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    if (mRequestedState == DisplayState::DEAD) {
+        ALOGE("Rejecting buffer request from object that lost ownership of the display.");
+        BufferDesc_1_0 nullBuff = {};
+        _hidl_cb(nullBuff);
+        return Void();
+    }
+
+    // If we don't already have a buffer, allocate one now
+    if (!mBuffer.memHandle) {
+        // Allocate the buffer that will hold our displayable image
+        buffer_handle_t handle = nullptr;
+        GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+        status_t result = alloc.allocate(
+            mBuffer.width, mBuffer.height, mBuffer.format, 1, mBuffer.usage,
+            &handle, &mBuffer.stride, 0, "EvsDisplay");
+        if (result != NO_ERROR) {
+            ALOGE("Error %d allocating %d x %d graphics buffer",
+                  result, mBuffer.width, mBuffer.height);
+            BufferDesc_1_0 nullBuff = {};
+            _hidl_cb(nullBuff);
+            return Void();
+        }
+        if (!handle) {
+            ALOGE("We didn't get a buffer handle back from the allocator");
+            BufferDesc_1_0 nullBuff = {};
+            _hidl_cb(nullBuff);
+            return Void();
+        }
+
+        mBuffer.memHandle = handle;
+        mFrameBusy = false;
+        ALOGD("Allocated new buffer %p with stride %u",
+              mBuffer.memHandle.getNativeHandle(), mBuffer.stride);
+    }
+
+    // Do we have a frame available?
+    if (mFrameBusy) {
+        // This means either we have a 2nd client trying to compete for buffers
+        // (an unsupported mode of operation) or else the client hasn't returned
+        // a previously issued buffer yet (they're behaving badly).
+        // NOTE:  We have to make the callback even if we have nothing to provide
+        ALOGE("getTargetBuffer called while no buffers available.");
+        BufferDesc_1_0 nullBuff = {};
+        _hidl_cb(nullBuff);
+        return Void();
+    } else {
+        // Mark our buffer as busy
+        mFrameBusy = true;
+
+        // Send the buffer to the client
+        ALOGD("Providing display buffer handle %p as id %d",
+              mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId);
+        _hidl_cb(mBuffer);
+        return Void();
+    }
+}
+
+
+/**
+ * This call tells the display that the buffer is ready for display.
+ * The buffer is no longer valid for use by the client after this call.
+ */
+Return<EvsResult> EvsDisplay::returnTargetBufferForDisplayImpl(const uint32_t bufferId, const buffer_handle_t memHandle) {
+    ALOGD("returnTargetBufferForDisplay %p", memHandle);
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    // Nobody should call us with a null handle
+    if (!memHandle) {
+        ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n");
+        return EvsResult::INVALID_ARG;
+    }
+    if (bufferId != mBuffer.bufferId) {
+        ALOGE ("Got an unrecognized frame returned.\n");
+        return EvsResult::INVALID_ARG;
+    }
+    if (!mFrameBusy) {
+        ALOGE ("A frame was returned with no outstanding frames.\n");
+        return EvsResult::BUFFER_NOT_AVAILABLE;
+    }
+
+    mFrameBusy = false;
+
+    // If we've been displaced by another owner of the display, then we can't do anything else
+    if (mRequestedState == DisplayState::DEAD) {
+        return EvsResult::OWNERSHIP_LOST;
+    }
+
+    // If we were waiting for a new frame, this is it!
+    if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) {
+        mRequestedState = DisplayState::VISIBLE;
+    }
+
+    // Validate we're in an expected state
+    if (mRequestedState != DisplayState::VISIBLE) {
+        // We shouldn't get frames back when we're not visible.
+        ALOGE ("Got an unexpected frame returned while not visible - ignoring.\n");
+    } else {
+        // This is where the buffer would be made visible.
+        // For now we simply validate it has the data we expect in it by reading it back
+
+        // Lock our display buffer for reading
+        uint32_t* pixels = nullptr;
+        GraphicBufferMapper &mapper = GraphicBufferMapper::get();
+        mapper.lock(mBuffer.memHandle,
+                    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
+                    android::Rect(mBuffer.width, mBuffer.height),
+                    (void **)&pixels);
+
+        // If we failed to lock the pixel buffer, we're about to crash, but log it first
+        if (!pixels) {
+            ALOGE("Display failed to gain access to image buffer for reading");
+        }
+
+        // Check the test pixels
+        bool frameLooksGood = true;
+        for (unsigned row = 0; row < mBuffer.height; row++) {
+            for (unsigned col = 0; col < mBuffer.width; col++) {
+                // Index into the row to check the pixel at this column.
+                // We expect 0xFF in the LSB channel, a vertical gradient in the
+                // second channel, a horitzontal gradient in the third channel, and
+                // 0xFF in the MSB.
+                // The exception is the very first 32 bits which is used for the
+                // time varying frame signature to avoid getting fooled by a static image.
+                uint32_t expectedPixel = 0xFF0000FF           | // MSB and LSB
+                                         ((row & 0xFF) <<  8) | // vertical gradient
+                                         ((col & 0xFF) << 16);  // horizontal gradient
+                if ((row | col) == 0) {
+                    // we'll check the "uniqueness" of the frame signature below
+                    continue;
+                }
+                // Walk across this row (we'll step rows below)
+                uint32_t receivedPixel = pixels[col];
+                if (receivedPixel != expectedPixel) {
+                    ALOGE("Pixel check mismatch in frame buffer");
+                    frameLooksGood = false;
+                    break;
+                }
+            }
+
+            if (!frameLooksGood) {
+                break;
+            }
+
+            // Point to the next row (NOTE:  gralloc reports stride in units of pixels)
+            pixels = pixels + mBuffer.stride;
+        }
+
+        // Ensure we don't see the same buffer twice without it being rewritten
+        static uint32_t prevSignature = ~0;
+        uint32_t signature = pixels[0] & 0xFF;
+        if (prevSignature == signature) {
+            frameLooksGood = false;
+            ALOGE("Duplicate, likely stale frame buffer detected");
+        }
+
+
+        // Release our output buffer
+        mapper.unlock(mBuffer.memHandle);
+
+        if (!frameLooksGood) {
+            return EvsResult::UNDERLYING_SERVICE_ERROR;
+        }
+    }
+
+    return EvsResult::OK;
+}
+
+
+Return<EvsResult> EvsDisplay::returnTargetBufferForDisplay(const BufferDesc_1_0& buffer)  {
+    return returnTargetBufferForDisplayImpl(buffer.bufferId, buffer.memHandle);
+}
+
+
+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
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.1/default/EvsDisplay.h b/automotive/evs/1.1/default/EvsDisplay.h
new file mode 100644
index 0000000..9b2ed90
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsDisplay.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_EVSDISPLAY_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_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_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 {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+class EvsDisplay : public IEvsDisplay {
+public:
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow.
+    Return<void>         getDisplayInfo(getDisplayInfo_cb _hidl_cb)  override;
+    Return<EvsResult>    setDisplayState(DisplayState state)  override;
+    Return<DisplayState> getDisplayState()  override;
+    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
+    Return<EvsResult> returnTargetBufferForDisplayImpl(const uint32_t bufferId,
+                                                       const buffer_handle_t memHandle);
+
+private:
+    DisplayDesc     mInfo           = {};
+    BufferDesc_1_0  mBuffer         = {};       // A graphics buffer into which we'll store images
+
+    bool            mFrameBusy      = false;    // A flag telling us our buffer is in use
+    DisplayState    mRequestedState = DisplayState::NOT_VISIBLE;
+
+    std::mutex      mAccessLock;
+
+    sp<IAutomotiveDisplayProxyService> mDisplayProxy;
+    uint64_t                           mDisplayId;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSDISPLAY_H
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
new file mode 100644
index 0000000..117ee7a
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -0,0 +1,464 @@
+/*
+ * 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 "android.hardware.automotive.evs@1.1-service"
+
+#include "EvsEnumerator.h"
+#include "EvsCamera.h"
+#include "EvsDisplay.h"
+#include "EvsUltrasonicsArray.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+// 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;
+sp<IAutomotiveDisplayProxyService>                  EvsEnumerator::sDisplayProxyService;
+std::unordered_map<uint8_t, uint64_t>               EvsEnumerator::sDisplayPortList;
+std::list<EvsEnumerator::UltrasonicsArrayRecord>    EvsEnumerator::sUltrasonicsArrayRecordList;
+
+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"));
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb)  {
+    ALOGD("getCameraList");
+
+    const unsigned numCameras = sCameraList.size();
+
+    // Build up a packed array of CameraDesc for return
+    // NOTE:  Only has to live until the callback returns
+    std::vector<CameraDesc_1_0> descriptions;
+    descriptions.reserve(numCameras);
+    for (const auto& cam : sCameraList) {
+        descriptions.push_back( cam.desc.v1 );
+    }
+
+    // Encapsulate our camera descriptions in the HIDL vec type
+    hidl_vec<CameraDesc_1_0> hidlCameras(descriptions);
+
+    // Send back the results
+    ALOGD("reporting %zu cameras available", hidlCameras.size());
+    _hidl_cb(hidlCameras);
+
+    // HIDL convention says we return Void if we sent our result back via callback
+    return Void();
+}
+
+
+Return<sp<IEvsCamera_1_0>> EvsEnumerator::openCamera(const hidl_string& cameraId) {
+    ALOGD("openCamera");
+
+    // Find the named camera
+    CameraRecord *pRecord = nullptr;
+    for (auto &&cam : sCameraList) {
+        if (cam.desc.v1.cameraId == cameraId) {
+            // Found a match!
+            pRecord = &cam;
+            break;
+        }
+    }
+
+    // Is this a recognized camera id?
+    if (!pRecord) {
+        ALOGE("Requested camera %s not found", cameraId.c_str());
+        return nullptr;
+    }
+
+    // Has this camera already been instantiated by another caller?
+    sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+    if (pActiveCamera != nullptr) {
+        ALOGW("Killing previous camera because of new caller");
+        closeCamera(pActiveCamera);
+    }
+
+    // Construct a camera instance for the caller
+    if (sConfigManager == nullptr) {
+        pActiveCamera = EvsCamera::Create(cameraId.c_str());
+    } else {
+        pActiveCamera = EvsCamera::Create(cameraId.c_str(),
+                                          sConfigManager->getCameraInfo(cameraId));
+    }
+    pRecord->activeInstance = pActiveCamera;
+    if (pActiveCamera == nullptr) {
+        ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
+    }
+
+    return pActiveCamera;
+}
+
+
+Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera_1_0>& pCamera) {
+    ALOGD("closeCamera");
+
+    auto pCamera_1_1 = IEvsCamera_1_1::castFrom(pCamera).withDefault(nullptr);
+    if (pCamera_1_1 == nullptr) {
+        ALOGE("Ignoring call to closeCamera with null camera ptr");
+        return Void();
+    }
+
+    // Get the camera id so we can find it in our list
+    std::string cameraId;
+    pCamera_1_1->getCameraInfo_1_1([&cameraId](CameraDesc desc) {
+                               cameraId = desc.v1.cameraId;
+                           }
+    );
+
+    // Find the named camera
+    CameraRecord *pRecord = nullptr;
+    for (auto &&cam : sCameraList) {
+        if (cam.desc.v1.cameraId == cameraId) {
+            // Found a match!
+            pRecord = &cam;
+            break;
+        }
+    }
+
+    // Is the display being destroyed actually the one we think is active?
+    if (!pRecord) {
+        ALOGE("Asked to close a camera who's name isn't recognized");
+    } else {
+        sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+
+        if (pActiveCamera == nullptr) {
+            ALOGE("Somehow a camera is being destroyed when the enumerator didn't know one existed");
+        } else if (pActiveCamera != pCamera_1_1) {
+            // This can happen if the camera was aggressively reopened, orphaning this previous instance
+            ALOGW("Ignoring close of previously orphaned camera - why did a client steal?");
+        } else {
+            // Drop the active camera
+            pActiveCamera->forceShutdown();
+            pRecord->activeInstance = nullptr;
+        }
+    }
+
+    return Void();
+}
+
+
+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
+    // 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();
+    sActiveDisplay = pActiveDisplay;
+
+    ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get());
+    return pActiveDisplay;
+}
+
+
+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?
+    sp<EvsDisplay> pActiveDisplay = sActiveDisplay.promote();
+    if (pActiveDisplay == nullptr) {
+        ALOGE("Somehow a display is being destroyed when the enumerator didn't know one existed");
+    } else if (sActiveDisplay != pDisplay) {
+        ALOGW("Ignoring close of previously orphaned display - why did a client steal?");
+    } else {
+        // Drop the active display
+        pActiveDisplay->forceShutdown();
+        sActiveDisplay = nullptr;
+    }
+
+    return Void();
+}
+
+
+Return<DisplayState> EvsEnumerator::getDisplayState()  {
+    ALOGD("getDisplayState");
+
+    // Do we still have a display object we think should be active?
+    sp<IEvsDisplay> pActiveDisplay = sActiveDisplay.promote();
+    if (pActiveDisplay != nullptr) {
+        return pActiveDisplay->getDisplayState();
+    } else {
+        return DisplayState::NOT_OPEN;
+    }
+}
+
+
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+Return<void> EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb)  {
+    ALOGD("getCameraList");
+
+    const unsigned numCameras = sCameraList.size();
+
+    // Build up a packed array of CameraDesc for return
+    // NOTE:  Only has to live until the callback returns
+    std::vector<CameraDesc_1_1> descriptions;
+    descriptions.reserve(numCameras);
+    for (const auto& cam : sCameraList) {
+        descriptions.push_back( cam.desc );
+    }
+
+    // Encapsulate our camera descriptions in the HIDL vec type
+    hidl_vec<CameraDesc_1_1> hidlCameras(descriptions);
+
+    // Send back the results
+    ALOGD("reporting %zu cameras available", hidlCameras.size());
+    _hidl_cb(hidlCameras);
+
+    // HIDL convention says we return Void if we sent our result back via callback
+    return Void();
+}
+
+Return<sp<IEvsCamera_1_1>>
+EvsEnumerator::openCamera_1_1(const hidl_string& cameraId,
+                              const Stream& streamCfg) {
+    // Find the named camera
+    CameraRecord *pRecord = nullptr;
+    for (auto &&cam : sCameraList) {
+        if (cam.desc.v1.cameraId == cameraId) {
+            // Found a match!
+            pRecord = &cam;
+            break;
+        }
+    }
+
+    // Is this a recognized camera id?
+    if (!pRecord) {
+        ALOGE("Requested camera %s not found", cameraId.c_str());
+        return nullptr;
+    }
+
+    // Has this camera already been instantiated by another caller?
+    sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+    if (pActiveCamera != nullptr) {
+        ALOGW("Killing previous camera because of new caller");
+        closeCamera(pActiveCamera);
+    }
+
+    // Construct a camera instance for the caller
+    if (sConfigManager == nullptr) {
+        pActiveCamera = EvsCamera::Create(cameraId.c_str());
+    } else {
+        pActiveCamera = EvsCamera::Create(cameraId.c_str(),
+                                          sConfigManager->getCameraInfo(cameraId),
+                                          &streamCfg);
+    }
+
+    pRecord->activeInstance = pActiveCamera;
+    if (pActiveCamera == nullptr) {
+        ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
+    }
+
+    return pActiveCamera;
+}
+
+
+EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) {
+    // Find the named camera
+    CameraRecord *pRecord = nullptr;
+    for (auto &&cam : sCameraList) {
+        if (cam.desc.v1.cameraId == cameraId) {
+            // Found a match!
+            pRecord = &cam;
+            break;
+        }
+    }
+
+    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
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h
new file mode 100644
index 0000000..d80124b
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -0,0 +1,122 @@
+/*
+ * 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_EVS_V1_1_EVSCAMERAENUMERATOR_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
+
+#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::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 {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+class EvsCamera;    // from EvsCamera.h
+class EvsDisplay;   // from EvsDisplay.h
+class EvsUltrasonicsArray;  // from EvsUltrasonicsArray.h
+
+
+class EvsEnumerator : public IEvsEnumerator {
+public:
+    // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow.
+    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_1_0>> openDisplay()  override;
+    Return<void>                closeDisplay(const ::android::sp<IEvsDisplay_1_0>& display)  override;
+    Return<DisplayState>        getDisplayState()  override;
+
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+    Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb)  override;
+    Return<sp<IEvsCamera_1_1>>  openCamera_1_1(const hidl_string& cameraId,
+                                               const Stream& streamCfg) override;
+    Return<bool> isHardware() override { return true; }
+    Return<void>                getDisplayIdList(getDisplayIdList_cb _list_cb) override;
+    Return<sp<IEvsDisplay_1_1>> openDisplay_1_1(uint8_t port) override;
+    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(sp<IAutomotiveDisplayProxyService> windowService = nullptr);
+
+private:
+    // 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.
+    struct CameraRecord {
+        CameraDesc_1_1      desc;
+        wp<EvsCamera>       activeInstance;
+
+        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
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
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/ServiceNames.h b/automotive/evs/1.1/default/ServiceNames.h
new file mode 100644
index 0000000..84b1697
--- /dev/null
+++ b/automotive/evs/1.1/default/ServiceNames.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const static char kEnumeratorServiceName[] = "hw/0";
diff --git a/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc b/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc
new file mode 100644
index 0000000..284b3fd
--- /dev/null
+++ b/automotive/evs/1.1/default/android.hardware.automotive.evs@1.1-service.rc
@@ -0,0 +1,5 @@
+service vendor.evs-hal-mock /vendor/bin/hw/android.hardware.automotive.evs@1.1-service
+    class hal
+    user automotive_evs
+    group automotive_evs
+    disabled
diff --git a/automotive/evs/1.1/default/manifest_android.hardware.automotive.evs@1.1-service.xml b/automotive/evs/1.1/default/manifest_android.hardware.automotive.evs@1.1-service.xml
new file mode 100644
index 0000000..d4d9b17
--- /dev/null
+++ b/automotive/evs/1.1/default/manifest_android.hardware.automotive.evs@1.1-service.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest version="1.0" type="device" >
+    <hal format="hidl">
+        <name>android.hardware.automotive.evs</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IEvsEnumerator</name>
+            <instance>hw/0</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
new file mode 100644
index 0000000..a79e7c2
--- /dev/null
+++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
@@ -0,0 +1,91 @@
+<?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.
+-->
+
+<!-- Exterior View System Example Configuration
+
+     Android Automotive axes are used to define coordinates.
+     See https://source.android.com/devices/sensors/sensor-types#auto_axes
+
+     Use evs_configuration.dtd with xmllint tool, to validate XML configuration file
+-->
+
+<configuration>
+    <!-- system configuration -->
+    <system>
+        <!-- number of cameras available to EVS -->
+        <num_cameras value='1'/>
+    </system>
+
+    <!-- camera information -->
+    <camera>
+        <!-- camera group starts -->
+        <group id='group1' synchronized='APPROXIMATE'>
+            <caps>
+                <stream id='0' width='640'  height='360'  format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <parameter
+                    name='REQUEST_AVAILABLE_CAPABILITIES'
+                    type='enum'
+                    size='1'
+                    value='LOGICAL_MULTI_CAMERA'
+                />
+                <parameter
+                    name='LOGICAL_MULTI_CAMERA_PHYSICAL_IDS'
+                    type='byte[]'
+                    size='1'
+                    value='/dev/video1'
+                />
+            </characteristics>
+        </group>
+
+        <!-- camera device starts -->
+        <device id='/dev/video1' position='rear'>
+            <caps>
+                <!-- list of supported controls -->
+                <supported_controls>
+                    <control name='BRIGHTNESS' min='0' max='255'/>
+                    <control name='CONTRAST' min='0' max='255'/>
+                </supported_controls>
+
+                <stream id='0' width='640'  height='360'  format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='0.0,0.0,0.0,0.0,0.0'
+                />
+            </characteristics>
+        </device>
+    </camera>
+    <display>
+        <device id='display0' position='driver'>
+            <caps>
+                <!-- list of supported inpu stream configurations -->
+                <stream id='0' width='1280' height='720' format='RGBA_8888' framerate='30'/>
+            </caps>
+        </device>
+    </display>
+</configuration>
+
diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp
new file mode 100644
index 0000000..374b646
--- /dev/null
+++ b/automotive/evs/1.1/default/service.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 "android.hardware.automotive.evs@1.1-service"
+
+#include <unistd.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "ServiceNames.h"
+#include "EvsEnumerator.h"
+#include "EvsDisplay.h"
+
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
+
+// The namespace in which all our implementation code lives
+using namespace android::hardware::automotive::evs::V1_1::implementation;
+using namespace android;
+
+
+int main() {
+    ALOGI("EVS Hardware Enumerator service is starting");
+    android::sp<IEvsEnumerator> service = new EvsEnumerator();
+
+    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).
+    status_t status = service->registerAsService(kEnumeratorServiceName);
+    if (status == OK) {
+        ALOGD("%s is ready.", kEnumeratorServiceName);
+        joinRpcThreadpool();
+    } else {
+        ALOGE("Could not register service %s (%d).", kEnumeratorServiceName, status);
+    }
+
+    // In normal operation, we don't expect the thread pool to exit
+    ALOGE("EVS Hardware Enumerator is shutting down");
+    return 1;
+}
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
new file mode 100644
index 0000000..e699fd0
--- /dev/null
+++ b/automotive/evs/1.1/types.hal
@@ -0,0 +1,377 @@
+/*
+ * 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.automotive.evs@1.1;
+
+import @1.0::CameraDesc;
+import @1.0::DisplayDesc;
+import @1.0::DisplayState;
+import @1.0::EvsResult;
+import android.hardware.graphics.common@1.2::HardwareBuffer;
+import android.hardware.camera.device@3.2::CameraMetadata;
+
+/**
+ * Structure describing the basic properties of an EVS camera, extended from its
+ * v1.0 declaration.
+ *
+ * The HAL is responsible for filling out this structure for each
+ * EVS camera in the system.
+ */
+struct CameraDesc {
+    @1.0::CameraDesc v1;
+    /**
+     * Store camera metadata such as lens characteristics.
+     */
+    CameraMetadata metadata;
+};
+
+/**
+ * Structure representing an image buffer through our APIs
+ *
+ * In addition to the handle to the graphics memory, we need to retain
+ * the properties of the buffer for easy reference and reconstruction of
+ * an ANativeWindowBuffer object on the remote side of API calls.
+ * (Not least because OpenGL expect an ANativeWindowBuffer* for us as a
+ * texture via eglCreateImageKHR().
+ */
+struct BufferDesc {
+    /**
+     * HIDL counterpart of `AHardwareBuffer_Desc`.  Please see
+     * hardware/interfaces/graphics/common/1.2/types.hal for more details.
+     */
+    HardwareBuffer buffer;
+    /**
+     * The size of a pixel in the units of bytes
+     */
+    uint32_t pixelSize;
+    /**
+     * Opaque value from driver
+     */
+    uint32_t bufferId;
+    /**
+     * Unique identifier of the physical camera device that produces this buffer.
+     */
+    string deviceId;
+    /**
+     * Time that this buffer is being filled.
+     */
+    int64_t timestamp;
+
+    /**
+     * Frame metadata.  This is opaque to EVS manager.
+     */
+    vec<uint8_t> metadata;
+};
+
+/**
+ * Types of informative streaming events
+ */
+enum EvsEventType : uint32_t {
+    /**
+     * Video stream is started
+     */
+    STREAM_STARTED = 0,
+    /**
+     * Video stream is stopped
+     */
+    STREAM_STOPPED,
+    /**
+     * Video frame is dropped
+     */
+    FRAME_DROPPED,
+    /**
+     * Timeout happens
+     */
+    TIMEOUT,
+    /**
+     * Camera parameter is changed; payload contains a changed parameter ID and
+     * its value
+     */
+    PARAMETER_CHANGED,
+    /**
+     * Master role has become available
+     */
+    MASTER_RELEASED,
+    /**
+     * Any other erroneous streaming events
+     */
+    STREAM_ERROR,
+};
+
+/**
+ * Structure that describes informative events occurred during EVS is streaming
+ */
+struct EvsEventDesc {
+    /**
+     * Type of an informative event
+     */
+    EvsEventType aType;
+    /**
+     * Device identifier
+     */
+    string deviceId;
+    /**
+     * Possible additional information
+     */
+    uint32_t[4] payload;
+};
+
+/**
+ * EVS Camera Parameter
+ */
+enum CameraParam : uint32_t {
+    /**
+     * The brightness of image frames
+     */
+    BRIGHTNESS,
+    /**
+     * The contrast of image frames
+     */
+    CONTRAST,
+    /**
+     * Automatic gain/exposure control
+     */
+    AUTOGAIN,
+    /**
+     * Gain control
+     */
+    GAIN,
+    /**
+     * Automatic Whitebalance
+     */
+    AUTO_WHITE_BALANCE,
+    /**
+     * Manual white balance setting as a color temperature in Kelvin.
+     */
+    WHITE_BALANCE_TEMPERATURE,
+    /**
+     * Image sharpness adjustment
+     */
+    SHARPNESS,
+    /**
+     * Auto Exposure Control modes; auto, manual, shutter priority, or
+     * aperture priority.
+     */
+    AUTO_EXPOSURE,
+    /**
+     * Manual exposure time of the camera
+     */
+    ABSOLUTE_EXPOSURE,
+    /**
+     * Set the focal point of the camera to the specified position.  This
+     * parameter may not be effective when auto focus is enabled.
+     */
+    ABSOLUTE_FOCUS,
+    /**
+     * Enables continuous automatic focus adjustments.
+     */
+    AUTO_FOCUS,
+    /**
+     * Specify the objective lens focal length as an absolute value.
+     */
+    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
new file mode 100644
index 0000000..086a199
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/Android.bp
@@ -0,0 +1,46 @@
+//
+// 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: "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",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.evs@common-default-lib",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.camera.device@3.2",
+    ],
+    test_suites: ["vts-core"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
new file mode 100644
index 0000000..ebf488a
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -0,0 +1,402 @@
+/*
+ * 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 "VtsHalEvsTest"
+
+#include "FrameHandler.h"
+#include "FormatConvert.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <chrono>
+
+#include <android/log.h>
+#include <cutils/native_handle.h>
+#include <ui/GraphicBuffer.h>
+
+using namespace std::chrono_literals;
+
+FrameHandler::FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
+                           android::sp <IEvsDisplay> pDisplay,
+                           BufferControlFlag mode) :
+    mCamera(pCamera),
+    mCameraInfo(cameraInfo),
+    mDisplay(pDisplay),
+    mReturnMode(mode) {
+    // Nothing but member initialization here...
+}
+
+
+void FrameHandler::shutdown()
+{
+    // Make sure we're not still streaming
+    blockingStopStream();
+
+    // At this point, the receiver thread is no longer running, so we can safely drop
+    // our remote object references so they can be freed
+    mCamera = nullptr;
+    mDisplay = nullptr;
+}
+
+
+bool FrameHandler::startStream() {
+    // Tell the camera to start streaming
+    Return<EvsResult> result = mCamera->startVideoStream(this);
+    if (result != EvsResult::OK) {
+        return false;
+    }
+
+    // Mark ourselves as running
+    mLock.lock();
+    mRunning = true;
+    mLock.unlock();
+
+    return true;
+}
+
+
+void FrameHandler::asyncStopStream() {
+    // Tell the camera to stop streaming.
+    // This will result in a null frame being delivered when the stream actually stops.
+    mCamera->stopVideoStream();
+}
+
+
+void FrameHandler::blockingStopStream() {
+    // Tell the stream to stop
+    asyncStopStream();
+
+    // Wait until the stream has actually stopped
+    std::unique_lock<std::mutex> lock(mEventLock);
+    if (mRunning) {
+        mEventSignal.wait(lock, [this]() { return !mRunning; });
+    }
+}
+
+
+bool FrameHandler::returnHeldBuffer() {
+    std::lock_guard<std::mutex> lock(mLock);
+
+    // Return the oldest buffer we're holding
+    if (mHeldBuffers.empty()) {
+        // No buffers are currently held
+        return false;
+    }
+
+    hidl_vec<BufferDesc_1_1> buffers = mHeldBuffers.front();
+    mHeldBuffers.pop();
+    mCamera->doneWithFrame_1_1(buffers);
+
+    return true;
+}
+
+
+bool FrameHandler::isRunning() {
+    std::lock_guard<std::mutex> lock(mLock);
+    return mRunning;
+}
+
+
+void FrameHandler::waitForFrameCount(unsigned frameCount) {
+    // Wait until we've seen at least the requested number of frames (could be more)
+    std::unique_lock<std::mutex> lock(mLock);
+    mFrameSignal.wait(lock, [this, frameCount](){
+                                return mFramesReceived >= frameCount;
+                            });
+}
+
+
+void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) {
+    std::lock_guard<std::mutex> lock(mLock);
+
+    if (received) {
+        *received = mFramesReceived;
+    }
+    if (displayed) {
+        *displayed = mFramesDisplayed;
+    }
+}
+
+
+Return<void> FrameHandler::deliverFrame(const BufferDesc_1_0& bufferArg) {
+    ALOGW("A frame delivered via v1.0 method is rejected.");
+    mCamera->doneWithFrame(bufferArg);
+    return Void();
+}
+
+
+Return<void> FrameHandler::deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffers) {
+    mLock.lock();
+    // For VTS tests, FrameHandler uses a single frame among delivered frames.
+    auto bufferIdx = mFramesDisplayed % buffers.size();
+    auto buffer = buffers[bufferIdx];
+    mLock.unlock();
+
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&buffer.buffer.description);
+    ALOGD("Received a frame from the camera (%p)",
+          buffer.buffer.nativeHandle.getNativeHandle());
+
+    // Store a dimension of a received frame.
+    mFrameWidth = pDesc->width;
+    mFrameHeight = pDesc->height;
+
+    // If we were given an opened display at construction time, then send the received
+    // image back down the camera.
+    bool displayed = false;
+    if (mDisplay.get()) {
+        // Get the output buffer we'll use to display the imagery
+        BufferDesc_1_0 tgtBuffer = {};
+        mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
+                                      tgtBuffer = buff;
+                                  }
+        );
+
+        if (tgtBuffer.memHandle == nullptr) {
+            printf("Didn't get target buffer - frame lost\n");
+            ALOGE("Didn't get requested output buffer -- skipping this frame.");
+        } else {
+            // Copy the contents of the of buffer.memHandle into tgtBuffer
+            copyBufferContents(tgtBuffer, buffer);
+
+            // Send the target buffer back for display
+            Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+            if (!result.isOk()) {
+                printf("HIDL error on display buffer (%s)- frame lost\n",
+                       result.description().c_str());
+                ALOGE("Error making the remote function call.  HIDL said %s",
+                      result.description().c_str());
+            } else if (result != EvsResult::OK) {
+                printf("Display reported error - frame lost\n");
+                ALOGE("We encountered error %d when returning a buffer to the display!",
+                      (EvsResult) result);
+            } else {
+                // Everything looks good!
+                // Keep track so tests or watch dogs can monitor progress
+                displayed = true;
+            }
+        }
+    }
+
+    mLock.lock();
+    // increases counters
+    ++mFramesReceived;
+    mFramesDisplayed += (int)displayed;
+    mLock.unlock();
+    mFrameSignal.notify_all();
+
+    switch (mReturnMode) {
+    case eAutoReturn:
+        // Send the camera buffer back now that the client has seen it
+        ALOGD("Calling doneWithFrame");
+        mCamera->doneWithFrame_1_1(buffers);
+        break;
+    case eNoAutoReturn:
+        // Hang onto the buffer handles for now -- the client will return it explicitly later
+        mHeldBuffers.push(buffers);
+        break;
+    }
+
+    ALOGD("Frame handling complete");
+
+    return Void();
+}
+
+
+Return<void> FrameHandler::notify(const EvsEventDesc& event) {
+    // Local flag we use to keep track of when the stream is stopping
+    std::unique_lock<std::mutex> lock(mEventLock);
+    mLatestEventDesc.aType = event.aType;
+    mLatestEventDesc.payload[0] = event.payload[0];
+    mLatestEventDesc.payload[1] = event.payload[1];
+    if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) {
+        // Signal that the last frame has been received and the stream is stopped
+        mRunning = false;
+    } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) {
+        ALOGD("Camera parameter 0x%X is changed to 0x%X",
+              mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]);
+    } else {
+        ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
+    }
+    lock.unlock();
+    mEventSignal.notify_one();
+
+    return Void();
+}
+
+
+bool FrameHandler::copyBufferContents(const BufferDesc_1_0& tgtBuffer,
+                                      const BufferDesc_1_1& srcBuffer) {
+    bool success = true;
+    const AHardwareBuffer_Desc* pSrcDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&srcBuffer.buffer.description);
+
+    // Make sure we don't run off the end of either buffer
+    const unsigned width  = std::min(tgtBuffer.width,
+                                     pSrcDesc->width);
+    const unsigned height = std::min(tgtBuffer.height,
+                                     pSrcDesc->height);
+
+    sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(tgtBuffer.memHandle,
+                                                                android::GraphicBuffer::CLONE_HANDLE,
+                                                                tgtBuffer.width,
+                                                                tgtBuffer.height,
+                                                                tgtBuffer.format,
+                                                                1,
+                                                                tgtBuffer.usage,
+                                                                tgtBuffer.stride);
+    sp<android::GraphicBuffer> src = new android::GraphicBuffer(srcBuffer.buffer.nativeHandle,
+                                                                android::GraphicBuffer::CLONE_HANDLE,
+                                                                pSrcDesc->width,
+                                                                pSrcDesc->height,
+                                                                pSrcDesc->format,
+                                                                pSrcDesc->layers,
+                                                                pSrcDesc->usage,
+                                                                pSrcDesc->stride);
+
+    // Lock our source buffer for reading (current expectation are for this to be NV21 format)
+    uint8_t* srcPixels = nullptr;
+    src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
+
+    // Lock our target buffer for writing (should be either RGBA8888 or BGRA8888 format)
+    uint32_t* tgtPixels = nullptr;
+    tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
+
+    if (srcPixels && tgtPixels) {
+        using namespace ::android::hardware::automotive::evs::common;
+        if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) {
+            if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) {   // 420SP == NV21
+                Utils::copyNV21toRGB32(width, height,
+                                       srcPixels,
+                                       tgtPixels, tgtBuffer.stride);
+            } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
+                Utils::copyYV12toRGB32(width, height,
+                                       srcPixels,
+                                       tgtPixels, tgtBuffer.stride);
+            } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
+                Utils::copyYUYVtoRGB32(width, height,
+                                       srcPixels, pSrcDesc->stride,
+                                       tgtPixels, tgtBuffer.stride);
+            } else if (pSrcDesc->format == tgtBuffer.format) {  // 32bit RGBA
+                Utils::copyMatchedInterleavedFormats(width, height,
+                                                     srcPixels, pSrcDesc->stride,
+                                                     tgtPixels, tgtBuffer.stride,
+                                                     tgtBuffer.pixelSize);
+            } else {
+                ALOGE("Camera buffer format is not supported");
+                success = false;
+            }
+        } else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) {
+            if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCRCB_420_SP) {   // 420SP == NV21
+                Utils::copyNV21toBGR32(width, height,
+                                       srcPixels,
+                                       tgtPixels, tgtBuffer.stride);
+            } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
+                Utils::copyYV12toBGR32(width, height,
+                                       srcPixels,
+                                       tgtPixels, tgtBuffer.stride);
+            } else if (pSrcDesc->format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
+                Utils::copyYUYVtoBGR32(width, height,
+                                       srcPixels, pSrcDesc->stride,
+                                       tgtPixels, tgtBuffer.stride);
+            } else if (pSrcDesc->format == tgtBuffer.format) {  // 32bit RGBA
+                Utils::copyMatchedInterleavedFormats(width, height,
+                                                     srcPixels, pSrcDesc->stride,
+                                                     tgtPixels, tgtBuffer.stride,
+                                                     tgtBuffer.pixelSize);
+            } else {
+                ALOGE("Camera buffer format is not supported");
+                success = false;
+            }
+        } else {
+            // We always expect 32 bit RGB for the display output for now.  Is there a need for 565?
+            ALOGE("Diplay buffer is always expected to be 32bit RGBA");
+            success = false;
+        }
+    } else {
+        ALOGE("Failed to lock buffer contents for contents transfer");
+        success = false;
+    }
+
+    if (srcPixels) {
+        src->unlock();
+    }
+    if (tgtPixels) {
+        tgt->unlock();
+    }
+
+    return success;
+}
+
+void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) {
+    if (width) {
+        *width = mFrameWidth;
+    }
+
+    if (height) {
+        *height = mFrameHeight;
+    }
+}
+
+bool FrameHandler::waitForEvent(const EvsEventDesc& aTargetEvent,
+                                      EvsEventDesc& aReceivedEvent,
+                                      bool ignorePayload) {
+    // Wait until we get an expected parameter change event.
+    std::unique_lock<std::mutex> lock(mEventLock);
+    auto now = std::chrono::system_clock::now();
+    bool found = false;
+    while (!found) {
+        bool result = mEventSignal.wait_until(lock, now + 5s,
+            [this, aTargetEvent, ignorePayload, &aReceivedEvent, &found](){
+                found = (mLatestEventDesc.aType == aTargetEvent.aType) &&
+                        (ignorePayload || (mLatestEventDesc.payload[0] == aTargetEvent.payload[0] &&
+                                           mLatestEventDesc.payload[1] == aTargetEvent.payload[1]));
+
+                aReceivedEvent.aType = mLatestEventDesc.aType;
+                aReceivedEvent.payload[0] = mLatestEventDesc.payload[0];
+                aReceivedEvent.payload[1] = mLatestEventDesc.payload[1];
+                return found;
+            }
+        );
+
+        if (!result) {
+            ALOGW("A timer is expired before a target event has happened.");
+            break;
+        }
+    }
+
+    return found;
+}
+
+const char *FrameHandler::eventToString(const EvsEventType aType) {
+    switch (aType) {
+        case EvsEventType::STREAM_STARTED:
+            return "STREAM_STARTED";
+        case EvsEventType::STREAM_STOPPED:
+            return "STREAM_STOPPED";
+        case EvsEventType::FRAME_DROPPED:
+            return "FRAME_DROPPED";
+        case EvsEventType::TIMEOUT:
+            return "TIMEOUT";
+        case EvsEventType::PARAMETER_CHANGED:
+            return "PARAMETER_CHANGED";
+        case EvsEventType::MASTER_RELEASED:
+            return "MASTER_RELEASED";
+        default:
+            return "Unknown";
+    }
+}
+
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
new file mode 100644
index 0000000..21e85fe
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -0,0 +1,118 @@
+/*
+ * 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 EVS_VTS_FRAMEHANDLER_H
+#define EVS_VTS_FRAMEHANDLER_H
+
+#include <queue>
+
+#include <FrameHandler.h>
+
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::sp;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
+using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
+
+
+/*
+ * FrameHandler:
+ * This class can be used to receive camera imagery from an IEvsCamera implementation.  Given an
+ * IEvsDisplay instance at startup, it will forward the received imagery to the display,
+ * providing a trivial implementation of a rear vew camera type application.
+ * Note that the video frames are delivered on a background thread, while the control interface
+ * is actuated from the applications foreground thread.
+ */
+class FrameHandler : public IEvsCameraStream {
+public:
+    enum BufferControlFlag {
+        eAutoReturn,
+        eNoAutoReturn,
+    };
+
+    FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
+                 android::sp <IEvsDisplay> pDisplay = nullptr,
+                 BufferControlFlag mode = eAutoReturn);
+    virtual ~FrameHandler() {
+        if (mCamera != nullptr) {
+            /* shutdown a camera explicitly */
+            shutdown();
+        }
+    }
+
+    void shutdown();
+
+    bool startStream();
+    void asyncStopStream();
+    void blockingStopStream();
+
+    bool returnHeldBuffer();
+
+    bool isRunning();
+
+    void waitForFrameCount(unsigned frameCount);
+    bool waitForEvent(const EvsEventDesc& aTargetEvent,
+                            EvsEventDesc& aReceivedEvent,
+                            bool ignorePayload = false);
+    void getFramesCounters(unsigned* received, unsigned* displayed);
+    void getFrameDimension(unsigned* width, unsigned* height);
+
+private:
+    // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
+    Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
+
+    // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+    Return<void> deliverFrame_1_1(const hidl_vec<BufferDesc_1_1>& buffer) override;
+    Return<void> notify(const EvsEventDesc& event) override;
+
+    // Local implementation details
+    bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer);
+    const char *eventToString(const EvsEventType aType);
+
+    // Values initialized as startup
+    android::sp <IEvsCamera>    mCamera;
+    CameraDesc                  mCameraInfo;
+    android::sp <IEvsDisplay>   mDisplay;
+    BufferControlFlag           mReturnMode;
+
+    // Since we get frames delivered to us asynchronously via the IEvsCameraStream interface,
+    // we need to protect all member variables that may be modified while we're streaming
+    // (ie: those below)
+    std::mutex                            mLock;
+    std::mutex                            mEventLock;
+    std::condition_variable               mEventSignal;
+    std::condition_variable               mFrameSignal;
+    std::queue<hidl_vec<BufferDesc_1_1>>  mHeldBuffers;
+
+    bool                        mRunning = false;
+    unsigned                    mFramesReceived = 0;    // Simple counter -- rolls over eventually!
+    unsigned                    mFramesDisplayed = 0;   // Simple counter -- rolls over eventually!
+    unsigned                    mFrameWidth = 0;
+    unsigned                    mFrameHeight = 0;
+    EvsEventDesc                mLatestEventDesc;
+};
+
+
+#endif //EVS_VTS_FRAMEHANDLER_H
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
new file mode 100644
index 0000000..8b68fd6
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -0,0 +1,2480 @@
+/*
+ * 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 "VtsHalEvsTest"
+
+
+// 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;
+
+static const int kSecondsToMilliseconds = 1000;
+static const int kMillisecondsToMicroseconds = 1000;
+static const float kNanoToMilliseconds = 0.000001f;
+static const float kNanoToSeconds = 0.000000001f;
+
+
+#include "FrameHandler.h"
+#include "FrameHandlerUltrasonics.h"
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <thread>
+#include <unordered_set>
+
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/ProcessState.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.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.1/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android-base/logging.h>
+#include <system/camera_metadata.h>
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.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;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::wp;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::automotive::evs::V1_1::BufferDesc;
+using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+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
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 5;
+typedef struct {
+    int32_t width;
+    int32_t height;
+    int32_t format;
+    int32_t direction;
+    int32_t framerate;
+} RawStreamConfig;
+
+
+// The main test class for EVS
+class EvsHidlTest : public ::testing::TestWithParam<std::string> {
+public:
+    virtual void SetUp() override {
+        // Make sure we can connect to the enumerator
+        std::string service_name = GetParam();
+        pEnumerator = IEvsEnumerator::getService(service_name);
+        ASSERT_NE(pEnumerator.get(), nullptr);
+        LOG(INFO) << "Test target service: " << service_name;
+
+        mIsHwModule = pEnumerator->isHardware();
+    }
+
+    virtual void TearDown() override {
+        // Attempt to close any active camera
+        for (auto &&cam : activeCameras) {
+            if (cam != nullptr) {
+                pEnumerator->closeCamera(cam);
+            }
+        }
+        activeCameras.clear();
+    }
+
+protected:
+    void loadCameraList() {
+        // SetUp() must run first!
+        assert(pEnumerator != nullptr);
+
+        // Get the camera list
+        pEnumerator->getCameraList_1_1(
+            [this](hidl_vec <CameraDesc> cameraList) {
+                LOG(INFO) << "Camera list callback received "
+                          << cameraList.size()
+                          << " cameras";
+                cameraInfo.reserve(cameraList.size());
+                for (auto&& cam: cameraList) {
+                    LOG(INFO) << "Found camera " << cam.v1.cameraId;
+                    cameraInfo.push_back(cam);
+                }
+            }
+        );
+    }
+
+    void loadUltrasonicsArrayList() {
+        // SetUp() must run first!
+        assert(pEnumerator != nullptr);
+
+        // Get the ultrasonics array list
+        pEnumerator->getUltrasonicsArrayList([this](hidl_vec<UltrasonicsArrayDesc> ultraList) {
+            LOG(INFO) << "Ultrasonics array list callback received "
+                      << ultraList.size()
+                      << " arrays";
+            ultrasonicsArraysInfo.reserve(ultraList.size());
+            for (auto&& ultraArray : ultraList) {
+                LOG(INFO) << "Found ultrasonics array " << ultraArray.ultrasonicsArrayId;
+                ultrasonicsArraysInfo.push_back(ultraArray);
+            }
+        });
+    }
+
+    bool isLogicalCamera(const camera_metadata_t *metadata) {
+        if (metadata == nullptr) {
+            // A logical camera device must have a valid camera metadata.
+            return false;
+        }
+
+        // Looking for LOGICAL_MULTI_CAMERA capability from metadata.
+        camera_metadata_ro_entry_t entry;
+        int rc = find_camera_metadata_ro_entry(metadata,
+                                               ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                               &entry);
+        if (0 != rc) {
+            // No capabilities are found.
+            return false;
+        }
+
+        for (size_t i = 0; i < entry.count; ++i) {
+            uint8_t cap = entry.data.u8[i];
+            if (cap == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    std::unordered_set<std::string> getPhysicalCameraIds(const std::string& id,
+                                                         bool& flag) {
+        std::unordered_set<std::string> physicalCameras;
+
+        auto it = cameraInfo.begin();
+        while (it != cameraInfo.end()) {
+            if (it->v1.cameraId == id) {
+                break;
+            }
+            ++it;
+        }
+
+        if (it == cameraInfo.end()) {
+            // Unknown camera is requested.  Return an empty list.
+            return physicalCameras;
+        }
+
+        const camera_metadata_t *metadata =
+            reinterpret_cast<camera_metadata_t *>(&it->metadata[0]);
+        flag = isLogicalCamera(metadata);
+        if (!flag) {
+            // EVS assumes that the device w/o a valid metadata is a physical
+            // device.
+            LOG(INFO) << id << " is not a logical camera device.";
+            physicalCameras.emplace(id);
+            return physicalCameras;
+        }
+
+        // Look for physical camera identifiers
+        camera_metadata_ro_entry entry;
+        int rc = find_camera_metadata_ro_entry(metadata,
+                                               ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
+                                               &entry);
+        if (rc != 0) {
+            LOG(ERROR) << "No physical camera ID is found for a logical camera device";
+        }
+
+        const uint8_t *ids = entry.data.u8;
+        size_t start = 0;
+        for (size_t i = 0; i < entry.count; ++i) {
+            if (ids[i] == '\0') {
+                if (start != i) {
+                    std::string id(reinterpret_cast<const char *>(ids + start));
+                    physicalCameras.emplace(id);
+                }
+                start = i + 1;
+            }
+        }
+
+        LOG(INFO) << id
+                  << " consists of "
+                  << physicalCameras.size()
+                  << " physical camera devices";
+        return physicalCameras;
+    }
+
+
+    sp<IEvsEnumerator>              pEnumerator;   // Every test needs access to the service
+    std::vector<CameraDesc>         cameraInfo;    // Empty unless/until loadCameraList() is called
+    bool                            mIsHwModule;   // boolean to tell current module under testing
+                                                   // is HW module implementation.
+    std::deque<sp<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.
+};
+
+
+// Test cases, their implementations, and corresponding requirements are
+// documented at go/aae-evs-public-api-test.
+
+/*
+ * CameraOpenClean:
+ * 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_P(EvsHidlTest, CameraOpenClean) {
+    LOG(INFO) << "Starting CameraOpenClean test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // Open and close each camera twice
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            LOG(INFO) << "Skip a logical device, " << cam.v1.cameraId << " for HW target.";
+            continue;
+        }
+
+        for (int pass = 0; pass < 2; pass++) {
+            sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg);
+            ASSERT_NE(pCam, nullptr);
+
+            for (auto&& devName : devices) {
+                bool matched = false;
+                pCam->getPhysicalCameraInfo(devName,
+                                            [&devName, &matched](const CameraDesc& info) {
+                                                matched = devName == info.v1.cameraId;
+                                            });
+                ASSERT_TRUE(matched);
+            }
+
+            // Store a camera handle for a clean-up
+            activeCameras.push_back(pCam);
+
+            // Verify that this camera self-identifies correctly
+            pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
+                                        LOG(DEBUG) << "Found camera " << desc.v1.cameraId;
+                                        EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+                                    }
+            );
+
+            // 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_NE(EvsResult::INVALID_ARG, err);
+
+            pCam->getExtendedInfo_1_1(id, [](const auto& result, const auto& data) {
+                ASSERT_NE(EvsResult::INVALID_ARG, result);
+                ASSERT_EQ(0, data.size());
+            });
+
+            // Explicitly close the camera so resources are released right away
+            pEnumerator->closeCamera(pCam);
+            activeCameras.clear();
+        }
+    }
+}
+
+
+/*
+ * CameraOpenAggressive:
+ * Opens each camera reported by the enumerator twice in a row without an intervening closeCamera
+ * 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_P(EvsHidlTest, CameraOpenAggressive) {
+    LOG(INFO) << "Starting CameraOpenAggressive test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // Open and close each camera twice
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            LOG(INFO) << "Skip a logical device, " << cam.v1.cameraId << " for HW target.";
+            continue;
+        }
+
+        activeCameras.clear();
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
+        // Verify that this camera self-identifies correctly
+        pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
+                                    LOG(DEBUG) << "Found camera " << desc.v1.cameraId;
+                                    EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+                                }
+        );
+
+        sp<IEvsCamera_1_1> pCam2 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam2, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam2);
+
+        ASSERT_NE(pCam, pCam2);
+
+        Return<EvsResult> result = pCam->setMaxFramesInFlight(2);
+        if (mIsHwModule) {
+            // Verify that the old camera rejects calls via HW module.
+            EXPECT_EQ(EvsResult::OWNERSHIP_LOST, EvsResult(result));
+        } else {
+            // default implementation supports multiple clients.
+            EXPECT_EQ(EvsResult::OK, EvsResult(result));
+        }
+
+        // Close the superceded camera
+        pEnumerator->closeCamera(pCam);
+        activeCameras.pop_front();
+
+        // Verify that the second camera instance self-identifies correctly
+        pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) {
+                                     LOG(DEBUG) << "Found camera " << desc.v1.cameraId;
+                                     EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+                                 }
+        );
+
+        // Close the second camera instance
+        pEnumerator->closeCamera(pCam2);
+        activeCameras.pop_front();
+    }
+
+    // Sleep here to ensure the destructor cleanup has time to run so we don't break follow on tests
+    sleep(1);   // I hate that this is an arbitrary time to wait.  :(  b/36122635
+}
+
+
+/*
+ * CameraStreamPerformance:
+ * Measure and qualify the stream start up time and streaming frame rate of each reported camera
+ */
+TEST_P(EvsHidlTest, CameraStreamPerformance) {
+    LOG(INFO) << "Starting CameraStreamPerformance test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
+            continue;
+        }
+
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
+        // Set up a frame receiver object which will fire up its own thread
+        sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+                                                         nullptr,
+                                                         FrameHandler::eAutoReturn);
+
+        // Start the camera's video stream
+        nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        bool startResult = frameHandler->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the first frame arrived within the expected time
+        frameHandler->waitForFrameCount(1);
+        nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+        nsecs_t timeToFirstFrame = systemTime(SYSTEM_TIME_MONOTONIC) - start;
+
+        // Extra delays are expected when we attempt to start a video stream on
+        // the logical camera device.  The amount of delay is expected the
+        // number of physical camera devices multiplied by
+        // kMaxStreamStartMilliseconds at most.
+        EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame),
+                  kMaxStreamStartMilliseconds * devices.size());
+        printf("%s: Measured time to first frame %0.2f ms\n",
+               cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
+        LOG(INFO) << cam.v1.cameraId
+                  << ": Measured time to first frame "
+                  << std::scientific << timeToFirstFrame * kNanoToMilliseconds
+                  << " ms.";
+
+        // Check aspect ratio
+        unsigned width = 0, height = 0;
+        frameHandler->getFrameDimension(&width, &height);
+        EXPECT_GE(width, height);
+
+        // Wait a bit, then ensure we get at least the required minimum number of frames
+        sleep(5);
+        nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        // Even when the camera pointer goes out of scope, the FrameHandler object will
+        // keep the stream alive unless we tell it to shutdown.
+        // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+        // we have to break that cycle in order for either of them to get cleaned up.
+        frameHandler->shutdown();
+
+        unsigned framesReceived = 0;
+        frameHandler->getFramesCounters(&framesReceived, nullptr);
+        framesReceived = framesReceived - 1;    // Back out the first frame we already waited for
+        nsecs_t runTime = end - firstFrame;
+        float framesPerSecond = framesReceived / (runTime * kNanoToSeconds);
+        printf("Measured camera rate %3.2f fps\n", framesPerSecond);
+        LOG(INFO) << "Measured camera rate "
+                  << std::scientific << framesPerSecond
+                  << " fps.";
+        EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond);
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
+    }
+}
+
+
+/*
+ * CameraStreamBuffering:
+ * 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_P(EvsHidlTest, CameraStreamBuffering) {
+    LOG(INFO) << "Starting CameraStreamBuffering test";
+
+    // Arbitrary constant (should be > 1 and less than crazy)
+    static const unsigned int kBuffersToHold = 6;
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId << " for HW target.";
+            continue;
+        }
+
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
+        // Ask for a crazy number of buffers in flight to ensure it errors correctly
+        Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
+        EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
+
+        // Now ask for exactly two buffers in flight as we'll test behavior in that case
+        Return<EvsResult> goodResult = pCam->setMaxFramesInFlight(kBuffersToHold);
+        EXPECT_EQ(EvsResult::OK, goodResult);
+
+
+        // Set up a frame receiver object which will fire up its own thread.
+        sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+                                                         nullptr,
+                                                         FrameHandler::eNoAutoReturn);
+
+        // Start the camera's video stream
+        bool startResult = frameHandler->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Check that the video stream stalls once we've gotten exactly the number of buffers
+        // we requested since we told the frameHandler not to return them.
+        sleep(1);   // 1 second should be enough for at least 5 frames to be delivered worst case
+        unsigned framesReceived = 0;
+        frameHandler->getFramesCounters(&framesReceived, nullptr);
+        ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
+
+
+        // Give back one buffer
+        bool didReturnBuffer = frameHandler->returnHeldBuffer();
+        EXPECT_TRUE(didReturnBuffer);
+
+        // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one
+        // filled since we require 10fps minimum -- but give a 10% allowance just in case.
+        usleep(110 * kMillisecondsToMicroseconds);
+        frameHandler->getFramesCounters(&framesReceived, nullptr);
+        EXPECT_EQ(kBuffersToHold+1, framesReceived) << "Stream should've resumed";
+
+        // Even when the camera pointer goes out of scope, the FrameHandler object will
+        // keep the stream alive unless we tell it to shutdown.
+        // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+        // we have to break that cycle in order for either of them to get cleaned up.
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
+    }
+}
+
+
+/*
+ * CameraToDisplayRoundTrip:
+ * End to end test of data flowing from the camera to the display.  Each delivered frame of camera
+ * 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_P(EvsHidlTest, CameraToDisplayRoundTrip) {
+    LOG(INFO) << "Starting CameraToDisplayRoundTrip test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // 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);
+    LOG(INFO) << "Display " << targetDisplayId << " is alreay in use.";
+
+    // 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();
+        LOG(INFO) << "    Resolution: " << width << "x" << 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) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId << " for HW target.";
+            continue;
+        }
+
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
+        // Set up a frame receiver object which will fire up its own thread.
+        sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+                                                         pDisplay,
+                                                         FrameHandler::eAutoReturn);
+
+
+        // Activate the display
+        pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+        // Start the camera's video stream
+        bool startResult = frameHandler->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Wait a while to let the data flow
+        static const int kSecondsToWait = 5;
+        const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds -
+                                 kMaxStreamStartMilliseconds;
+        const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond /
+                                               kSecondsToMilliseconds;
+        sleep(kSecondsToWait);
+        unsigned framesReceived = 0;
+        unsigned framesDisplayed = 0;
+        frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+        EXPECT_EQ(framesReceived, framesDisplayed);
+        EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+        // Turn off the display (yes, before the stream stops -- it should be handled)
+        pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+        // Shut down the streamer
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
+    }
+
+    // Explicitly release the display
+    pEnumerator->closeDisplay(pDisplay);
+}
+
+
+/*
+ * MultiCameraStream:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera.
+ */
+TEST_P(EvsHidlTest, MultiCameraStream) {
+    LOG(INFO) << "Starting MultiCameraStream test";
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // Create two camera clients.
+        sp<IEvsCamera_1_1> pCam0 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam0, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam0);
+
+        sp<IEvsCamera_1_1> pCam1 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam1, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam1);
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+                                                          nullptr,
+                                                          FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandler0, nullptr);
+
+        sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+                                                          nullptr,
+                                                          FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandler1, nullptr);
+
+        // Start the camera's video stream via client 0
+        bool startResult = false;
+        startResult = frameHandler0->startStream() &&
+                      frameHandler1->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandler0->waitForFrameCount(1);
+        frameHandler1->waitForFrameCount(1);
+
+        nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        // Wait a bit, then ensure both clients get at least the required minimum number of frames
+        sleep(5);
+        nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+        unsigned framesReceived0 = 0, framesReceived1 = 0;
+        frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+        framesReceived0 = framesReceived0 - 1;    // Back out the first frame we already waited for
+        framesReceived1 = framesReceived1 - 1;    // Back out the first frame we already waited for
+        nsecs_t runTime = end - firstFrame;
+        float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+        float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+        LOG(INFO) << "Measured camera rate "
+                  << std::scientific << framesPerSecond0 << " fps and "
+                  << framesPerSecond1 << " fps";
+        EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+        EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+        // Shutdown one client
+        frameHandler0->shutdown();
+
+        // Read frame counters again
+        frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+        // Wait a bit again
+        sleep(5);
+        unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+        frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+        EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+        EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+        // Shutdown another
+        frameHandler1->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam0);
+        pEnumerator->closeCamera(pCam1);
+        activeCameras.clear();
+
+        // TODO(b/145459970, b/145457727): below sleep() is added to ensure the
+        // destruction of active camera objects; this may be related with two
+        // issues.
+        sleep(1);
+    }
+}
+
+
+/*
+ * CameraParameter:
+ * Verify that a client can adjust a camera parameter.
+ */
+TEST_P(EvsHidlTest, CameraParameter) {
+    LOG(INFO) << "Starting CameraParameter test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // Test each reported camera
+    Return<EvsResult> result = EvsResult::OK;
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (isLogicalCam) {
+            // TODO(b/145465724): Support camera parameter programming on
+            // logical devices.
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
+            continue;
+        }
+
+        // Create a camera client
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // Store a camera
+        activeCameras.push_back(pCam);
+
+        // Get the parameter list
+        std::vector<CameraParam> cmds;
+        pCam->getParameterList([&cmds](hidl_vec<CameraParam> cmdList) {
+                cmds.reserve(cmdList.size());
+                for (auto &&cmd : cmdList) {
+                    cmds.push_back(cmd);
+                }
+            }
+        );
+
+        if (cmds.size() < 1) {
+            continue;
+        }
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+                                                         nullptr,
+                                                         FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandler, nullptr);
+
+        // Start the camera's video stream
+        bool startResult = frameHandler->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandler->waitForFrameCount(1);
+
+        result = pCam->setMaster();
+        ASSERT_EQ(EvsResult::OK, result);
+
+        for (auto &cmd : cmds) {
+            // Get a valid parameter value range
+            int32_t minVal, maxVal, step;
+            pCam->getIntParameterRange(
+                cmd,
+                [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+                    minVal = val0;
+                    maxVal = val1;
+                    step   = val2;
+                }
+            );
+
+            EvsResult result = EvsResult::OK;
+            if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+                // Try to turn off auto-focus
+                std::vector<int32_t> values;
+                pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &values](auto status, auto effectiveValues) {
+                                       result = status;
+                                       if (status == EvsResult::OK) {
+                                          for (auto &&v : effectiveValues) {
+                                              values.push_back(v);
+                                          }
+                                       }
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                for (auto &&v : values) {
+                    ASSERT_EQ(v, 0);
+                }
+            }
+
+            // Try to program a parameter with a random value [minVal, maxVal]
+            int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+            std::vector<int32_t> values;
+
+            // Rounding down
+            val0 = val0 - (val0 % step);
+            pCam->setIntParameter(cmd, val0,
+                               [&result, &values](auto status, auto effectiveValues) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      for (auto &&v : effectiveValues) {
+                                          values.push_back(v);
+                                      }
+                                   }
+                               });
+
+            ASSERT_EQ(EvsResult::OK, result);
+
+            values.clear();
+            pCam->getIntParameter(cmd,
+                               [&result, &values](auto status, auto readValues) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      for (auto &&v : readValues) {
+                                          values.push_back(v);
+                                      }
+                                   }
+                               });
+            ASSERT_EQ(EvsResult::OK, result);
+            for (auto &&v : values) {
+                ASSERT_EQ(val0, v) << "Values are not matched.";
+            }
+        }
+
+        result = pCam->unsetMaster();
+        ASSERT_EQ(EvsResult::OK, result);
+
+        // Shutdown
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
+    }
+}
+
+
+/*
+ * CameraMasterRelease
+ * Verify that non-master client gets notified when the master client either
+ * terminates or releases a role.
+ */
+TEST_P(EvsHidlTest, CameraMasterRelease) {
+    LOG(INFO) << "Starting CameraMasterRelease test";
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (isLogicalCam) {
+            // TODO(b/145465724): Support camera parameter programming on
+            // logical devices.
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
+            continue;
+        }
+
+        // Create two camera clients.
+        sp<IEvsCamera_1_1> pCamMaster =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCamMaster, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCamMaster);
+
+        sp<IEvsCamera_1_1> pCamNonMaster =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCamNonMaster, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCamNonMaster);
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        sp<FrameHandler> frameHandlerMaster =
+            new FrameHandler(pCamMaster, cam,
+                             nullptr,
+                             FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandlerMaster, nullptr);
+        sp<FrameHandler> frameHandlerNonMaster =
+            new FrameHandler(pCamNonMaster, cam,
+                             nullptr,
+                             FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandlerNonMaster, nullptr);
+
+        // Set one client as the master
+        EvsResult result = pCamMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        // Try to set another client as the master.
+        result = pCamNonMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+
+        // Start the camera's video stream via a master client.
+        bool startResult = frameHandlerMaster->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandlerMaster->waitForFrameCount(1);
+
+        // Start the camera's video stream via another client
+        startResult = frameHandlerNonMaster->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandlerNonMaster->waitForFrameCount(1);
+
+        // Non-master client expects to receive a master role relesed
+        // notification.
+        EvsEventDesc aTargetEvent  = {};
+        EvsEventDesc aNotification = {};
+
+        bool listening = false;
+        std::mutex eventLock;
+        std::condition_variable eventCond;
+        std::thread listener = std::thread(
+            [&aNotification, &frameHandlerNonMaster, &listening, &eventCond]() {
+                // Notify that a listening thread is running.
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+                if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
+                }
+
+            }
+        );
+
+        // Wait until a listening thread starts.
+        std::unique_lock<std::mutex> lock(eventLock);
+        auto timer = std::chrono::system_clock::now();
+        while (!listening) {
+            timer += 1s;
+            eventCond.wait_until(lock, timer);
+        }
+        lock.unlock();
+
+        // Release a master role.
+        pCamMaster->unsetMaster();
+
+        // Join a listening thread.
+        if (listener.joinable()) {
+            listener.join();
+        }
+
+        // Verify change notifications.
+        ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+                  static_cast<EvsEventType>(aNotification.aType));
+
+        // Non-master becomes a master.
+        result = pCamNonMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OK);
+
+        // Previous master client fails to become a master.
+        result = pCamMaster->setMaster();
+        ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+
+        listening = false;
+        listener = std::thread(
+            [&aNotification, &frameHandlerMaster, &listening, &eventCond]() {
+                // Notify that a listening thread is running.
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+                if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
+                }
+
+            }
+        );
+
+        // Wait until a listening thread starts.
+        timer = std::chrono::system_clock::now();
+        lock.lock();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        // Closing current master client.
+        frameHandlerNonMaster->shutdown();
+
+        // Join a listening thread.
+        if (listener.joinable()) {
+            listener.join();
+        }
+
+        // Verify change notifications.
+        ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+                  static_cast<EvsEventType>(aNotification.aType));
+
+        // Closing streams.
+        frameHandlerMaster->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCamMaster);
+        pEnumerator->closeCamera(pCamNonMaster);
+        activeCameras.clear();
+    }
+}
+
+
+/*
+ * MultiCameraParameter:
+ * Verify that master and non-master clients behave as expected when they try to adjust
+ * camera parameters.
+ */
+TEST_P(EvsHidlTest, MultiCameraParameter) {
+    LOG(INFO) << "Starting MultiCameraParameter test";
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (isLogicalCam) {
+            // TODO(b/145465724): Support camera parameter programming on
+            // logical devices.
+            LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
+            continue;
+        }
+
+        // Create two camera clients.
+        sp<IEvsCamera_1_1> pCamMaster =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCamMaster, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCamMaster);
+
+        sp<IEvsCamera_1_1> pCamNonMaster =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCamNonMaster, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCamNonMaster);
+
+        // Get the parameter list
+        std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
+        pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
+                camMasterCmds.reserve(cmdList.size());
+                for (auto &&cmd : cmdList) {
+                    camMasterCmds.push_back(cmd);
+                }
+            }
+        );
+
+        pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec<CameraParam> cmdList) {
+                camNonMasterCmds.reserve(cmdList.size());
+                for (auto &&cmd : cmdList) {
+                    camNonMasterCmds.push_back(cmd);
+                }
+            }
+        );
+
+        if (camMasterCmds.size() < 1 ||
+            camNonMasterCmds.size() < 1) {
+            // Skip a camera device if it does not support any parameter.
+            continue;
+        }
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        sp<FrameHandler> frameHandlerMaster =
+            new FrameHandler(pCamMaster, cam,
+                             nullptr,
+                             FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandlerMaster, nullptr);
+        sp<FrameHandler> frameHandlerNonMaster =
+            new FrameHandler(pCamNonMaster, cam,
+                             nullptr,
+                             FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandlerNonMaster, nullptr);
+
+        // Set one client as the master
+        EvsResult result = pCamMaster->setMaster();
+        ASSERT_EQ(EvsResult::OK, result);
+
+        // Try to set another client as the master.
+        result = pCamNonMaster->setMaster();
+        ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
+
+        // Start the camera's video stream via a master client.
+        bool startResult = frameHandlerMaster->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandlerMaster->waitForFrameCount(1);
+
+        // Start the camera's video stream via another client
+        startResult = frameHandlerNonMaster->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandlerNonMaster->waitForFrameCount(1);
+
+        int32_t val0 = 0;
+        std::vector<int32_t> values;
+        EvsEventDesc aNotification0 = {};
+        EvsEventDesc aNotification1 = {};
+        for (auto &cmd : camMasterCmds) {
+            // Get a valid parameter value range
+            int32_t minVal, maxVal, step;
+            pCamMaster->getIntParameterRange(
+                cmd,
+                [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+                    minVal = val0;
+                    maxVal = val1;
+                    step   = val2;
+                }
+            );
+
+            EvsResult result = EvsResult::OK;
+            if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+                // Try to turn off auto-focus
+                values.clear();
+                pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &values](auto status, auto effectiveValues) {
+                                       result = status;
+                                       if (status == EvsResult::OK) {
+                                          for (auto &&v : effectiveValues) {
+                                              values.push_back(v);
+                                          }
+                                       }
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                for (auto &&v : values) {
+                    ASSERT_EQ(v, 0);
+                }
+            }
+
+            // Calculate a parameter value to program.
+            val0 = minVal + (std::rand() % (maxVal - minVal));
+            val0 = val0 - (val0 % step);
+
+            // Prepare and start event listeners.
+            bool listening0 = false;
+            bool listening1 = false;
+            std::condition_variable eventCond;
+            std::thread listener0 = std::thread(
+                [cmd, val0,
+                 &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+                    listening0 = true;
+                    if (listening1) {
+                        eventCond.notify_all();
+                    }
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                    aTargetEvent.payload[1] = val0;
+                    if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
+                    }
+                }
+            );
+            std::thread listener1 = std::thread(
+                [cmd, val0,
+                 &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+                    listening1 = true;
+                    if (listening0) {
+                        eventCond.notify_all();
+                    }
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                    aTargetEvent.payload[1] = val0;
+                    if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
+                    }
+                }
+            );
+
+            // Wait until a listening thread starts.
+            std::mutex eventLock;
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening0 || !listening1) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to program a parameter
+            values.clear();
+            pCamMaster->setIntParameter(cmd, val0,
+                                     [&result, &values](auto status, auto effectiveValues) {
+                                         result = status;
+                                         if (status == EvsResult::OK) {
+                                            for (auto &&v : effectiveValues) {
+                                                values.push_back(v);
+                                            }
+                                         }
+                                     });
+
+            ASSERT_EQ(EvsResult::OK, result);
+            for (auto &&v : values) {
+                ASSERT_EQ(val0, v) << "Values are not matched.";
+            }
+
+            // Join a listening thread.
+            if (listener0.joinable()) {
+                listener0.join();
+            }
+            if (listener1.joinable()) {
+                listener1.join();
+            }
+
+            // Verify a change notification
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification0.aType));
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification1.aType));
+            ASSERT_EQ(cmd,
+                      static_cast<CameraParam>(aNotification0.payload[0]));
+            ASSERT_EQ(cmd,
+                      static_cast<CameraParam>(aNotification1.payload[0]));
+            for (auto &&v : values) {
+                ASSERT_EQ(v,
+                          static_cast<int32_t>(aNotification0.payload[1]));
+                ASSERT_EQ(v,
+                          static_cast<int32_t>(aNotification1.payload[1]));
+            }
+
+            // Clients expects to receive a parameter change notification
+            // whenever a master client adjusts it.
+            values.clear();
+            pCamMaster->getIntParameter(cmd,
+                                     [&result, &values](auto status, auto readValues) {
+                                         result = status;
+                                         if (status == EvsResult::OK) {
+                                            for (auto &&v : readValues) {
+                                                values.push_back(v);
+                                            }
+                                         }
+                                     });
+            ASSERT_EQ(EvsResult::OK, result);
+            for (auto &&v : values) {
+                ASSERT_EQ(val0, v) << "Values are not matched.";
+            }
+        }
+
+        // Try to adjust a parameter via non-master client
+        values.clear();
+        pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
+                                    [&result, &values](auto status, auto effectiveValues) {
+                                        result = status;
+                                        if (status == EvsResult::OK) {
+                                            for (auto &&v : effectiveValues) {
+                                                values.push_back(v);
+                                            }
+                                        }
+                                    });
+        ASSERT_EQ(EvsResult::INVALID_ARG, result);
+
+        // Non-master client attemps to be a master
+        result = pCamNonMaster->setMaster();
+        ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
+
+        // Master client retires from a master role
+        bool listening = false;
+        std::condition_variable eventCond;
+        std::thread listener = std::thread(
+            [&aNotification0, &frameHandlerNonMaster, &listening, &eventCond]() {
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+                if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) {
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
+                }
+            }
+        );
+
+        std::mutex eventLock;
+        auto timer = std::chrono::system_clock::now();
+        std::unique_lock<std::mutex> lock(eventLock);
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        result = pCamMaster->unsetMaster();
+        ASSERT_EQ(EvsResult::OK, result);
+
+        if (listener.joinable()) {
+            listener.join();
+        }
+        ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+                  static_cast<EvsEventType>(aNotification0.aType));
+
+        // Try to adjust a parameter after being retired
+        values.clear();
+        pCamMaster->setIntParameter(camMasterCmds[0], val0,
+                                 [&result, &values](auto status, auto effectiveValues) {
+                                     result = status;
+                                     if (status == EvsResult::OK) {
+                                        for (auto &&v : effectiveValues) {
+                                            values.push_back(v);
+                                        }
+                                     }
+                                 });
+        ASSERT_EQ(EvsResult::INVALID_ARG, result);
+
+        // Non-master client becomes a master
+        result = pCamNonMaster->setMaster();
+        ASSERT_EQ(EvsResult::OK, result);
+
+        // Try to adjust a parameter via new master client
+        for (auto &cmd : camNonMasterCmds) {
+            // Get a valid parameter value range
+            int32_t minVal, maxVal, step;
+            pCamNonMaster->getIntParameterRange(
+                cmd,
+                [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+                    minVal = val0;
+                    maxVal = val1;
+                    step   = val2;
+                }
+            );
+
+            EvsResult result = EvsResult::OK;
+            values.clear();
+            if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+                // Try to turn off auto-focus
+                values.clear();
+                pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &values](auto status, auto effectiveValues) {
+                                       result = status;
+                                       if (status == EvsResult::OK) {
+                                          for (auto &&v : effectiveValues) {
+                                              values.push_back(v);
+                                          }
+                                       }
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                for (auto &&v : values) {
+                    ASSERT_EQ(v, 0);
+                }
+            }
+
+            // Calculate a parameter value to program.  This is being rounding down.
+            val0 = minVal + (std::rand() % (maxVal - minVal));
+            val0 = val0 - (val0 % step);
+
+            // Prepare and start event listeners.
+            bool listening0 = false;
+            bool listening1 = false;
+            std::condition_variable eventCond;
+            std::thread listener0 = std::thread(
+                [&cmd, &val0, &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+                    listening0 = true;
+                    if (listening1) {
+                        eventCond.notify_all();
+                    }
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                    aTargetEvent.payload[1] = val0;
+                    if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
+                    }
+                }
+            );
+            std::thread listener1 = std::thread(
+                [&cmd, &val0, &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+                    listening1 = true;
+                    if (listening0) {
+                        eventCond.notify_all();
+                    }
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
+                    aTargetEvent.payload[1] = val0;
+                    if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
+                    }
+                }
+            );
+
+            // Wait until a listening thread starts.
+            std::mutex eventLock;
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening0 || !listening1) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to program a parameter
+            values.clear();
+            pCamNonMaster->setIntParameter(cmd, val0,
+                                        [&result, &values](auto status, auto effectiveValues) {
+                                            result = status;
+                                            if (status == EvsResult::OK) {
+                                                for (auto &&v : effectiveValues) {
+                                                    values.push_back(v);
+                                                }
+                                            }
+                                        });
+            ASSERT_EQ(EvsResult::OK, result);
+
+            // Clients expects to receive a parameter change notification
+            // whenever a master client adjusts it.
+            values.clear();
+            pCamNonMaster->getIntParameter(cmd,
+                                        [&result, &values](auto status, auto readValues) {
+                                            result = status;
+                                            if (status == EvsResult::OK) {
+                                                for (auto &&v : readValues) {
+                                                    values.push_back(v);
+                                                }
+                                            }
+                                        });
+            ASSERT_EQ(EvsResult::OK, result);
+            for (auto &&v : values) {
+                ASSERT_EQ(val0, v) << "Values are not matched.";
+            }
+
+            // Join a listening thread.
+            if (listener0.joinable()) {
+                listener0.join();
+            }
+            if (listener1.joinable()) {
+                listener1.join();
+            }
+
+            // Verify a change notification
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification0.aType));
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification1.aType));
+            ASSERT_EQ(cmd,
+                      static_cast<CameraParam>(aNotification0.payload[0]));
+            ASSERT_EQ(cmd,
+                      static_cast<CameraParam>(aNotification1.payload[0]));
+            for (auto &&v : values) {
+                ASSERT_EQ(v,
+                          static_cast<int32_t>(aNotification0.payload[1]));
+                ASSERT_EQ(v,
+                          static_cast<int32_t>(aNotification1.payload[1]));
+            }
+        }
+
+        // New master retires from a master role
+        result = pCamNonMaster->unsetMaster();
+        ASSERT_EQ(EvsResult::OK, result);
+
+        // Shutdown
+        frameHandlerMaster->shutdown();
+        frameHandlerNonMaster->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCamMaster);
+        pEnumerator->closeCamera(pCamNonMaster);
+        activeCameras.clear();
+    }
+}
+
+
+/*
+ * HighPriorityCameraClient:
+ * EVS client, which owns the display, is priortized and therefore can take over
+ * a master role from other EVS clients without the display.
+ */
+TEST_P(EvsHidlTest, HighPriorityCameraClient) {
+    LOG(INFO) << "Starting HighPriorityCameraClient test";
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // Request exclusive access to the EVS display
+    sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
+    ASSERT_NE(pDisplay, nullptr);
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // Create two clients
+        sp<IEvsCamera_1_1> pCam0 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam0, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam0);
+
+        sp<IEvsCamera_1_1> pCam1 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam1, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam1);
+
+        // Get the parameter list; this test will use the first command in both
+        // lists.
+        std::vector<CameraParam> cam0Cmds, cam1Cmds;
+        pCam0->getParameterList([&cam0Cmds](hidl_vec<CameraParam> cmdList) {
+                cam0Cmds.reserve(cmdList.size());
+                for (auto &&cmd : cmdList) {
+                    cam0Cmds.push_back(cmd);
+                }
+            }
+        );
+
+        pCam1->getParameterList([&cam1Cmds](hidl_vec<CameraParam> cmdList) {
+                cam1Cmds.reserve(cmdList.size());
+                for (auto &&cmd : cmdList) {
+                    cam1Cmds.push_back(cmd);
+                }
+            }
+        );
+        if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) {
+            // Cannot execute this test.
+            return;
+        }
+
+        // Set up a frame receiver object which will fire up its own thread.
+        sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+                                                          pDisplay,
+                                                          FrameHandler::eAutoReturn);
+        sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+                                                          nullptr,
+                                                          FrameHandler::eAutoReturn);
+
+        // Activate the display
+        pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+        // Start the camera's video stream
+        ASSERT_TRUE(frameHandler0->startStream());
+        ASSERT_TRUE(frameHandler1->startStream());
+
+        // Ensure the stream starts
+        frameHandler0->waitForFrameCount(1);
+        frameHandler1->waitForFrameCount(1);
+
+        // Client 1 becomes a master and programs a parameter.
+        EvsResult result = EvsResult::OK;
+        // Get a valid parameter value range
+        int32_t minVal, maxVal, step;
+        pCam1->getIntParameterRange(
+            cam1Cmds[0],
+            [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+                minVal = val0;
+                maxVal = val1;
+                step   = val2;
+            }
+        );
+
+        // Client1 becomes a master
+        result = pCam1->setMaster();
+        ASSERT_EQ(EvsResult::OK, result);
+
+        std::vector<int32_t> values;
+        EvsEventDesc aTargetEvent  = {};
+        EvsEventDesc aNotification = {};
+        bool listening = false;
+        std::mutex eventLock;
+        std::condition_variable eventCond;
+        if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+            std::thread listener = std::thread(
+                [&frameHandler0, &aNotification, &listening, &eventCond] {
+                    listening = true;
+                    eventCond.notify_all();
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+                    aTargetEvent.payload[1] = 0;
+                    if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
+                    }
+                }
+            );
+
+            // Wait until a lister starts.
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to turn off auto-focus
+            pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                               [&result, &values](auto status, auto effectiveValues) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      for (auto &&v : effectiveValues) {
+                                          values.push_back(v);
+                                      }
+                                   }
+                               });
+            ASSERT_EQ(EvsResult::OK, result);
+            for (auto &&v : values) {
+                ASSERT_EQ(v, 0);
+            }
+
+            // Join a listener
+            if (listener.joinable()) {
+                listener.join();
+            }
+
+            // Make sure AUTO_FOCUS is off.
+            ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                      EvsEventType::PARAMETER_CHANGED);
+        }
+
+        // Try to program a parameter with a random value [minVal, maxVal] after
+        // rounding it down.
+        int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+        val0 = val0 - (val0 % step);
+
+        std::thread listener = std::thread(
+            [&frameHandler1, &aNotification, &listening, &eventCond, &cam1Cmds, val0] {
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                aTargetEvent.payload[0] = static_cast<uint32_t>(cam1Cmds[0]);
+                aTargetEvent.payload[1] = val0;
+                if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
+                }
+            }
+        );
+
+        // Wait until a lister starts.
+        listening = false;
+        std::unique_lock<std::mutex> lock(eventLock);
+        auto timer = std::chrono::system_clock::now();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        values.clear();
+        pCam1->setIntParameter(cam1Cmds[0], val0,
+                            [&result, &values](auto status, auto effectiveValues) {
+                                result = status;
+                                if (status == EvsResult::OK) {
+                                    for (auto &&v : effectiveValues) {
+                                        values.push_back(v);
+                                    }
+                                }
+                            });
+        ASSERT_EQ(EvsResult::OK, result);
+        for (auto &&v : values) {
+            ASSERT_EQ(val0, v);
+        }
+
+        // Join a listener
+        if (listener.joinable()) {
+            listener.join();
+        }
+
+        // Verify a change notification
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                  EvsEventType::PARAMETER_CHANGED);
+        ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+                  cam1Cmds[0]);
+        for (auto &&v : values) {
+            ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        listener = std::thread(
+            [&frameHandler1, &aNotification, &listening, &eventCond] {
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
+                if (!frameHandler1->waitForEvent(aTargetEvent, aNotification, true)) {
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
+                }
+            }
+        );
+
+        // Wait until a lister starts.
+        listening = false;
+        lock.lock();
+        timer = std::chrono::system_clock::now();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        // Client 0 steals a master role
+        ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
+
+        // Join a listener
+        if (listener.joinable()) {
+            listener.join();
+        }
+
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                  EvsEventType::MASTER_RELEASED);
+
+        // Client 0 programs a parameter
+        val0 = minVal + (std::rand() % (maxVal - minVal));
+
+        // Rounding down
+        val0 = val0 - (val0 % step);
+
+        if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+            std::thread listener = std::thread(
+                [&frameHandler1, &aNotification, &listening, &eventCond] {
+                    listening = true;
+                    eventCond.notify_all();
+
+                    EvsEventDesc aTargetEvent;
+                    aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                    aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
+                    aTargetEvent.payload[1] = 0;
+                    if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
+                        LOG(WARNING) << "A timer is expired before a target event is fired.";
+                    }
+                }
+            );
+
+            // Wait until a lister starts.
+            std::unique_lock<std::mutex> lock(eventLock);
+            auto timer = std::chrono::system_clock::now();
+            while (!listening) {
+                eventCond.wait_until(lock, timer + 1s);
+            }
+            lock.unlock();
+
+            // Try to turn off auto-focus
+            values.clear();
+            pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                               [&result, &values](auto status, auto effectiveValues) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      for (auto &&v : effectiveValues) {
+                                          values.push_back(v);
+                                      }
+                                   }
+                               });
+            ASSERT_EQ(EvsResult::OK, result);
+            for (auto &&v : values) {
+                ASSERT_EQ(v, 0);
+            }
+
+            // Join a listener
+            if (listener.joinable()) {
+                listener.join();
+            }
+
+            // Make sure AUTO_FOCUS is off.
+            ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                      EvsEventType::PARAMETER_CHANGED);
+        }
+
+        listener = std::thread(
+            [&frameHandler0, &aNotification, &listening, &eventCond, &cam0Cmds, val0] {
+                listening = true;
+                eventCond.notify_all();
+
+                EvsEventDesc aTargetEvent;
+                aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
+                aTargetEvent.payload[0] = static_cast<uint32_t>(cam0Cmds[0]);
+                aTargetEvent.payload[1] = val0;
+                if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
+                    LOG(WARNING) << "A timer is expired before a target event is fired.";
+                }
+            }
+        );
+
+        // Wait until a lister starts.
+        listening = false;
+        timer = std::chrono::system_clock::now();
+        lock.lock();
+        while (!listening) {
+            eventCond.wait_until(lock, timer + 1s);
+        }
+        lock.unlock();
+
+        values.clear();
+        pCam0->setIntParameter(cam0Cmds[0], val0,
+                            [&result, &values](auto status, auto effectiveValues) {
+                                result = status;
+                                if (status == EvsResult::OK) {
+                                    for (auto &&v : effectiveValues) {
+                                        values.push_back(v);
+                                    }
+                                }
+                            });
+        ASSERT_EQ(EvsResult::OK, result);
+
+        // Join a listener
+        if (listener.joinable()) {
+            listener.join();
+        }
+        // Verify a change notification
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                  EvsEventType::PARAMETER_CHANGED);
+        ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+                  cam0Cmds[0]);
+        for (auto &&v : values) {
+            ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        // Turn off the display (yes, before the stream stops -- it should be handled)
+        pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+        // Shut down the streamer
+        frameHandler0->shutdown();
+        frameHandler1->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam0);
+        pEnumerator->closeCamera(pCam1);
+        activeCameras.clear();
+
+    }
+
+    // Explicitly release the display
+    pEnumerator->closeDisplay(pDisplay);
+}
+
+
+/*
+ * CameraUseStreamConfigToDisplay:
+ * End to end test of data flowing from the camera to the display.  Similar to
+ * CameraToDisplayRoundTrip test case but this case retrieves available stream
+ * configurations from EVS and uses one of them to start a video stream.
+ */
+TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) {
+    LOG(INFO) << "Starting CameraUseStreamConfigToDisplay test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Request exclusive access to the EVS display
+    sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
+    ASSERT_NE(pDisplay, nullptr);
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // choose a configuration that has a frame rate faster than minReqFps.
+        Stream targetCfg = {};
+        const int32_t minReqFps = 15;
+        int32_t maxArea = 0;
+        camera_metadata_entry_t streamCfgs;
+        bool foundCfg = false;
+        if (!find_camera_metadata_entry(
+                 reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+                 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                 &streamCfgs)) {
+            // Stream configurations are found in metadata
+            RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+            for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+                    if (ptr->width * ptr->height > maxArea &&
+                        ptr->framerate >= minReqFps) {
+                        targetCfg.width = ptr->width;
+                        targetCfg.height = ptr->height;
+
+                        maxArea = ptr->width * ptr->height;
+                        foundCfg = true;
+                    }
+                }
+                ++ptr;
+            }
+        }
+        targetCfg.format =
+            static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+        if (!foundCfg) {
+            // Current EVS camera does not provide stream configurations in the
+            // metadata.
+            continue;
+        }
+
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
+        // Set up a frame receiver object which will fire up its own thread.
+        sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+                                                         pDisplay,
+                                                         FrameHandler::eAutoReturn);
+
+
+        // Activate the display
+        pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+        // Start the camera's video stream
+        bool startResult = frameHandler->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Wait a while to let the data flow
+        static const int kSecondsToWait = 5;
+        const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds -
+                                 kMaxStreamStartMilliseconds;
+        const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond /
+                                               kSecondsToMilliseconds;
+        sleep(kSecondsToWait);
+        unsigned framesReceived = 0;
+        unsigned framesDisplayed = 0;
+        frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+        EXPECT_EQ(framesReceived, framesDisplayed);
+        EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+        // Turn off the display (yes, before the stream stops -- it should be handled)
+        pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+        // Shut down the streamer
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
+    }
+
+    // Explicitly release the display
+    pEnumerator->closeDisplay(pDisplay);
+}
+
+
+/*
+ * MultiCameraStreamUseConfig:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera with same configuration.
+ */
+TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) {
+    LOG(INFO) << "Starting MultiCameraStream test";
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // choose a configuration that has a frame rate faster than minReqFps.
+        Stream targetCfg = {};
+        const int32_t minReqFps = 15;
+        int32_t maxArea = 0;
+        camera_metadata_entry_t streamCfgs;
+        bool foundCfg = false;
+        if (!find_camera_metadata_entry(
+                 reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+                 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                 &streamCfgs)) {
+            // Stream configurations are found in metadata
+            RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+            for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+                    if (ptr->width * ptr->height > maxArea &&
+                        ptr->framerate >= minReqFps) {
+                        targetCfg.width = ptr->width;
+                        targetCfg.height = ptr->height;
+
+                        maxArea = ptr->width * ptr->height;
+                        foundCfg = true;
+                    }
+                }
+                ++ptr;
+            }
+        }
+        targetCfg.format =
+            static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+        if (!foundCfg) {
+            LOG(INFO) << "Device " << cam.v1.cameraId
+                      << " does not provide a list of supported stream configurations, skipped";
+            continue;
+        }
+
+        // Create the first camera client with a selected stream configuration.
+        sp<IEvsCamera_1_1> pCam0 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam0, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam0);
+
+        // Try to create the second camera client with different stream
+        // configuration.
+        int32_t id = targetCfg.id;
+        targetCfg.id += 1;  // EVS manager sees only the stream id.
+        sp<IEvsCamera_1_1> pCam1 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+            .withDefault(nullptr);
+        ASSERT_EQ(pCam1, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam0);
+
+        // Try again with same stream configuration.
+        targetCfg.id = id;
+        pCam1 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam1, nullptr);
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+                                                          nullptr,
+                                                          FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandler0, nullptr);
+
+        sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+                                                          nullptr,
+                                                          FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandler1, nullptr);
+
+        // Start the camera's video stream via client 0
+        bool startResult = false;
+        startResult = frameHandler0->startStream() &&
+                      frameHandler1->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandler0->waitForFrameCount(1);
+        frameHandler1->waitForFrameCount(1);
+
+        nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        // Wait a bit, then ensure both clients get at least the required minimum number of frames
+        sleep(5);
+        nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+        unsigned framesReceived0 = 0, framesReceived1 = 0;
+        frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+        framesReceived0 = framesReceived0 - 1;    // Back out the first frame we already waited for
+        framesReceived1 = framesReceived1 - 1;    // Back out the first frame we already waited for
+        nsecs_t runTime = end - firstFrame;
+        float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+        float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+        LOG(INFO) << "Measured camera rate "
+                  << std::scientific << framesPerSecond0 << " fps and "
+                  << framesPerSecond1 << " fps";
+        EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+        EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+        // Shutdown one client
+        frameHandler0->shutdown();
+
+        // Read frame counters again
+        frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+        // Wait a bit again
+        sleep(5);
+        unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+        frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+        EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+        EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+        // Shutdown another
+        frameHandler1->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam0);
+        pEnumerator->closeCamera(pCam1);
+        activeCameras.clear();
+    }
+}
+
+
+/*
+ * LogicalCameraMetadata:
+ * Opens logical camera reported by the enumerator and validate its metadata by
+ * checking its capability and locating supporting physical camera device
+ * identifiers.
+ */
+TEST_P(EvsHidlTest, LogicalCameraMetadata) {
+    LOG(INFO) << "Starting LogicalCameraMetadata test";
+
+    // Get the camera list
+    loadCameraList();
+
+    // Open and close each camera twice
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (isLogicalCam) {
+            ASSERT_GE(devices.size(), 1) <<
+                "Logical camera device must have at least one physical camera device ID in its metadata.";
+        }
+    }
+}
+
+
+/*
+ * CameraStreamExternalBuffering:
+ * This is same with CameraStreamBuffering except frame buffers are allocated by
+ * the test client and then imported by EVS framework.
+ */
+TEST_P(EvsHidlTest, CameraStreamExternalBuffering) {
+    LOG(INFO) << "Starting CameraStreamExternalBuffering test";
+
+    // Arbitrary constant (should be > 1 and less than crazy)
+    static const unsigned int kBuffersToHold = 6;
+
+    // Get the camera list
+    loadCameraList();
+
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
+    // Acquire the graphics buffer allocator
+    android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
+    const auto usage = GRALLOC_USAGE_HW_TEXTURE |
+                       GRALLOC_USAGE_SW_READ_RARELY |
+                       GRALLOC_USAGE_SW_WRITE_OFTEN;
+    const auto format = HAL_PIXEL_FORMAT_RGBA_8888;
+    const auto width = 640;
+    const auto height = 360;
+
+    // Allocate buffers to use
+    hidl_vec<BufferDesc> buffers;
+    buffers.resize(kBuffersToHold);
+    for (auto i = 0; i < kBuffersToHold; ++i) {
+        unsigned pixelsPerLine;
+        buffer_handle_t memHandle = nullptr;
+        android::status_t result = alloc.allocate(width,
+                                                  height,
+                                                  format,
+                                                  1,
+                                                  usage,
+                                                  &memHandle,
+                                                  &pixelsPerLine,
+                                                  0,
+                                                  "EvsApp");
+        if (result != android::NO_ERROR) {
+            LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
+        } else {
+            BufferDesc buf;
+            AHardwareBuffer_Desc* pDesc =
+                reinterpret_cast<AHardwareBuffer_Desc *>(&buf.buffer.description);
+            pDesc->width = width;
+            pDesc->height = height;
+            pDesc->layers = 1;
+            pDesc->format = format;
+            pDesc->usage = usage;
+            pDesc->stride = pixelsPerLine;
+            buf.buffer.nativeHandle = memHandle;
+            buf.bufferId = i;   // Unique number to identify this buffer
+            buffers[i] = buf;
+        }
+    }
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // Store a camera handle for a clean-up
+        activeCameras.push_back(pCam);
+
+        // Request to import buffers
+        EvsResult result = EvsResult::OK;
+        int delta = 0;
+        pCam->importExternalBuffers(buffers,
+                                    [&] (auto _result, auto _delta) {
+                                        result = _result;
+                                        delta = _delta;
+                                    });
+        if (isLogicalCam) {
+            EXPECT_EQ(result, EvsResult::UNDERLYING_SERVICE_ERROR);
+            continue;
+        }
+
+        EXPECT_EQ(result, EvsResult::OK);
+        EXPECT_GE(delta, 0);
+
+        // Set up a frame receiver object which will fire up its own thread.
+        sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+                                                         nullptr,
+                                                         FrameHandler::eNoAutoReturn);
+
+        // Start the camera's video stream
+        bool startResult = frameHandler->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Check that the video stream stalls once we've gotten exactly the number of buffers
+        // we requested since we told the frameHandler not to return them.
+        sleep(1);   // 1 second should be enough for at least 5 frames to be delivered worst case
+        unsigned framesReceived = 0;
+        frameHandler->getFramesCounters(&framesReceived, nullptr);
+        ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
+
+
+        // Give back one buffer
+        bool didReturnBuffer = frameHandler->returnHeldBuffer();
+        EXPECT_TRUE(didReturnBuffer);
+
+        // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one
+        // filled since we require 10fps minimum -- but give a 10% allowance just in case.
+        usleep(110 * kMillisecondsToMicroseconds);
+        frameHandler->getFramesCounters(&framesReceived, nullptr);
+        EXPECT_EQ(kBuffersToHold+1, framesReceived) << "Stream should've resumed";
+
+        // Even when the camera pointer goes out of scope, the FrameHandler object will
+        // keep the stream alive unless we tell it to shutdown.
+        // Also note that the FrameHandle and the Camera have a mutual circular reference, so
+        // we have to break that cycle in order for either of them to get cleaned up.
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam);
+        activeCameras.clear();
+    }
+
+    // Release buffers
+    for (auto& b : buffers) {
+        alloc.free(b.buffer.nativeHandle);
+    }
+    buffers.resize(0);
+}
+
+
+/*
+ * 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) {
+    LOG(INFO) << "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) {
+                LOG(DEBUG) << "Found ultrasonics array " << ultraInfo.ultrasonicsArrayId;
+                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) {
+    LOG(INFO) << "Starting UltrasonicsVerifyStreamData";
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // For each ultrasonics array.
+    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
+        LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId;
+
+        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) {
+    LOG(INFO) << "Starting UltrasonicsSetFramesInFlight";
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // For each ultrasonics array.
+    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
+        LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId;
+
+        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/evs/1.1/vts/fuzzing/Android.bp b/automotive/evs/1.1/vts/fuzzing/Android.bp
new file mode 100644
index 0000000..48427ee
--- /dev/null
+++ b/automotive/evs/1.1/vts/fuzzing/Android.bp
@@ -0,0 +1,50 @@
+//
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+    name: "android.hardware.automotive.evs@fuzz-defaults",
+    defaults: ["VtsHalTargetTestDefaults"],
+    shared_libs: [
+        "libui",
+        "libcamera_metadata",
+    ],
+    static_libs: [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@1.1",
+        "android.hardware.automotive.evs@common-default-lib",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.camera.device@3.2",
+    ],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
+
+cc_fuzz {
+    name: "VtsHalEvsV1_1CameraOpenFuzz",
+    defaults: ["android.hardware.automotive.evs@fuzz-defaults"],
+    srcs: [
+        "VtsHalEvsV1_1CameraOpenFuzz.cpp",
+    ],
+    fuzz_config: {
+        // wait for Haiku device ready
+        fuzz_on_haiku_device: false,
+        fuzz_on_haiku_host: false,
+    },
+}
diff --git a/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp b/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp
new file mode 100644
index 0000000..4f05d21
--- /dev/null
+++ b/automotive/evs/1.1/vts/fuzzing/VtsHalEvsV1_1CameraOpenFuzz.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
+using ::android::hardware::camera::device::V3_2::Stream;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
+    UNUSED(argc);
+    UNUSED(argv);
+    pEnumerator = IEvsEnumerator::getService(kEnumeratorName);
+    sp<EvsDeathRecipient> dr = new EvsDeathRecipient();
+
+    pEnumerator->linkToDeath(dr, 0);
+
+    loadCameraList();
+    return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+
+    std::vector<sp<IEvsCamera_1_1>> camList;
+    Stream nullCfg = {};
+
+    while (fdp.remaining_bytes() > 4) {
+        switch (fdp.ConsumeIntegralInRange<uint32_t>(0, 3)) {
+            case 0:  // open camera
+            {
+                uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, cameraInfo.size() - 1);
+                sp<IEvsCamera_1_1> pCam =
+                        IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(
+                                                         cameraInfo[whichCam].v1.cameraId, nullCfg))
+                                .withDefault(nullptr);
+                camList.emplace_back(pCam);
+                break;
+            }
+            case 1:  // close camera
+            {
+                if (!camList.empty()) {
+                    uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, camList.size() - 1);
+                    pEnumerator->closeCamera(camList[whichCam]);
+                }
+                break;
+            }
+            case 2:  // get camera info
+            {
+                if (!camList.empty()) {
+                    uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, camList.size() - 1);
+                    camList[whichCam]->getCameraInfo_1_1([](CameraDesc desc) { UNUSED(desc); });
+                }
+                break;
+            }
+            case 3:  // setMaxFramesInFlight
+            {
+                if (!camList.empty()) {
+                    uint32_t whichCam = fdp.ConsumeIntegralInRange<uint32_t>(0, camList.size() - 1);
+                    int32_t numFrames = fdp.ConsumeIntegral<int32_t>();
+                    camList[whichCam]->setMaxFramesInFlight(numFrames);
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    return 0;
+}
diff --git a/automotive/evs/1.1/vts/fuzzing/common.h b/automotive/evs/1.1/vts/fuzzing/common.h
new file mode 100644
index 0000000..af6fd54
--- /dev/null
+++ b/automotive/evs/1.1/vts/fuzzing/common.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalEvsTest"
+#define UNUSED(x) (void)(x)
+
+const static char kEnumeratorName[] = "EvsEnumeratorHw";
+
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/StrongPointer.h>
+
+using namespace ::android::hardware::automotive::evs::V1_1;
+
+using ::android::sp;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_vec;
+
+static sp<IEvsEnumerator> pEnumerator;
+static std::vector<CameraDesc> cameraInfo;
+
+class EvsDeathRecipient : public hidl_death_recipient {
+  public:
+    void serviceDied(uint64_t /*cookie*/,
+                     const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
+        abort();
+    }
+};
+
+void loadCameraList() {
+    // SetUp() must run first!
+    assert(pEnumerator != nullptr);
+
+    // Get the camera list
+    pEnumerator->getCameraList_1_1([](hidl_vec<CameraDesc> cameraList) {
+        ALOGI("Camera list callback received %zu cameras", cameraList.size());
+        cameraInfo.reserve(cameraList.size());
+        for (auto&& cam : cameraList) {
+            ALOGI("Found camera %s", cam.v1.cameraId.c_str());
+            cameraInfo.push_back(cam);
+        }
+    });
+}
diff --git a/automotive/evs/common/utils/default/Android.bp b/automotive/evs/common/utils/default/Android.bp
new file mode 100644
index 0000000..776ef81
--- /dev/null
+++ b/automotive/evs/common/utils/default/Android.bp
@@ -0,0 +1,32 @@
+//
+// 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_library_static {
+    host_supported: true,
+    name: "android.hardware.automotive.evs@common-default-lib",
+    vendor_available: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+    srcs: [
+        "FormatConvert.cpp"
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+    ],
+}
diff --git a/automotive/evs/common/utils/default/FormatConvert.cpp b/automotive/evs/common/utils/default/FormatConvert.cpp
new file mode 100644
index 0000000..d4c7da0
--- /dev/null
+++ b/automotive/evs/common/utils/default/FormatConvert.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalEvsTest"
+
+#include "FormatConvert.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace common {
+
+// Round up to the nearest multiple of the given alignment value
+template<unsigned alignment>
+int Utils::align(int value) {
+    static_assert((alignment && !(alignment & (alignment - 1))),
+                  "alignment must be a power of 2");
+
+    unsigned mask = alignment - 1;
+    return (value + mask) & ~mask;
+}
+
+
+// Limit the given value to the provided range.  :)
+inline float Utils::clamp(float v, float min, float max) {
+    if (v < min) return min;
+    if (v > max) return max;
+    return v;
+}
+
+
+uint32_t Utils::yuvToRgbx(const unsigned char Y,
+                          const unsigned char Uin,
+                          const unsigned char Vin,
+                          bool bgrxFormat) {
+    // Don't use this if you want to see the best performance.  :)
+    // Better to do this in a pixel shader if we really have to, but on actual
+    // embedded hardware we expect to be able to texture directly from the YUV data
+    float U = Uin - 128.0f;
+    float V = Vin - 128.0f;
+
+    float Rf = Y + 1.140f*V;
+    float Gf = Y - 0.395f*U - 0.581f*V;
+    float Bf = Y + 2.032f*U;
+    unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
+    unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
+    unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
+
+    if (!bgrxFormat) {
+        return (R      ) |
+               (G <<  8) |
+               (B << 16) |
+               0xFF000000;  // Fill the alpha channel with ones
+    } else {
+        return (R << 16) |
+               (G <<  8) |
+               (B      ) |
+               0xFF000000;  // Fill the alpha channel with ones
+    }
+}
+
+
+void Utils::copyNV21toRGB32(unsigned width, unsigned height,
+                            uint8_t* src,
+                            uint32_t* dst, unsigned dstStridePixels,
+                            bool bgrxFormat)
+{
+    // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+    // U/V array.  It assumes an even width and height for the overall image, and a horizontal
+    // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+    unsigned strideLum = align<16>(width);
+    unsigned sizeY = strideLum * height;
+    unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
+    unsigned offsetUV = sizeY;
+
+    uint8_t* srcY = src;
+    uint8_t* srcUV = src+offsetUV;
+
+    for (unsigned r = 0; r < height; r++) {
+        // Note that we're walking the same UV row twice for even/odd luminance rows
+        uint8_t* rowY  = srcY  + r*strideLum;
+        uint8_t* rowUV = srcUV + (r/2 * strideColor);
+
+        uint32_t* rowDest = dst + r*dstStridePixels;
+
+        for (unsigned c = 0; c < width; c++) {
+            unsigned uCol = (c & ~1);   // uCol is always even and repeats 1:2 with Y values
+            unsigned vCol = uCol | 1;   // vCol is always odd
+            rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol], bgrxFormat);
+        }
+    }
+}
+
+
+void Utils::copyYV12toRGB32(unsigned width, unsigned height,
+                            uint8_t* src,
+                            uint32_t* dst, unsigned dstStridePixels,
+                            bool bgrxFormat)
+{
+    // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
+    // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
+    // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
+    // and V arrays.
+    unsigned strideLum = align<16>(width);
+    unsigned sizeY = strideLum * height;
+    unsigned strideColor = align<16>(strideLum/2);
+    unsigned sizeColor = strideColor * height/2;
+    unsigned offsetU = sizeY;
+    unsigned offsetV = sizeY + sizeColor;
+
+    uint8_t* srcY = src;
+    uint8_t* srcU = src+offsetU;
+    uint8_t* srcV = src+offsetV;
+
+    for (unsigned r = 0; r < height; r++) {
+        // Note that we're walking the same U and V rows twice for even/odd luminance rows
+        uint8_t* rowY = srcY + r*strideLum;
+        uint8_t* rowU = srcU + (r/2 * strideColor);
+        uint8_t* rowV = srcV + (r/2 * strideColor);
+
+        uint32_t* rowDest = dst + r*dstStridePixels;
+
+        for (unsigned c = 0; c < width; c++) {
+            rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c], bgrxFormat);
+        }
+    }
+}
+
+
+void Utils::copyYUYVtoRGB32(unsigned width, unsigned height,
+                            uint8_t* src, unsigned srcStridePixels,
+                            uint32_t* dst, unsigned dstStridePixels,
+                            bool bgrxFormat)
+{
+    uint32_t* srcWords = (uint32_t*)src;
+
+    const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
+    const int dstRowPadding32 = dstStridePixels   - width;    // 4 bytes per pixel, 4 bytes per word
+
+    for (unsigned r = 0; r < height; r++) {
+        for (unsigned c = 0; c < width/2; c++) {
+            // Note:  we're walking two pixels at a time here (even/odd)
+            uint32_t srcPixel = *srcWords++;
+
+            uint8_t Y1 = (srcPixel)       & 0xFF;
+            uint8_t U  = (srcPixel >> 8)  & 0xFF;
+            uint8_t Y2 = (srcPixel >> 16) & 0xFF;
+            uint8_t V  = (srcPixel >> 24) & 0xFF;
+
+            // On the RGB output, we're writing one pixel at a time
+            *(dst+0) = yuvToRgbx(Y1, U, V, bgrxFormat);
+            *(dst+1) = yuvToRgbx(Y2, U, V, bgrxFormat);
+            dst += 2;
+        }
+
+        // Skip over any extra data or end of row alignment padding
+        srcWords += srcRowPadding32;
+        dst += dstRowPadding32;
+    }
+}
+
+
+void Utils::copyNV21toBGR32(unsigned width, unsigned height,
+                            uint8_t* src,
+                            uint32_t* dst, unsigned dstStridePixels)
+{
+    return copyNV21toRGB32(width, height, src, dst, dstStridePixels, true);
+}
+
+
+void Utils::copyYV12toBGR32(unsigned width, unsigned height,
+                            uint8_t* src,
+                            uint32_t* dst, unsigned dstStridePixels)
+{
+    return copyYV12toRGB32(width, height, src, dst, dstStridePixels, true);
+}
+
+
+void Utils::copyYUYVtoBGR32(unsigned width, unsigned height,
+                            uint8_t* src, unsigned srcStridePixels,
+                            uint32_t* dst, unsigned dstStridePixels)
+{
+    return copyYUYVtoRGB32(width, height, src, srcStridePixels, dst, dstStridePixels, true);
+}
+
+
+void Utils::copyMatchedInterleavedFormats(unsigned width, unsigned height,
+                                          void* src, unsigned srcStridePixels,
+                                          void* dst, unsigned dstStridePixels,
+                                          unsigned pixelSize) {
+    for (unsigned row = 0; row < height; row++) {
+        // Copy the entire row of pixel data
+        memcpy(dst, src, width * pixelSize);
+
+        // Advance to the next row (keeping in mind that stride here is in units of pixels)
+        src = (uint8_t*)src + srcStridePixels * pixelSize;
+        dst = (uint8_t*)dst + dstStridePixels * pixelSize;
+    }
+}
+
+} // namespace common
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
diff --git a/automotive/evs/common/utils/default/include/FormatConvert.h b/automotive/evs/common/utils/default/include/FormatConvert.h
new file mode 100644
index 0000000..2bb8955
--- /dev/null
+++ b/automotive/evs/common/utils/default/include/FormatConvert.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EVS_VTS_FORMATCONVERT_H
+#define EVS_VTS_FORMATCONVERT_H
+
+#include <queue>
+#include <stdint.h>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace common {
+
+class Utils {
+public:
+    // Given an image buffer in NV21 format (HAL_PIXEL_FORMAT_YCRCB_420_SP), output 32bit RGBx/BGRx
+    // values.  The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+    // U/V array.  It assumes an even width and height for the overall image, and a horizontal
+    // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+    static void copyNV21toRGB32(unsigned width, unsigned height,
+                                uint8_t* src,
+                                uint32_t* dst, unsigned dstStridePixels,
+                                bool bgrxFormat = false);
+
+    static void copyNV21toBGR32(unsigned width, unsigned height,
+                                uint8_t* src,
+                                uint32_t* dst, unsigned dstStridePixels);
+
+
+    // Given an image buffer in YV12 format (HAL_PIXEL_FORMAT_YV12), output 32bit RGBx/BGRx values.
+    // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed
+    // by another 1/2 x 1/2 V array.  It assumes an even width and height for the overall image,
+    // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U,
+    // and V arrays.
+    static void copyYV12toRGB32(unsigned width, unsigned height,
+                                uint8_t* src,
+                                uint32_t* dst, unsigned dstStridePixels,
+                                bool bgrxFormat = false);
+
+    static void copyYV12toBGR32(unsigned width, unsigned height,
+                                uint8_t* src,
+                                uint32_t* dst, unsigned dstStridePixels);
+
+    // Given an image buffer in YUYV format (HAL_PIXEL_FORMAT_YCBCR_422_I), output 32bit RGBx/BGRx
+    // values.  The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved
+    // U/V array.  It assumes an even width and height for the overall image, and a horizontal
+    // stride that is an even multiple of 16 bytes for both the Y and UV arrays.
+    static void copyYUYVtoRGB32(unsigned width, unsigned height,
+                                uint8_t* src, unsigned srcStrideBytes,
+                                uint32_t* dst, unsigned dstStrideBytes,
+                                bool bgrxFormat = false);
+
+    static void copyYUYVtoBGR32(unsigned width, unsigned height,
+                                uint8_t* src, unsigned srcStrideBytes,
+                                uint32_t* dst, unsigned dstStrideBytes);
+
+
+    // Given an simple rectangular image buffer with an integer number of bytes per pixel,
+    // copy the pixel values into a new rectangular buffer (potentially with a different stride).
+    // This is typically used to copy RGBx data into an RGBx output buffer.
+    static void copyMatchedInterleavedFormats(unsigned width, unsigned height,
+                                              void* src, unsigned srcStridePixels,
+                                              void* dst, unsigned dstStridePixels,
+                                              unsigned pixelSize);
+
+private:
+    template<unsigned alignment>
+    static int align(int value);
+
+    static inline float clamp(float v, float min, float max);
+    static uint32_t yuvToRgbx(const unsigned char Y,
+                              const unsigned char Uin,
+                              const unsigned char Vin,
+                              bool bgrxFormat = false);
+};
+
+} // namespace common
+} // namespace evs
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // EVS_VTS_FORMATCONVERT_H
diff --git a/automotive/evs/common/utils/default/test/fuzz/Android.bp b/automotive/evs/common/utils/default/test/fuzz/Android.bp
new file mode 100644
index 0000000..105ec68
--- /dev/null
+++ b/automotive/evs/common/utils/default/test/fuzz/Android.bp
@@ -0,0 +1,99 @@
+//
+// 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_fuzz {
+    host_supported: true,
+    name : "FormatConvertFuzzer_copyNV21toRGB32",
+    srcs: [
+        "FormatConvertFuzzer.cpp",
+    ],
+    static_libs: [
+        "android.hardware.automotive.evs@common-default-lib"
+    ],
+    cflags: [
+        "-DCOPY_NV21_TO_RGB32",
+    ],
+}
+
+cc_fuzz {
+    host_supported: true,
+    name : "FormatConvertFuzzer_copyNV21toBGR32",
+    srcs: [
+        "FormatConvertFuzzer.cpp",
+    ],
+    static_libs: [
+        "android.hardware.automotive.evs@common-default-lib"
+    ],
+    cflags: [
+        "-DCOPY_NV21_TO_BGR32",
+    ],
+}
+
+cc_fuzz {
+    host_supported: true,
+    name : "FormatConvertFuzzer_copyYV12toRGB32",
+    srcs: [
+        "FormatConvertFuzzer.cpp",
+    ],
+    static_libs: [
+        "android.hardware.automotive.evs@common-default-lib"
+    ],
+    cflags: [
+        "-DCOPY_YV12_TO_RGB32",
+    ],
+}
+
+cc_fuzz {
+    host_supported: true,
+    name : "FormatConvertFuzzer_copyYV12toBGR32",
+    srcs: [
+        "FormatConvertFuzzer.cpp",
+    ],
+    static_libs: [
+        "android.hardware.automotive.evs@common-default-lib"
+    ],
+    cflags: [
+        "-DCOPY_YV12_TO_BGR32",
+    ],
+}
+
+cc_fuzz {
+    host_supported: true,
+    name : "FormatConvertFuzzer_copyYUYVtoRGB32",
+    srcs: [
+        "FormatConvertFuzzer.cpp",
+    ],
+    static_libs: [
+        "android.hardware.automotive.evs@common-default-lib"
+    ],
+    cflags: [
+        "-DCOPY_YUYV_TO_RGB32",
+    ],
+}
+
+cc_fuzz {
+    host_supported: true,
+    name : "FormatConvertFuzzer_copyYUYVtoBGR32",
+    srcs: [
+        "FormatConvertFuzzer.cpp",
+    ],
+    static_libs: [
+        "android.hardware.automotive.evs@common-default-lib"
+    ],
+    cflags: [
+        "-DCOPY_YUYV_TO_BGR32",
+    ],
+}
diff --git a/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp
new file mode 100644
index 0000000..583a455
--- /dev/null
+++ b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include "FormatConvert.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, std::size_t size) {
+    if (size < 256) {
+        return 0;
+    }
+
+    std::srand(std::time(nullptr));  // use current time as seed for random generator
+    int random_variable = std::rand() % 10;
+    int width = (int)sqrt(size);
+    int height = width * ((float)random_variable / 10.0);
+
+    uint8_t* src = (uint8_t*)malloc(sizeof(uint8_t) * size);
+    memcpy(src, data, sizeof(uint8_t) * (size));
+    uint32_t* tgt = (uint32_t*)malloc(sizeof(uint32_t) * size);
+
+#ifdef COPY_NV21_TO_RGB32
+    android::hardware::automotive::evs::common::Utils::copyNV21toRGB32(width, height, src, tgt, 0);
+#elif COPY_NV21_TO_BGR32
+    android::hardware::automotive::evs::common::Utils::copyNV21toBGR32(width, height, src, tgt, 0);
+#elif COPY_YV12_TO_RGB32
+    android::hardware::automotive::evs::common::Utils::copyYV12toRGB32(width, height, src, tgt, 0);
+#elif COPY_YV12_TO_BGR32
+    android::hardware::automotive::evs::common::Utils::copyYV12toBGR32(width, height, src, tgt, 0);
+#elif COPY_YUYV_TO_RGB32
+    android::hardware::automotive::evs::common::Utils::copyYUYVtoRGB32(width, height, src, 0, tgt,
+                                                                       0);
+#elif COPY_YUYV_TO_BGR32
+    android::hardware::automotive::evs::common::Utils::copyYUYVtoBGR32(width, height, src, 0, tgt,
+                                                                       0);
+#endif
+
+    free(src);
+    free(tgt);
+
+    return 0;
+}
diff --git a/automotive/occupant_awareness/aidl/Android.bp b/automotive/occupant_awareness/aidl/Android.bp
new file mode 100644
index 0000000..4127f33
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/Android.bp
@@ -0,0 +1,19 @@
+aidl_interface {
+    name: "android.hardware.automotive.occupant_awareness",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/automotive/occupant_awareness/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+    versions: ["1"],
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/.hash b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/.hash
new file mode 100644
index 0000000..6786231
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/.hash
@@ -0,0 +1 @@
+3614b1c47ed7be85c1e77554e7f04966cf35b465
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl
new file mode 100644
index 0000000..6e40d79
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@Backing(type="byte") @VintfStability
+enum ConfidenceLevel {
+  NONE = 0,
+  LOW = 1,
+  HIGH = 2,
+  MAX = 3,
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl
new file mode 100644
index 0000000..51d2149
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+parcelable DriverMonitoringDetection {
+  android.hardware.automotive.occupant_awareness.ConfidenceLevel confidenceScore;
+  boolean isLookingOnRoad;
+  long gazeDurationMillis;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/GazeDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/GazeDetection.aidl
new file mode 100644
index 0000000..5ce14df
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/GazeDetection.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+parcelable GazeDetection {
+  android.hardware.automotive.occupant_awareness.ConfidenceLevel gazeConfidence;
+  double[] headPosition;
+  double[] headAngleUnitVector;
+  double[] gazeAngleUnitVector;
+  android.hardware.automotive.occupant_awareness.VehicleRegion gazeTarget;
+  String customGazeTarget;
+  long timeOnTargetMillis;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl
new file mode 100644
index 0000000..7faff00
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+interface IOccupantAwareness {
+  android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus startDetection();
+  android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus stopDetection();
+  int getCapabilityForRole(in android.hardware.automotive.occupant_awareness.Role occupantRole);
+  android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus getState(in android.hardware.automotive.occupant_awareness.Role occupantRole, in int detectionCapability);
+  void setCallback(in android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback callback);
+  void getLatestDetection(out android.hardware.automotive.occupant_awareness.OccupantDetections detections);
+  const int CAP_NONE = 0;
+  const int CAP_PRESENCE_DETECTION = 1;
+  const int CAP_GAZE_DETECTION = 2;
+  const int CAP_DRIVER_MONITORING_DETECTION = 4;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl
new file mode 100644
index 0000000..31b8220
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+interface IOccupantAwarenessClientCallback {
+  oneway void onSystemStatusChanged(in int detectionFlags, in android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus status);
+  oneway void onDetectionEvent(in android.hardware.automotive.occupant_awareness.OccupantDetections detections);
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl
new file mode 100644
index 0000000..26371c9
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@Backing(type="byte") @VintfStability
+enum OccupantAwarenessStatus {
+  READY = 0,
+  NOT_SUPPORTED = 1,
+  NOT_INITIALIZED = 2,
+  FAILURE = 3,
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl
new file mode 100644
index 0000000..42b1095
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+parcelable OccupantDetection {
+  android.hardware.automotive.occupant_awareness.Role role;
+  android.hardware.automotive.occupant_awareness.PresenceDetection[] presenceData;
+  android.hardware.automotive.occupant_awareness.GazeDetection[] gazeData;
+  android.hardware.automotive.occupant_awareness.DriverMonitoringDetection[] attentionData;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl
new file mode 100644
index 0000000..9bcad6b
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+parcelable OccupantDetections {
+  long timeStampMillis;
+  android.hardware.automotive.occupant_awareness.OccupantDetection[] detections;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl
new file mode 100644
index 0000000..dd6c5c8
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+parcelable PresenceDetection {
+  boolean isOccupantDetected;
+  long detectionDurationMillis;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/Role.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/Role.aidl
new file mode 100644
index 0000000..7b2b907
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/Role.aidl
@@ -0,0 +1,35 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@Backing(type="int") @VintfStability
+enum Role {
+  INVALID = 0,
+  UNKNOWN = 1,
+  FRONT_PASSENGER = 2,
+  DRIVER = 4,
+  ROW_2_PASSENGER_LEFT = 8,
+  ROW_2_PASSENGER_CENTER = 16,
+  ROW_2_PASSENGER_RIGHT = 32,
+  ROW_3_PASSENGER_LEFT = 64,
+  ROW_3_PASSENGER_CENTER = 128,
+  ROW_3_PASSENGER_RIGHT = 256,
+  FRONT_OCCUPANTS = 6,
+  ROW_2_OCCUPANTS = 56,
+  ROW_3_OCCUPANTS = 448,
+  ALL_OCCUPANTS = 511,
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl
new file mode 100644
index 0000000..f96d950
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/1/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@Backing(type="int") @VintfStability
+enum VehicleRegion {
+  UNKNOWN = 0,
+  INSTRUMENT_CLUSTER = 1,
+  REAR_VIEW_MIRROR = 2,
+  LEFT_SIDE_MIRROR = 3,
+  RIGHT_SIDE_MIRROR = 4,
+  FORWARD_ROADWAY = 5,
+  LEFT_ROADWAY = 6,
+  RIGHT_ROADWAY = 7,
+  HEAD_UNIT_DISPLAY = 8,
+  CUSTOM_TARGET = 200,
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl
new file mode 100644
index 0000000..6e40d79
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@Backing(type="byte") @VintfStability
+enum ConfidenceLevel {
+  NONE = 0,
+  LOW = 1,
+  HIGH = 2,
+  MAX = 3,
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl
new file mode 100644
index 0000000..51d2149
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+parcelable DriverMonitoringDetection {
+  android.hardware.automotive.occupant_awareness.ConfidenceLevel confidenceScore;
+  boolean isLookingOnRoad;
+  long gazeDurationMillis;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/GazeDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/GazeDetection.aidl
new file mode 100644
index 0000000..5ce14df
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/GazeDetection.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+parcelable GazeDetection {
+  android.hardware.automotive.occupant_awareness.ConfidenceLevel gazeConfidence;
+  double[] headPosition;
+  double[] headAngleUnitVector;
+  double[] gazeAngleUnitVector;
+  android.hardware.automotive.occupant_awareness.VehicleRegion gazeTarget;
+  String customGazeTarget;
+  long timeOnTargetMillis;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl
new file mode 100644
index 0000000..7faff00
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+interface IOccupantAwareness {
+  android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus startDetection();
+  android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus stopDetection();
+  int getCapabilityForRole(in android.hardware.automotive.occupant_awareness.Role occupantRole);
+  android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus getState(in android.hardware.automotive.occupant_awareness.Role occupantRole, in int detectionCapability);
+  void setCallback(in android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback callback);
+  void getLatestDetection(out android.hardware.automotive.occupant_awareness.OccupantDetections detections);
+  const int CAP_NONE = 0;
+  const int CAP_PRESENCE_DETECTION = 1;
+  const int CAP_GAZE_DETECTION = 2;
+  const int CAP_DRIVER_MONITORING_DETECTION = 4;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl
new file mode 100644
index 0000000..31b8220
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+interface IOccupantAwarenessClientCallback {
+  oneway void onSystemStatusChanged(in int detectionFlags, in android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus status);
+  oneway void onDetectionEvent(in android.hardware.automotive.occupant_awareness.OccupantDetections detections);
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl
new file mode 100644
index 0000000..26371c9
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@Backing(type="byte") @VintfStability
+enum OccupantAwarenessStatus {
+  READY = 0,
+  NOT_SUPPORTED = 1,
+  NOT_INITIALIZED = 2,
+  FAILURE = 3,
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl
new file mode 100644
index 0000000..42b1095
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+parcelable OccupantDetection {
+  android.hardware.automotive.occupant_awareness.Role role;
+  android.hardware.automotive.occupant_awareness.PresenceDetection[] presenceData;
+  android.hardware.automotive.occupant_awareness.GazeDetection[] gazeData;
+  android.hardware.automotive.occupant_awareness.DriverMonitoringDetection[] attentionData;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl
new file mode 100644
index 0000000..9bcad6b
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+parcelable OccupantDetections {
+  long timeStampMillis;
+  android.hardware.automotive.occupant_awareness.OccupantDetection[] detections;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl
new file mode 100644
index 0000000..dd6c5c8
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@VintfStability
+parcelable PresenceDetection {
+  boolean isOccupantDetected;
+  long detectionDurationMillis;
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/Role.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/Role.aidl
new file mode 100644
index 0000000..7b2b907
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/Role.aidl
@@ -0,0 +1,35 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@Backing(type="int") @VintfStability
+enum Role {
+  INVALID = 0,
+  UNKNOWN = 1,
+  FRONT_PASSENGER = 2,
+  DRIVER = 4,
+  ROW_2_PASSENGER_LEFT = 8,
+  ROW_2_PASSENGER_CENTER = 16,
+  ROW_2_PASSENGER_RIGHT = 32,
+  ROW_3_PASSENGER_LEFT = 64,
+  ROW_3_PASSENGER_CENTER = 128,
+  ROW_3_PASSENGER_RIGHT = 256,
+  FRONT_OCCUPANTS = 6,
+  ROW_2_OCCUPANTS = 56,
+  ROW_3_OCCUPANTS = 448,
+  ALL_OCCUPANTS = 511,
+}
diff --git a/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl
new file mode 100644
index 0000000..f96d950
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/aidl_api/android.hardware.automotive.occupant_awareness/current/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.occupant_awareness;
+@Backing(type="int") @VintfStability
+enum VehicleRegion {
+  UNKNOWN = 0,
+  INSTRUMENT_CLUSTER = 1,
+  REAR_VIEW_MIRROR = 2,
+  LEFT_SIDE_MIRROR = 3,
+  RIGHT_SIDE_MIRROR = 4,
+  FORWARD_ROADWAY = 5,
+  LEFT_ROADWAY = 6,
+  RIGHT_ROADWAY = 7,
+  HEAD_UNIT_DISPLAY = 8,
+  CUSTOM_TARGET = 200,
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl
new file mode 100644
index 0000000..8597ddb
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/ConfidenceLevel.aidl
@@ -0,0 +1,40 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+@VintfStability
+@Backing(type="byte")
+enum ConfidenceLevel {
+    /**
+     * No prediction could be made.
+     */
+    NONE,
+    /**
+     * Best-guess, low-confidence prediction. Predictions exceeding this threshold are adequate
+     * for non-critical applications.
+     */
+    LOW,
+    /**
+     * High-confidence prediction. Predictions exceeding this threshold are adequate for
+     * applications that require reliable predictions.
+     */
+    HIGH,
+    /**
+     * Highest confidence rate achievable.
+     */
+    MAX,
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl
new file mode 100644
index 0000000..f5cc9d5
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/DriverMonitoringDetection.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.ConfidenceLevel;
+
+@VintfStability
+parcelable DriverMonitoringDetection {
+    /*
+     * Confidence of the computed attention data.
+     */
+    ConfidenceLevel confidenceScore;
+    /*
+     * Is the driver currently looking on-road?
+     */
+    boolean isLookingOnRoad;
+    /*
+     * Duration the driver has been looking on or off road, in milliseconds.
+     */
+    long gazeDurationMillis;
+}
+
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/GazeDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/GazeDetection.aidl
new file mode 100644
index 0000000..fc36e13
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/GazeDetection.aidl
@@ -0,0 +1,57 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.VehicleRegion;
+import android.hardware.automotive.occupant_awareness.ConfidenceLevel;
+
+@VintfStability
+parcelable GazeDetection {
+    /*
+     * Confidence level for the gaze detection.
+     */
+    ConfidenceLevel gazeConfidence;
+    /*
+     * Head position, in millimeters. The vehicle coordinate system is specified in the cabin space
+     * configuration. headPosition is double[3] array.
+     */
+    double[] headPosition;
+    /*
+     * Unit vector for the head pose direction. The vehicle coordinate system is specified in the
+     * cabin space configuration. headAngleUnitVector is double[3] array.
+     */
+    double[] headAngleUnitVector;
+    /*
+     * Unit vector for the gaze direction. The vehicle coordinate system is specified in the cabin
+     * space configuration. gazeAngleUnitVector is double[3] array.
+     */
+    double[] gazeAngleUnitVector;
+    /*
+     * Current gaze target.
+     */
+    VehicleRegion gazeTarget;
+    /*
+     * Custom gaze target string. This only need to be populated when gazeTarget is CUSTOM_TARGET.
+     * Vendors should use "com.vendor_name.target_name" format to avoid name collision with other
+     * vendors.
+     */
+    String customGazeTarget;
+    /*
+     * Duration that the subject has been looking at the current gaze target in milliseconds.
+     */
+    long timeOnTargetMillis;
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl
new file mode 100644
index 0000000..1df0bda
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwareness.aidl
@@ -0,0 +1,88 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
+import android.hardware.automotive.occupant_awareness.Role;
+import android.hardware.automotive.occupant_awareness.IOccupantAwarenessClientCallback;
+import android.hardware.automotive.occupant_awareness.OccupantDetections;
+
+@VintfStability
+interface IOccupantAwareness {
+    /*
+     * System not able to generate any occupancy awareness.
+     */
+    const int CAP_NONE = 0;
+    /*
+     * System is able to detect the presence of humans.
+     */
+    const int CAP_PRESENCE_DETECTION = 1 << 0;
+    /*
+     * System is able to detect the gaze of humans.
+     */
+    const int CAP_GAZE_DETECTION = 1 << 1;
+    /*
+     * System is able to compute the attention details of humans.
+     */
+    const int CAP_DRIVER_MONITORING_DETECTION = 1 << 2;
+
+    /**
+     * Starts the occupant awareness detection system. This is a non-blocking function call.
+     * Once system is ready, state will be modified. State update can be inrquired using callback
+     * or getState() function.
+     * @return status is the current system state.
+     */
+    OccupantAwarenessStatus startDetection();
+
+    /**
+     * Stops the occupant awareness detection system. This is a non-blocking function call.
+     * Once system is reset, state will be modified. State update can be inrquired using callback
+     * or getState() function.
+     * @return status is the current system state.
+     */
+    OccupantAwarenessStatus stopDetection();
+
+    /**
+     * Returns list of Awareness Capability supported for the given type of occupants.
+     *
+     * @param out Bitwise OR of supported capabilities (CAP_* mask).
+     */
+    int getCapabilityForRole(in Role occupantRole);
+
+    /**
+     * Inquires the current state of the occupant awareness system.
+     * @param occupantRole specifies the role of occupants of interest.
+     * @param detectionCapability specifies a single detection capability (CAP_* ) of interest.
+     *
+     * @return status is the current system state.
+     */
+    OccupantAwarenessStatus getState(in Role occupantRole, in int detectionCapability);
+
+    /**
+     * Registers a callback for data streaming. Only single callback is supported. setCallback()
+     *        should replace existing callback with new callback.
+     * @return: returns ok if successful.
+     */
+    void setCallback(in IOccupantAwarenessClientCallback callback);
+
+    /**
+     * Returns the most recent set of detections.
+     * @param OccupantDetections output detections.
+     * @return returns ok if successful.
+     */
+    void getLatestDetection(out OccupantDetections detections);
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl
new file mode 100644
index 0000000..69f7b0b
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/IOccupantAwarenessClientCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.OccupantAwarenessStatus;
+import android.hardware.automotive.occupant_awareness.OccupantDetections;
+
+@VintfStability
+interface IOccupantAwarenessClientCallback {
+    /**
+     * A callback invoked when the system status changes.
+     *
+     * @param detectionFlags The detection subsystem(s) whose status has changed.
+     * @param status The new system status.
+     */
+    oneway void onSystemStatusChanged(in int detectionFlags, in OccupantAwarenessStatus status);
+
+    /**
+     * A callback invoked when a new set of detections are available.
+     *
+     * @param detections Occupant detections.
+     */
+    oneway void onDetectionEvent(in OccupantDetections detections);
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl
new file mode 100644
index 0000000..6a3453d
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantAwarenessStatus.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+@VintfStability
+@Backing(type="byte")
+enum OccupantAwarenessStatus {
+    /*
+     * System is online and ready to serve requests.
+     */
+    READY = 0,
+    /**
+     * Detection is not supported in this vehicle due to a permanent lack of capabilities. Clients
+     * need not retry.
+     */
+    NOT_SUPPORTED = 1,
+    /*
+     * The system has not yet been initialized. No requests can be served until the
+     * initialization process completes. This state does not indicate any error and
+     * clients should retry later.
+     */
+    NOT_INITIALIZED = 2,
+    /*
+     * A permanent failure has occurred. No detections will be provided.
+     */
+    FAILURE = 3,
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl
new file mode 100644
index 0000000..47ca35a
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetection.aidl
@@ -0,0 +1,50 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.Role;
+import android.hardware.automotive.occupant_awareness.PresenceDetection;
+import android.hardware.automotive.occupant_awareness.GazeDetection;
+import android.hardware.automotive.occupant_awareness.DriverMonitoringDetection;
+
+/*
+ * A complete detection for a single occupant in the vehicle. Includes data about the subject's
+ * presence in the vehicle, gaze and attention.
+ */
+ @VintfStability
+parcelable OccupantDetection {
+    /*
+     * Role of the occupant (e.g., driver, passenger).
+     */
+    Role role;
+    /*
+     * Occupant presence state for a single occupant.
+     * If the vector is empty, no data could be generated.
+     */
+    PresenceDetection[] presenceData;
+    /*
+     * Gaze data for a single occupant.
+     * If the vector is empty, no data could be generated.
+     */
+    GazeDetection[] gazeData;
+    /*
+     * Attention data for a single occupant.
+     * If the vector is empty, no data could be generated.
+     */
+    DriverMonitoringDetection[] attentionData;
+}
+
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl
new file mode 100644
index 0000000..e8f6621
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/OccupantDetections.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+import android.hardware.automotive.occupant_awareness.OccupantDetection;
+
+@VintfStability
+parcelable OccupantDetections {
+    /**
+     * Timestamp that the underlying source image was captured, in milliseconds since Jan 1, 1970
+     * (Unix time).
+     */
+    long timeStampMillis;
+    /**
+     * A vector of detections for all occupants in the vehicle. One OccupantDetection will be
+     * generated per detected face.
+     */
+    OccupantDetection[] detections;
+}
+
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl
new file mode 100644
index 0000000..a018106
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/PresenceDetection.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+@VintfStability
+parcelable PresenceDetection {
+    /*
+     * Boolean representing whether an occupant was detected.
+     */
+    boolean isOccupantDetected;
+    /**
+     * Duration that a particular occupant has been continuously
+     * detected, in milliseconds. Will be zero duration if the occupant is not
+     * currently detected.
+     */
+    long detectionDurationMillis;
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/Role.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/Role.aidl
new file mode 100644
index 0000000..42e86ad
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/Role.aidl
@@ -0,0 +1,83 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+@VintfStability
+@Backing(type="int")
+enum Role {
+    /*
+     * All valid role(s) must have at least 1 bit set.
+     */
+    INVALID = 0,
+    /*
+     * System could not determine role for this occupant.
+     */
+    UNKNOWN = 1 << 0,
+    /*
+     * Occupants that the system detects as front seat passengers.
+     */
+    FRONT_PASSENGER = 1 << 1,
+    /*
+     * Occupants that the system detects as driver(s).
+     */
+    DRIVER = 1 << 2,
+    /*
+     * Occupants on left seat of row 2.
+     */
+    ROW_2_PASSENGER_LEFT = 1 << 3,
+    /*
+     * Occupants on center seat of row 2.
+     */
+    ROW_2_PASSENGER_CENTER = 1 << 4,
+    /*
+     * Occupants on right seat of row 2.
+     */
+    ROW_2_PASSENGER_RIGHT = 1 << 5,
+    /*
+     * Occupants on left seat of row 3.
+     */
+    ROW_3_PASSENGER_LEFT = 1 << 6,
+    /*
+     * Occupants on center seat of row 3.
+     */
+    ROW_3_PASSENGER_CENTER = 1 << 7,
+    /*
+     * Occupants on right seat of row 3.
+     */
+    ROW_3_PASSENGER_RIGHT = 1 << 8,
+
+    /*
+     * Occupants that the system detects as front seat occupant.
+     * FRONT_OCCUPANTS = DRIVER | FRONT_PASSENGER
+     */
+    FRONT_OCCUPANTS = 1 << 1 | 1 << 2,
+    /*
+     * Occupants of row 2.
+     * ROW_2_OCCUPANTS = ROW_2_PASSENGER_LEFT | ROW_2_PASSENGER_CENTER | ROW_2_PASSENGER_RIGHT
+     */
+    ROW_2_OCCUPANTS = 1 << 3 | 1 << 4 | 1 << 5,
+    /*
+     * Occupants of row 3.
+     * ROW_3_OCCUPANTS = ROW_3_PASSENGER_LEFT | ROW_3_PASSENGER_CENTER | ROW_3_PASSENGER_RIGHT
+     */
+    ROW_3_OCCUPANTS = 1 << 6 | 1 << 7 | 1 << 8,
+    /*
+     * All the occupants in the vehicle.
+     * ALL_OCCUPANTS = UNKNOWN | FRONT_OCCUPANTS | ROW_2_OCCUPANTS | ROW_3_OCCUPANTS
+     */
+    ALL_OCCUPANTS = 0x1FF,
+}
diff --git a/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl
new file mode 100644
index 0000000..9ee9d52
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/android/hardware/automotive/occupant_awareness/VehicleRegion.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.automotive.occupant_awareness;
+
+@VintfStability
+@Backing(type="int")
+enum VehicleRegion {
+    /*
+     * List of targets in the car.
+     */
+    UNKNOWN = 0,
+    INSTRUMENT_CLUSTER = 1,
+    REAR_VIEW_MIRROR = 2,
+    LEFT_SIDE_MIRROR = 3,
+    RIGHT_SIDE_MIRROR = 4,
+    FORWARD_ROADWAY = 5,
+    LEFT_ROADWAY = 6,
+    RIGHT_ROADWAY = 7,
+    HEAD_UNIT_DISPLAY = 8,
+    /*
+     * Vendors can use this value along with customGazeTarget string to uniquely identify their
+     * custom region.
+     */
+    CUSTOM_TARGET = 200,
+}
diff --git a/automotive/occupant_awareness/aidl/default/Android.bp b/automotive/occupant_awareness/aidl/default/Android.bp
new file mode 100644
index 0000000..1b2fba2
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/default/Android.bp
@@ -0,0 +1,32 @@
+/*
+ * 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.automotive.occupant_awareness@1.0-service",
+    init_rc: ["android.hardware.automotive.occupant_awareness@1.0-service.rc"],
+    relative_install_path: "hw",
+    vendor: true,
+    srcs: [
+        "service.cpp",
+        "OccupantAwareness.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libutils",
+        "android.hardware.automotive.occupant_awareness-ndk_platform",
+    ],
+}
diff --git a/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp b/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp
new file mode 100644
index 0000000..a156075
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/default/OccupantAwareness.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "OccupantAwareness.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace occupant_awareness {
+namespace V1_0 {
+namespace implementation {
+
+using ndk::ScopedAStatus;
+
+static const int32_t kAllCapabilities = OccupantAwareness::CAP_PRESENCE_DETECTION |
+                                        OccupantAwareness::CAP_GAZE_DETECTION |
+                                        OccupantAwareness::CAP_DRIVER_MONITORING_DETECTION;
+
+ScopedAStatus OccupantAwareness::startDetection(OccupantAwarenessStatus* status) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mStatus != OccupantAwarenessStatus::NOT_SUPPORTED) {
+        mStatus = OccupantAwarenessStatus::NOT_SUPPORTED;
+        if (mCallback) {
+            mCallback->onSystemStatusChanged(kAllCapabilities,
+                                             OccupantAwarenessStatus::NOT_SUPPORTED);
+        }
+    }
+    *status = mStatus;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::stopDetection(OccupantAwarenessStatus* status) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mStatus != OccupantAwarenessStatus::NOT_INITIALIZED) {
+        mStatus = OccupantAwarenessStatus::NOT_INITIALIZED;
+        if (mCallback) {
+            mCallback->onSystemStatusChanged(kAllCapabilities,
+                                             OccupantAwarenessStatus::NOT_INITIALIZED);
+        }
+    }
+    *status = mStatus;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::getCapabilityForRole(Role occupantRole, int32_t* capabilities) {
+    if (!isValidRole(occupantRole)) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    // No awareness capability for default HAL.
+    *capabilities = 0;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::getState(Role occupantRole, int detectionCapability,
+                                          OccupantAwarenessStatus* status) {
+    if (!isValidRole(occupantRole)) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    if (!isValidDetectionCapabilities(detectionCapability) ||
+        !isSingularCapability(detectionCapability)) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    *status = mStatus;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::setCallback(
+        const std::shared_ptr<IOccupantAwarenessClientCallback>& callback) {
+    if (callback == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    mCallback = callback;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::getLatestDetection(OccupantDetections* detections) {
+    // No detection generated for default hal.
+    (void)detections;
+    return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+}
+
+bool OccupantAwareness::isValidRole(Role occupantRole) {
+    int intVal = static_cast<int>(occupantRole);
+    int allOccupants = static_cast<int>(Role::ALL_OCCUPANTS);
+    return (occupantRole != Role::INVALID) && ((intVal & (~allOccupants)) == 0);
+}
+
+bool OccupantAwareness::isValidDetectionCapabilities(int detectionCapabilities) {
+    return (detectionCapabilities != CAP_NONE) &&
+           ((detectionCapabilities & (~kAllCapabilities)) == 0);
+}
+
+bool OccupantAwareness::isSingularCapability(int detectionCapability) {
+    // Check whether the value is 0, or the value has only one bit set.
+    return (detectionCapability & (detectionCapability - 1)) == 0;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace occupant_awareness
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/occupant_awareness/aidl/default/OccupantAwareness.h b/automotive/occupant_awareness/aidl/default/OccupantAwareness.h
new file mode 100644
index 0000000..ac51aa4
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/default/OccupantAwareness.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#pragma once
+#include <aidl/android/hardware/automotive/occupant_awareness/BnOccupantAwareness.h>
+#include <aidl/android/hardware/automotive/occupant_awareness/BnOccupantAwarenessClientCallback.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace occupant_awareness {
+namespace V1_0 {
+namespace implementation {
+
+using ::aidl::android::hardware::automotive::occupant_awareness::BnOccupantAwareness;
+using ::aidl::android::hardware::automotive::occupant_awareness::IOccupantAwarenessClientCallback;
+using ::aidl::android::hardware::automotive::occupant_awareness::OccupantAwarenessStatus;
+using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetections;
+using ::aidl::android::hardware::automotive::occupant_awareness::Role;
+
+/**
+ * The default HAL mimics a system which has no Occupant awareness capability. The hal does not
+ * do any useful work, and returns appropriate failure code / status.
+ **/
+class OccupantAwareness : public BnOccupantAwareness {
+  public:
+    // Methods from ::android::hardware::automotive::occupant_awareness::IOccupantAwareness
+    // follow.
+    ndk::ScopedAStatus startDetection(OccupantAwarenessStatus* status) override;
+    ndk::ScopedAStatus stopDetection(OccupantAwarenessStatus* status) override;
+    ndk::ScopedAStatus getCapabilityForRole(Role occupantRole, int32_t* capabilities) override;
+    ndk::ScopedAStatus getState(Role occupantRole, int detectionCapability,
+                                OccupantAwarenessStatus* status) override;
+    ndk::ScopedAStatus setCallback(
+            const std::shared_ptr<IOccupantAwarenessClientCallback>& callback) override;
+    ndk::ScopedAStatus getLatestDetection(OccupantDetections* detections) override;
+
+  private:
+    bool isValidRole(Role occupantRole);
+    bool isValidDetectionCapabilities(int detectionCapabilities);
+    bool isSingularCapability(int detectionCapability);
+
+    std::mutex mMutex;
+    std::shared_ptr<IOccupantAwarenessClientCallback> mCallback = nullptr;
+    OccupantAwarenessStatus mStatus = OccupantAwarenessStatus::NOT_INITIALIZED;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace occupant_awareness
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/occupant_awareness/aidl/default/android.hardware.automotive.occupant_awareness@1.0-service.rc b/automotive/occupant_awareness/aidl/default/android.hardware.automotive.occupant_awareness@1.0-service.rc
new file mode 100644
index 0000000..35d5bca
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/default/android.hardware.automotive.occupant_awareness@1.0-service.rc
@@ -0,0 +1,4 @@
+service hal_occupant_awareness_default /vendor/bin/hw/android.hardware.automotive.occupant_awareness@1.0-service
+    class hal
+    user system
+    group system
diff --git a/automotive/occupant_awareness/aidl/default/service.cpp b/automotive/occupant_awareness/aidl/default/service.cpp
new file mode 100644
index 0000000..44960fb
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.occupant_awareness@1.0-service"
+
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "OccupantAwareness.h"
+
+using ::aidl::android::hardware::automotive::occupant_awareness::IOccupantAwareness;
+using ::android::hardware::automotive::occupant_awareness::V1_0::implementation::OccupantAwareness;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+
+const static char kOccupantAwarenessServiceName[] = "default";
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    LOG(INFO) << "Occupant Awareness service is starting";
+    std::shared_ptr<OccupantAwareness> occupantAwareness = SharedRefBase::make<OccupantAwareness>();
+
+    const std::string instance =
+            std::string() + IOccupantAwareness::descriptor + "/" + kOccupantAwarenessServiceName;
+
+    binder_status_t status =
+            AServiceManager_addService(occupantAwareness->asBinder().get(), instance.c_str());
+    if (status == STATUS_OK) {
+        LOG(INFO) << "Service " << kOccupantAwarenessServiceName << " is ready";
+        ABinderProcess_joinThreadPool();
+    } else {
+        LOG(ERROR) << "Could not register service " << kOccupantAwarenessServiceName
+                   << ", status: " << status;
+    }
+
+    // In normal operation, we don't expect the thread pool to exit.
+    LOG(ERROR) << "Occupant Awareness service is shutting down";
+    return 1;
+}
diff --git a/automotive/occupant_awareness/aidl/mock/Android.bp b/automotive/occupant_awareness/aidl/mock/Android.bp
new file mode 100644
index 0000000..4b30866
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/Android.bp
@@ -0,0 +1,32 @@
+/*
+ * 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.automotive.occupant_awareness@1.0-service_mock",
+    relative_install_path: "hw",
+    vendor: true,
+    srcs: [
+        "service.cpp",
+        "OccupantAwareness.cpp",
+        "DetectionGenerator.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libutils",
+        "android.hardware.automotive.occupant_awareness-ndk_platform",
+    ],
+}
diff --git a/automotive/occupant_awareness/aidl/mock/DetectionGenerator.cpp b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.cpp
new file mode 100644
index 0000000..79d4dbc
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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/SystemClock.h>
+
+#include "DetectionGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace occupant_awareness {
+namespace V1_0 {
+namespace implementation {
+
+using ::aidl::android::hardware::automotive::occupant_awareness::ConfidenceLevel;
+using ::aidl::android::hardware::automotive::occupant_awareness::DriverMonitoringDetection;
+using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetection;
+using ::aidl::android::hardware::automotive::occupant_awareness::PresenceDetection;
+
+static int64_t kNanoSecondsPerMilliSecond = 1000 * 1000;
+
+OccupantDetections DetectionGenerator::GetNextDetections() {
+    OccupantDetections detections;
+    detections.timeStampMillis = android::elapsedRealtimeNano() / kNanoSecondsPerMilliSecond;
+    int remainingRoles = getSupportedRoles();
+    while (remainingRoles) {
+        int currentRole = remainingRoles & (~(remainingRoles - 1));
+        remainingRoles = remainingRoles & (remainingRoles - 1);
+
+        OccupantDetection occupantDetection;
+        occupantDetection.role = static_cast<Role>(currentRole);
+
+        // Add presence detection object for this occupant.
+        PresenceDetection presenceDetection;
+        presenceDetection.isOccupantDetected = true;
+        presenceDetection.detectionDurationMillis = detections.timeStampMillis;
+        occupantDetection.presenceData.emplace_back(presenceDetection);
+
+        if (occupantDetection.role == Role::DRIVER) {
+            // Add driver monitoring detection object for this occupant.
+            DriverMonitoringDetection driverMonitoringDetection;
+            driverMonitoringDetection.confidenceScore = ConfidenceLevel::HIGH;
+            driverMonitoringDetection.isLookingOnRoad = 0;
+            driverMonitoringDetection.gazeDurationMillis = detections.timeStampMillis;
+            occupantDetection.attentionData.emplace_back(driverMonitoringDetection);
+        }
+
+        detections.detections.emplace_back(occupantDetection);
+    }
+    return detections;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace occupant_awareness
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/occupant_awareness/aidl/mock/DetectionGenerator.h b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.h
new file mode 100644
index 0000000..0884685
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/DetectionGenerator.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/automotive/occupant_awareness/BnOccupantAwareness.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace occupant_awareness {
+namespace V1_0 {
+namespace implementation {
+
+using ::aidl::android::hardware::automotive::occupant_awareness::BnOccupantAwareness;
+using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetections;
+using ::aidl::android::hardware::automotive::occupant_awareness::Role;
+
+class DetectionGenerator {
+  public:
+    static int getSupportedRoles() {
+        return static_cast<int>(Role::DRIVER) | static_cast<int>(Role::FRONT_PASSENGER);
+    }
+    static int getSupportedCapabilities() {
+        return static_cast<int>(BnOccupantAwareness::CAP_PRESENCE_DETECTION) |
+               static_cast<int>(BnOccupantAwareness::CAP_DRIVER_MONITORING_DETECTION);
+    }
+
+    OccupantDetections GetNextDetections();
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace occupant_awareness
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/occupant_awareness/aidl/mock/OccupantAwareness.cpp b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.cpp
new file mode 100644
index 0000000..910760a
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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/SystemClock.h>
+
+#include "OccupantAwareness.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace occupant_awareness {
+namespace V1_0 {
+namespace implementation {
+
+using ndk::ScopedAStatus;
+
+static const int32_t kAllCapabilities = OccupantAwareness::CAP_PRESENCE_DETECTION |
+                                        OccupantAwareness::CAP_GAZE_DETECTION |
+                                        OccupantAwareness::CAP_DRIVER_MONITORING_DETECTION;
+
+constexpr int64_t kNanoSecondsPerMilliSecond = 1000 * 1000;
+
+ScopedAStatus OccupantAwareness::startDetection(OccupantAwarenessStatus* status) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mStatus != OccupantAwarenessStatus::NOT_INITIALIZED) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    mStatus = OccupantAwarenessStatus::READY;
+    mWorkerThread = std::thread(startWorkerThread, this);
+    if (mCallback) {
+        mCallback->onSystemStatusChanged(kAllCapabilities, mStatus);
+    }
+
+    *status = mStatus;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::stopDetection(OccupantAwarenessStatus* status) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mStatus != OccupantAwarenessStatus::READY) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    mStatus = OccupantAwarenessStatus::NOT_INITIALIZED;
+    mWorkerThread.join();
+    if (mCallback) {
+        mCallback->onSystemStatusChanged(kAllCapabilities, mStatus);
+    }
+
+    *status = mStatus;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::getCapabilityForRole(Role occupantRole, int32_t* capabilities) {
+    if (!isValidRole(occupantRole)) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    int intVal = static_cast<int>(occupantRole);
+    if ((intVal & DetectionGenerator::getSupportedRoles()) == intVal) {
+        int capabilities_ = DetectionGenerator::getSupportedCapabilities();
+        if (occupantRole != Role::DRIVER) {
+            capabilities_ &= ~CAP_DRIVER_MONITORING_DETECTION;
+        }
+        *capabilities = capabilities_;
+    } else {
+        *capabilities = 0;
+    }
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::getState(Role occupantRole, int detectionCapability,
+                                          OccupantAwarenessStatus* status) {
+    if (!isValidRole(occupantRole)) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    if (!isValidDetectionCapabilities(detectionCapability) ||
+        !isSingularCapability(detectionCapability)) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    int roleVal = static_cast<int>(occupantRole);
+
+    if (((roleVal & DetectionGenerator::getSupportedRoles()) != roleVal) ||
+        ((detectionCapability & DetectionGenerator::getSupportedCapabilities()) !=
+         detectionCapability)) {
+        *status = OccupantAwarenessStatus::NOT_SUPPORTED;
+        return ScopedAStatus::ok();
+    }
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    *status = mStatus;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::setCallback(
+        const std::shared_ptr<IOccupantAwarenessClientCallback>& callback) {
+    if (callback == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    mCallback = callback;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus OccupantAwareness::getLatestDetection(OccupantDetections* detections) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    if (mStatus != OccupantAwarenessStatus::READY) {
+        return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+    }
+
+    *detections = mLatestDetections;
+    return ScopedAStatus::ok();
+}
+
+bool OccupantAwareness::isValidRole(Role occupantRole) {
+    int intVal = static_cast<int>(occupantRole);
+    int allOccupants = static_cast<int>(Role::ALL_OCCUPANTS);
+    return (occupantRole != Role::INVALID) && ((intVal & (~allOccupants)) == 0);
+}
+
+bool OccupantAwareness::isValidDetectionCapabilities(int detectionCapabilities) {
+    return (detectionCapabilities != OccupantAwareness::CAP_NONE) &&
+           ((detectionCapabilities & (~kAllCapabilities)) == 0);
+}
+
+bool OccupantAwareness::isSingularCapability(int detectionCapability) {
+    // Check whether the value is 0, or the value has only one bit set.
+    return (detectionCapability & (detectionCapability - 1)) == 0;
+}
+
+void OccupantAwareness::startWorkerThread(OccupantAwareness* occupantAwareness) {
+    occupantAwareness->workerThreadFunction();
+}
+
+void OccupantAwareness::workerThreadFunction() {
+    bool isFirstDetection = true;
+    int64_t prevDetectionTimeMs;
+    while (mStatus == OccupantAwarenessStatus::READY) {
+        int64_t currentTimeMs = android::elapsedRealtimeNano() / kNanoSecondsPerMilliSecond;
+        if ((isFirstDetection) || (currentTimeMs - prevDetectionTimeMs > mDetectionDurationMs)) {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mLatestDetections = mGenerator.GetNextDetections();
+            if (mCallback != nullptr) {
+                mCallback->onDetectionEvent(mLatestDetections);
+            }
+            isFirstDetection = false;
+            prevDetectionTimeMs = currentTimeMs;
+        }
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace occupant_awareness
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/occupant_awareness/aidl/mock/OccupantAwareness.h b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.h
new file mode 100644
index 0000000..c5f6dd6
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/OccupantAwareness.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <thread>
+
+#include <aidl/android/hardware/automotive/occupant_awareness/BnOccupantAwareness.h>
+#include <aidl/android/hardware/automotive/occupant_awareness/BnOccupantAwarenessClientCallback.h>
+#include <utils/StrongPointer.h>
+
+#include "DetectionGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace occupant_awareness {
+namespace V1_0 {
+namespace implementation {
+
+using ::aidl::android::hardware::automotive::occupant_awareness::BnOccupantAwareness;
+using ::aidl::android::hardware::automotive::occupant_awareness::IOccupantAwarenessClientCallback;
+using ::aidl::android::hardware::automotive::occupant_awareness::OccupantAwarenessStatus;
+using ::aidl::android::hardware::automotive::occupant_awareness::OccupantDetections;
+using ::aidl::android::hardware::automotive::occupant_awareness::Role;
+
+/**
+ * The mock HAL can detect presence of Driver and front passenger, and driver awareness detection
+ * for driver.
+ **/
+class OccupantAwareness : public BnOccupantAwareness {
+  public:
+    // Methods from ::android::hardware::automotive::occupant_awareness::IOccupantAwareness
+    // follow.
+    ndk::ScopedAStatus startDetection(OccupantAwarenessStatus* status) override;
+    ndk::ScopedAStatus stopDetection(OccupantAwarenessStatus* status) override;
+    ndk::ScopedAStatus getCapabilityForRole(Role occupantRole, int32_t* capabilities) override;
+    ndk::ScopedAStatus getState(Role occupantRole, int detectionCapability,
+                                OccupantAwarenessStatus* status) override;
+    ndk::ScopedAStatus setCallback(
+            const std::shared_ptr<IOccupantAwarenessClientCallback>& callback) override;
+    ndk::ScopedAStatus getLatestDetection(OccupantDetections* detections) override;
+
+  private:
+    bool isValidRole(Role occupantRole);
+    bool isValidDetectionCapabilities(int detectionCapabilities);
+    bool isSingularCapability(int detectionCapability);
+
+    void workerThreadFunction();
+    static void startWorkerThread(OccupantAwareness* occupantAwareness);
+
+    std::mutex mMutex;
+    std::shared_ptr<IOccupantAwarenessClientCallback> mCallback = nullptr;
+    OccupantAwarenessStatus mStatus = OccupantAwarenessStatus::NOT_INITIALIZED;
+
+    OccupantDetections mLatestDetections;
+    std::thread mWorkerThread;
+
+    DetectionGenerator mGenerator;
+
+    // Generate a new detection every 1ms.
+    const int64_t mDetectionDurationMs = 1;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace occupant_awareness
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/occupant_awareness/aidl/mock/service.cpp b/automotive/occupant_awareness/aidl/mock/service.cpp
new file mode 100644
index 0000000..d8860df
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/mock/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.occupant_awareness@1.0-service_mock"
+
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "OccupantAwareness.h"
+
+using ::aidl::android::hardware::automotive::occupant_awareness::IOccupantAwareness;
+using ::android::hardware::automotive::occupant_awareness::V1_0::implementation::OccupantAwareness;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+
+const static char kOccupantAwarenessServiceName[] = "default";
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    LOG(INFO) << "Occupant Awareness service is starting";
+    std::shared_ptr<OccupantAwareness> occupantAwareness = SharedRefBase::make<OccupantAwareness>();
+
+    const std::string instance =
+            std::string() + IOccupantAwareness::descriptor + "/" + kOccupantAwarenessServiceName;
+
+    binder_status_t status =
+            AServiceManager_addService(occupantAwareness->asBinder().get(), instance.c_str());
+    if (status == STATUS_OK) {
+        LOG(INFO) << "Service " << kOccupantAwarenessServiceName << " is ready";
+        ABinderProcess_joinThreadPool();
+    } else {
+        LOG(ERROR) << "Could not register service " << kOccupantAwarenessServiceName
+                   << ", status: " << status;
+    }
+
+    // In normal operation, we don't expect the thread pool to exit.
+    LOG(ERROR) << "Occupant Awareness service is shutting down";
+    return 1;
+}
diff --git a/automotive/occupant_awareness/aidl/vts/functional/Android.bp b/automotive/occupant_awareness/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..1256b69
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/vts/functional/Android.bp
@@ -0,0 +1,17 @@
+cc_test {
+    name: "VtsHalOccupantAwarenessV1_0TargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalOccupantAwarenessV1_0TargetTest.cpp"],
+    shared_libs: [
+        "libbinder",
+    ],
+    static_libs: [
+        "android.hardware.automotive.occupant_awareness-cpp",
+    ],
+    test_suites: [
+        "vts-core",
+    ],
+}
diff --git a/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp b/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp
new file mode 100644
index 0000000..c431f9d
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp
@@ -0,0 +1,203 @@
+/*
+ * 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 "**** HAL log ****"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android-base/logging.h>
+#include <android/hardware/automotive/occupant_awareness/BnOccupantAwarenessClientCallback.h>
+#include <android/hardware/automotive/occupant_awareness/IOccupantAwareness.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <future>
+#include <vector>
+
+using namespace android::hardware::automotive::occupant_awareness;
+using android::hardware::automotive::occupant_awareness::IOccupantAwareness;
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+
+constexpr auto kTimeout = std::chrono::seconds(3);
+
+#define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk())
+
+class OccupantAwarenessCallback : public BnOccupantAwarenessClientCallback {
+  public:
+    OccupantAwarenessCallback(const std::function<void(int, OccupantAwarenessStatus)>& callback)
+        : mCallback(callback) {}
+    Status onSystemStatusChanged(int detectionFlags, OccupantAwarenessStatus status) override {
+        mCallback(detectionFlags, status);
+        return Status::ok();
+    }
+
+    Status onDetectionEvent(const OccupantDetections& detections) override {
+        (void)detections;
+        return Status::ok();
+    }
+
+  private:
+    std::function<void(int, OccupantAwarenessStatus)> mCallback;
+};
+
+class OccupantAwarenessAidl : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mOccupantAwarenessService =
+                android::waitForDeclaredService<IOccupantAwareness>(String16(GetParam().c_str()));
+        ASSERT_NE(mOccupantAwarenessService, nullptr);
+    }
+
+    sp<IOccupantAwareness> mOccupantAwarenessService;
+};
+
+// Test that startDetection() returns within the timeout.
+TEST_P(OccupantAwarenessAidl, StartDetectionTest) {
+    auto start = std::chrono::system_clock::now();
+    OccupantAwarenessStatus occupantAwarenessStatus;
+    Status status = mOccupantAwarenessService->startDetection(&occupantAwarenessStatus);
+    auto elapsed = std::chrono::system_clock::now() - start;
+    EXPECT_OK(status);
+    ASSERT_LE(elapsed, kTimeout);
+
+    EXPECT_OK(mOccupantAwarenessService->stopDetection(&occupantAwarenessStatus));
+}
+
+// Test that getCapabilityForRole() returns supported capabilities for the role. The test only
+// verifies that the IPC call returns successfully and does not verify the supported capabilities.
+TEST_P(OccupantAwarenessAidl, GetCapabilityTest) {
+    std::vector<Role> rolesToTest = {Role::FRONT_PASSENGER,        Role::DRIVER,
+                                     Role::ROW_2_PASSENGER_LEFT,   Role::ROW_2_PASSENGER_CENTER,
+                                     Role::ROW_2_PASSENGER_RIGHT,  Role::ROW_3_PASSENGER_LEFT,
+                                     Role::ROW_3_PASSENGER_CENTER, Role::ROW_3_PASSENGER_RIGHT,
+                                     Role::FRONT_OCCUPANTS,        Role::ROW_2_OCCUPANTS,
+                                     Role::ROW_3_OCCUPANTS,        Role::ALL_OCCUPANTS};
+
+    for (auto role : rolesToTest) {
+        int32_t capabilities;
+        EXPECT_OK(mOccupantAwarenessService->getCapabilityForRole(role, &capabilities));
+    }
+}
+
+// Test that getCapabilityForRole() returns failure when arguments are invalid.
+TEST_P(OccupantAwarenessAidl, GetCapabilityFailureTest) {
+    int32_t capabilities;
+    EXPECT_FALSE(
+            mOccupantAwarenessService->getCapabilityForRole(Role::INVALID, &capabilities).isOk());
+
+    Role invalidRole = static_cast<Role>(static_cast<int>(Role::ALL_OCCUPANTS) + 1);
+    EXPECT_FALSE(
+            mOccupantAwarenessService->getCapabilityForRole(invalidRole, &capabilities).isOk());
+}
+
+// Test that getState() returns within the timeout. The test do not attempt to verify the state, but
+// only checks that the IPC call returns successfully.
+TEST_P(OccupantAwarenessAidl, GetStateTest) {
+    std::vector<Role> rolesToTest = {Role::FRONT_PASSENGER,        Role::DRIVER,
+                                     Role::ROW_2_PASSENGER_LEFT,   Role::ROW_2_PASSENGER_CENTER,
+                                     Role::ROW_2_PASSENGER_RIGHT,  Role::ROW_3_PASSENGER_LEFT,
+                                     Role::ROW_3_PASSENGER_CENTER, Role::ROW_3_PASSENGER_RIGHT,
+                                     Role::FRONT_OCCUPANTS,        Role::ROW_2_OCCUPANTS,
+                                     Role::ROW_3_OCCUPANTS,        Role::ALL_OCCUPANTS};
+
+    std::vector<int> detectionCapabilities = {IOccupantAwareness::CAP_PRESENCE_DETECTION,
+                                              IOccupantAwareness::CAP_GAZE_DETECTION,
+                                              IOccupantAwareness::CAP_DRIVER_MONITORING_DETECTION};
+
+    for (auto role : rolesToTest) {
+        for (auto detectionCapability : detectionCapabilities) {
+            OccupantAwarenessStatus oasStatus;
+            EXPECT_OK(mOccupantAwarenessService->getState(role, detectionCapability, &oasStatus));
+        }
+    }
+}
+
+// Test that getState() returns failure with invalid args.
+TEST_P(OccupantAwarenessAidl, GetStateFailureTest) {
+    // Verify that getState() returns error when role is invalid (0).
+    OccupantAwarenessStatus oasStatus;
+    EXPECT_FALSE(mOccupantAwarenessService
+                         ->getState(Role::INVALID, IOccupantAwareness::CAP_PRESENCE_DETECTION,
+                                    &oasStatus)
+                         .isOk());
+
+    // Verify that getState() returns error when role is invalid (invalid flag).
+    int invalidRole = static_cast<int>(Role::ALL_OCCUPANTS) + 1;
+    EXPECT_FALSE(mOccupantAwarenessService
+                         ->getState(static_cast<Role>(invalidRole),
+                                    IOccupantAwareness::CAP_PRESENCE_DETECTION, &oasStatus)
+                         .isOk());
+
+    // Verify that getState() returns error when capability is invalid (none).
+    EXPECT_FALSE(mOccupantAwarenessService
+                         ->getState(Role::FRONT_PASSENGER, IOccupantAwareness::CAP_NONE, &oasStatus)
+                         .isOk());
+
+    // Verify that getState() returns error when capability is invalid (invalid flag).
+    int invalidDetectionFlags = 0x10;
+    EXPECT_FALSE(mOccupantAwarenessService
+                         ->getState(Role::FRONT_PASSENGER, invalidDetectionFlags, &oasStatus)
+                         .isOk());
+}
+
+// Test that setCallback() returns within the timeout.
+TEST_P(OccupantAwarenessAidl, SetCallbackTest) {
+    sp<OccupantAwarenessCallback> callback =
+            new OccupantAwarenessCallback([](int detectionFlags, OccupantAwarenessStatus status) {
+                (void)detectionFlags;
+                (void)status;
+            });
+    auto start = std::chrono::system_clock::now();
+    Status status = mOccupantAwarenessService->setCallback(callback);
+    auto elapsed = std::chrono::system_clock::now() - start;
+    EXPECT_OK(status);
+    ASSERT_LE(elapsed, kTimeout);
+}
+
+// Test that setCallback() returns failure with invalid args.
+TEST_P(OccupantAwarenessAidl, SetCallbackFailureTest) {
+    sp<OccupantAwarenessCallback> callback = nullptr;
+    Status status = mOccupantAwarenessService->setCallback(callback);
+    EXPECT_FALSE(status.isOk());
+}
+
+// Test that getLatestDetection() returns within the timeout.
+TEST_P(OccupantAwarenessAidl, GetLatestDetectionTest) {
+    auto start = std::chrono::system_clock::now();
+    OccupantDetections detections;
+    // Do not check status here, since error status is returned when no detection is present.
+    (void)mOccupantAwarenessService->getLatestDetection(&detections);
+    auto elapsed = std::chrono::system_clock::now() - start;
+    ASSERT_LE(elapsed, kTimeout);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        InstantiationName, OccupantAwarenessAidl,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IOccupantAwareness::descriptor)),
+        android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/automotive/sv/1.0/Android.bp b/automotive/sv/1.0/Android.bp
new file mode 100644
index 0000000..3a39148
--- /dev/null
+++ b/automotive/sv/1.0/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.sv@1.0",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "ISurroundView2dSession.hal",
+        "ISurroundView3dSession.hal",
+        "ISurroundViewService.hal",
+        "ISurroundViewSession.hal",
+        "ISurroundViewStream.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hidl.base@1.0",
+    ],
+    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 ed09859..d9ac239 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -27,6 +27,15 @@
     ],
 }
 
+cc_defaults {
+    name: "vhal_v2_0_target_defaults",
+    defaults: ["vhal_v2_0_defaults"],
+    shared_libs: [
+        "libbinder_ndk",
+        "carwatchdog_aidl_interface-ndk_platform",
+    ],
+}
+
 cc_library_headers {
     name: "vhal_v2_0_common_headers",
     vendor: true,
@@ -37,7 +46,7 @@
 cc_library {
     name: "android.hardware.automotive.vehicle@2.0-manager-lib",
     vendor: true,
-    defaults: ["vhal_v2_0_defaults"],
+    defaults: ["vhal_v2_0_target_defaults"],
     srcs: [
         "common/src/Obd2SensorStore.cpp",
         "common/src/SubscriptionManager.cpp",
@@ -46,6 +55,10 @@
         "common/src/VehiclePropertyStore.cpp",
         "common/src/VehicleUtils.cpp",
         "common/src/VmsUtils.cpp",
+        "common/src/WatchdogClient.cpp",
+    ],
+    shared_libs: [
+        "libbase",
     ],
     local_include_dirs: ["common/include/vhal_v2_0"],
     export_include_dirs: ["common/include"],
@@ -55,12 +68,16 @@
 cc_library_static {
     name: "android.hardware.automotive.vehicle@2.0-default-impl-lib",
     vendor: true,
-    defaults: ["vhal_v2_0_defaults"],
+    defaults: ["vhal_v2_0_target_defaults"],
     srcs: [
         "impl/vhal_v2_0/CommConn.cpp",
+        "impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
         "impl/vhal_v2_0/EmulatedVehicleHal.cpp",
+        "impl/vhal_v2_0/VehicleHalClient.cpp",
+        "impl/vhal_v2_0/VehicleHalServer.cpp",
         "impl/vhal_v2_0/VehicleEmulator.cpp",
         "impl/vhal_v2_0/PipeComm.cpp",
+        "impl/vhal_v2_0/ProtoMessageConverter.cpp",
         "impl/vhal_v2_0/SocketComm.cpp",
         "impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
         "impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
@@ -68,7 +85,10 @@
     ],
     local_include_dirs: ["common/include/vhal_v2_0"],
     export_include_dirs: ["impl"],
-    whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"],
+    whole_static_libs: [
+        "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib",
+        "android.hardware.automotive.vehicle@2.0-manager-lib",
+    ],
     shared_libs: [
         "libbase",
         "libjsoncpp",
@@ -80,10 +100,63 @@
     ],
 }
 
+// Library used  to emulate User HAL behavior through lshal debug requests.
+cc_library_static {
+    name: "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib",
+    vendor: true,
+    defaults: ["vhal_v2_0_target_defaults"],
+    srcs: [
+        "impl/vhal_v2_0/EmulatedUserHal.cpp",
+    ],
+}
+
+// Vehicle HAL Server reference impl lib
+cc_library_static {
+    name: "android.hardware.automotive.vehicle@2.0-server-common-lib",
+    vendor: true,
+    host_supported: true,
+    defaults: ["vhal_v2_0_defaults"],
+    local_include_dirs: ["common/include/vhal_v2_0"],
+    export_include_dirs: ["common/include"],
+    srcs: [
+        "common/src/Obd2SensorStore.cpp",
+        "common/src/VehicleObjectPool.cpp",
+        "common/src/VehicleUtils.cpp",
+    ],
+}
+
+// Vehicle HAL Server default implementation
+cc_library_static {
+    name: "android.hardware.automotive.vehicle@2.0-server-impl-lib",
+    vendor: true,
+    host_supported: true,
+    defaults: ["vhal_v2_0_defaults"],
+    local_include_dirs: ["common/include/vhal_v2_0"],
+    export_include_dirs: ["impl"],
+    srcs: [
+        "impl/vhal_v2_0/EmulatedUserHal.cpp",
+        "impl/vhal_v2_0/GeneratorHub.cpp",
+        "impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
+        "impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
+        "impl/vhal_v2_0/ProtoMessageConverter.cpp",
+        "impl/vhal_v2_0/VehicleHalServer.cpp",
+    ],
+    whole_static_libs: [
+        "android.hardware.automotive.vehicle@2.0-server-common-lib",
+    ],
+    static_libs: [
+        "android.hardware.automotive.vehicle@2.0-libproto-native",
+    ],
+    shared_libs: [
+        "libbase",
+        "libjsoncpp",
+    ],
+}
+
 cc_test {
     name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests",
     vendor: true,
-    defaults: ["vhal_v2_0_defaults"],
+    defaults: ["vhal_v2_0_target_defaults"],
     whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"],
     srcs: [
         "tests/RecurrentTimer_test.cpp",
@@ -93,13 +166,34 @@
         "tests/VehiclePropConfigIndex_test.cpp",
         "tests/VmsUtils_test.cpp",
     ],
+    shared_libs: [
+        "libbase",
+    ],
     header_libs: ["libbase_headers"],
     test_suites: ["general-tests"],
 }
 
+cc_test {
+    name: "android.hardware.automotive.vehicle@2.0-default-impl-unit-tests",
+    vendor: true,
+    defaults: ["vhal_v2_0_target_defaults"],
+    srcs: [
+        "impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp",
+    ],
+    static_libs: [
+        "android.hardware.automotive.vehicle@2.0-default-impl-lib",
+        "android.hardware.automotive.vehicle@2.0-libproto-native",
+        "libprotobuf-cpp-lite",
+    ],
+    test_suites: ["general-tests"],
+}
+
 cc_binary {
     name: "android.hardware.automotive.vehicle@2.0-service",
-    defaults: ["vhal_v2_0_defaults"],
+    defaults: ["vhal_v2_0_target_defaults"],
+    vintf_fragments: [
+        "android.hardware.automotive.vehicle@2.0-service.xml",
+    ],
     init_rc: ["android.hardware.automotive.vehicle@2.0-service.rc"],
     vendor: true,
     relative_install_path: "hw",
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
index d1fd555..47133fd 100644
--- a/automotive/vehicle/2.0/default/VehicleService.cpp
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -20,8 +20,13 @@
 
 #include <iostream>
 
-#include <vhal_v2_0/VehicleHalManager.h>
+#include <android/binder_process.h>
+#include <utils/Looper.h>
+#include <vhal_v2_0/EmulatedUserHal.h>
+#include <vhal_v2_0/EmulatedVehicleConnector.h>
 #include <vhal_v2_0/EmulatedVehicleHal.h>
+#include <vhal_v2_0/VehicleHalManager.h>
+#include <vhal_v2_0/WatchdogClient.h>
 
 using namespace android;
 using namespace android::hardware;
@@ -29,11 +34,14 @@
 
 int main(int /* argc */, char* /* argv */ []) {
     auto store = std::make_unique<VehiclePropertyStore>();
-    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get());
+    auto connector = impl::makeEmulatedPassthroughConnector();
+    auto userHal = connector->getEmulatedUserHal();
+    auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get(), userHal);
     auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
     auto service = std::make_unique<VehicleHalManager>(hal.get());
+    connector->setValuePool(hal->getValuePool());
 
-    configureRpcThreadpool(4, true /* callerWillJoin */);
+    configureRpcThreadpool(4, false /* callerWillJoin */);
 
     ALOGI("Registering as service...");
     status_t status = service->registerAsService();
@@ -43,8 +51,22 @@
         return 1;
     }
 
+    // Setup a binder thread pool to be a car watchdog client.
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    sp<Looper> looper(Looper::prepare(0 /* opts */));
+    std::shared_ptr<WatchdogClient> watchdogClient =
+            ndk::SharedRefBase::make<WatchdogClient>(looper, service.get());
+    // The current health check is done in the main thread, so it falls short of capturing the real
+    // situation. Checking through HAL binder thread should be considered.
+    if (!watchdogClient->initialize()) {
+        ALOGE("Failed to initialize car watchdog client");
+        return 1;
+    }
     ALOGI("Ready");
-    joinRpcThreadpool();
+    while (true) {
+        looper->pollAll(-1 /* timeoutMillis */);
+    }
 
     return 1;
 }
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.xml b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.xml
new file mode 100644
index 0000000..660b03d
--- /dev/null
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.automotive.vehicle</name>
+        <transport>hwbinder</transport>
+        <version>2.0</version>
+        <interface>
+            <name>IVehicle</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h
new file mode 100644
index 0000000..5e4bf27
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <vector>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android::hardware::automotive::vehicle::V2_0 {
+
+/**
+ *  Vehicle HAL talks to the vehicle through a client, instead of accessing
+ *  the car bus directly, to give us more flexibility on the implementation.
+ *  Android OS do not need direct access to the vehicle, and the communication
+ *  channel is also customizable.
+ *
+ *  Client lives on the Android (HAL) side to talk to the vehicle
+ */
+class IVehicleClient {
+  public:
+    IVehicleClient() = default;
+
+    IVehicleClient(const IVehicleClient&) = delete;
+
+    IVehicleClient& operator=(const IVehicleClient&) = delete;
+
+    IVehicleClient(IVehicleClient&&) = default;
+
+    virtual ~IVehicleClient() = default;
+
+    // Get configuration of all properties from server
+    virtual std::vector<VehiclePropConfig> getAllPropertyConfig() const = 0;
+
+    // Send the set property request to server
+    // updateStatus indicate if VHal should change the status of the value
+    // it should be false except injecting values for e2e tests
+    virtual StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) = 0;
+
+    // Receive a new property value from server
+    // updateStatus is true if and only if the value is
+    // generated by car (ECU/fake generator/injected)
+    virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0;
+
+    // Dump method forwarded from HIDL's debug()
+    // If implemented, it must return whether the caller should dump its state.
+    virtual bool dump(const hidl_handle& /* handle */, const hidl_vec<hidl_string>& /* options */) {
+        return true;
+    }
+};
+
+}  // namespace android::hardware::automotive::vehicle::V2_0
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
new file mode 100644
index 0000000..2908a55
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
@@ -0,0 +1,90 @@
+/*
+ * 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_VehicleConnector_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleConnector_H_
+
+#include <vector>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+#include "VehicleClient.h"
+#include "VehicleServer.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+/**
+ *  This file defines the interface of client/server pair for HAL-vehicle
+ *  communication. Vehicle HAL may use this interface to talk to the vehicle
+ *  regardless of the underlying communication channels.
+ */
+
+/**
+ *  If Android has direct access to the vehicle, then the client and
+ *  the server may act in passthrough mode to avoid extra IPC
+ *
+ *  Template is used here for spliting the logic of operating Android objects (VehicleClientType),
+ *  talking to cars (VehicleServerType) and the commucation between client and server (passthrough
+ *  mode in this case), so that we can easily combine different parts together without duplicating
+ *  codes (for example, in Google VHAL, the server talks to the fake car in the same way no matter
+ *  if it is on top of passthrough connector or VSOCK or any other communication channels between
+ *  client and server)
+ *
+ *  The alternative may be factoring the common logic of every operations for both client and
+ *  server. Which is not always the case. Making sure different non-template connectors calling
+ *  the same method is hard, especially when the engineer maintaining the code may not be aware
+ *  of it when making changes. Template is a clean and easy way to solve this problem in this
+ *  case.
+ */
+template <typename VehicleClientType, typename VehicleServerType>
+class IPassThroughConnector : public VehicleClientType, public VehicleServerType {
+    static_assert(std::is_base_of_v<IVehicleClient, VehicleClientType>);
+    static_assert(std::is_base_of_v<IVehicleServer, VehicleServerType>);
+
+  public:
+    std::vector<VehiclePropConfig> getAllPropertyConfig() const override {
+        return this->onGetAllPropertyConfig();
+    }
+
+    StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) override {
+        return this->onSetProperty(value, updateStatus);
+    }
+
+    void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) override {
+        return this->onPropertyValue(value, updateStatus);
+    }
+
+    bool dump(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override {
+        return this->onDump(handle, options);
+    }
+
+    // To be implemented:
+    // virtual std::vector<VehiclePropConfig> onGetAllPropertyConfig() = 0;
+    // virtual void onPropertyValue(const VehiclePropValue& value) = 0;
+    // virtual StatusCode onSetProperty(const VehiclePropValue& value) = 0;
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_VehicleConnector_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
index fd28483..fe01867 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
@@ -70,6 +70,26 @@
      */
     virtual void onCreate() {}
 
+    /**
+     * Dump method forwarded from HIDL's debug().
+     *
+     * By default it doesn't dump anything and let caller dump its properties, but it could be
+     * override to change the behavior. For example:
+     *
+     * - To augment caller's dump, it should dump its state and return true.
+     * - To not dump anything at all, it should just return false.
+     * - To provide custom dump (like dumping just specific state or executing a custom command),
+     *   it should check if options is not empty, handle the options accordingly, then return false.
+     *
+     * @param handle handle used to dump the contents.
+     * @param options options passed to dump.
+     *
+     * @return whether the caller should dump its state.
+     */
+    virtual bool dump(const hidl_handle& /* handle */, const hidl_vec<hidl_string>& /* options */) {
+        return true;
+    }
+
     void init(
         VehiclePropValuePool* valueObjectPool,
         const HalEventFunction& onHalEvent,
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
index c1e9e88..fcfe761 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
@@ -73,7 +73,9 @@
                                    int32_t propId)  override;
     Return<void> debugDump(debugDump_cb _hidl_cb = nullptr) override;
 
-private:
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
+
+  private:
     using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr;
     // Returns true if needs to call again shortly.
     using RetriableAction = std::function<bool()>;
@@ -96,6 +98,22 @@
     bool checkReadPermission(const VehiclePropConfig &config) const;
     void onAllClientsUnsubscribed(int32_t propertyId);
 
+    // Dump and commands
+    // TODO: most functions below (exception dump() and cmdSetOne()) should be const, but they rely
+    // on IVehicle.get(), which isn't...
+    void cmdDump(int fd, const hidl_vec<hidl_string>& options);
+    void cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId);
+    void cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config);
+
+    static bool checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options, size_t minSize);
+    static bool checkCallerHasWritePermissions(int fd);
+    static bool safelyParseInt(int fd, int index, std::string s, int* out);
+    void cmdHelp(int fd) const;
+    void cmdListAllProperties(int fd) const;
+    void cmdDumpAllProperties(int fd);
+    void cmdDumpSpecificProperties(int fd, const hidl_vec<hidl_string>& options);
+    void cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options);
+
     static bool isSubscribable(const VehiclePropConfig& config,
                                SubscribeFlags flags);
     static bool isSampleRateFixed(VehiclePropertyChangeMode mode);
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
index 946e74d..f2d3c13 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
@@ -21,6 +21,7 @@
 #include <deque>
 #include <map>
 #include <mutex>
+#include <memory>
 
 #include <android/hardware/automotive/vehicle/2.0/types.h>
 
@@ -205,7 +206,7 @@
         InternalPool(VehiclePropertyType type, size_t vectorSize)
             : mPropType(type), mVectorSize(vectorSize) {}
 
-        RecyclableType obtain() {
+        RecyclableType obtain() override {
             return ObjectPool<VehiclePropValue>::obtain();
         }
     protected:
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h
new file mode 100644
index 0000000..ba9799a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h
@@ -0,0 +1,68 @@
+/*
+ * 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 <vector>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android::hardware::automotive::vehicle::V2_0 {
+
+/**
+ *  Server lives on the vehicle side to talk to Android HAL.
+ *  Note that the server may not be run on Android
+ */
+class IVehicleServer {
+  public:
+    IVehicleServer() = default;
+
+    IVehicleServer(const IVehicleServer&) = delete;
+
+    IVehicleServer& operator=(const IVehicleServer&) = delete;
+
+    IVehicleServer(IVehicleServer&&) = default;
+
+    virtual ~IVehicleServer() = default;
+
+    // Receive the get property configuration request from HAL.
+    // Return a list of all property config
+    virtual std::vector<VehiclePropConfig> onGetAllPropertyConfig() const = 0;
+
+    // Receive the set property request from HAL.
+    // Process the setting and return the status code
+    // updateStatus indicate if VHal should change the status of the value
+    // it should be false except injecting values for e2e tests
+    virtual StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) = 0;
+
+    // Receive a new property value from car (via direct connection to the car bus or the emulator)
+    // and forward the value to HAL
+    // updateStatus is true if and only if the value is
+    // generated by car (ECU/fake generator/injected)
+    virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0;
+
+    // TODO (chenhaosjtuacm): fix this since there are no HIDL in non-Android OS
+#ifdef __ANDROID__
+    // Dump method forwarded from HIDL's debug()
+    // If implemented, it must return whether the caller should dump its state.
+    virtual bool onDump(const hidl_handle& /* handle */,
+                        const hidl_vec<hidl_string>& /* options */) {
+        return true;
+    }
+#endif  // __ANDROID__
+};
+
+}  // namespace android::hardware::automotive::vehicle::V2_0
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
index f97dfa1..9553415 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
@@ -19,7 +19,9 @@
 
 #include <memory>
 
+#ifdef __ANDROID__
 #include <hidl/HidlSupport.h>
+#endif
 
 #include <android/hardware/automotive/vehicle/2.0/types.h>
 
@@ -69,6 +71,8 @@
 void copyVehicleRawValue(VehiclePropValue::RawValue* dest,
                                 const VehiclePropValue::RawValue& src);
 
+#ifdef __ANDROID__
+
 template<typename T>
 void shallowCopyHidlVec(hidl_vec<T>* dest, const hidl_vec<T>& src);
 
@@ -76,6 +80,8 @@
 
 void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src);
 
+#endif  // __ANDROID__
+
 }  // namespace V2_0
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/WatchdogClient.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/WatchdogClient.h
new file mode 100644
index 0000000..578606d
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/WatchdogClient.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_automotive_vehicle_V2_0_WatchdogClient_H_
+#define android_hardware_automotive_vehicle_V2_0_WatchdogClient_H_
+
+#include "VehicleHalManager.h"
+
+#include <aidl/android/automotive/watchdog/BnCarWatchdog.h>
+#include <aidl/android/automotive/watchdog/BnCarWatchdogClient.h>
+#include <utils/Looper.h>
+#include <utils/Mutex.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+class WatchdogClient : public aidl::android::automotive::watchdog::BnCarWatchdogClient {
+  public:
+    explicit WatchdogClient(const ::android::sp<::android::Looper>& handlerLooper,
+                            VehicleHalManager* vhalManager);
+
+    ndk::ScopedAStatus checkIfAlive(
+            int32_t sessionId, aidl::android::automotive::watchdog::TimeoutLength timeout) override;
+    ndk::ScopedAStatus prepareProcessTermination() override;
+
+    bool initialize();
+
+  private:
+    class MessageHandlerImpl : public ::android::MessageHandler {
+      public:
+        explicit MessageHandlerImpl(WatchdogClient* client);
+        void handleMessage(const ::android::Message& message) override;
+
+      private:
+        WatchdogClient* mClient;
+    };
+
+  private:
+    void respondToWatchdog();
+    bool isClientHealthy() const;
+
+  private:
+    ::android::sp<::android::Looper> mHandlerLooper;
+    ::android::sp<MessageHandlerImpl> mMessageHandler;
+    std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdog> mWatchdogServer;
+    std::shared_ptr<aidl::android::automotive::watchdog::ICarWatchdogClient> mTestClient;
+    VehicleHalManager* mVhalManager;
+    ::android::Mutex mMutex;
+    int mCurrentSessionId GUARDED_BY(mMutex);
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_WatchdogClient_H_
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index 393d3ec..b09e9bf 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -21,8 +21,14 @@
 #include <cmath>
 #include <fstream>
 
-#include <android/log.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
 #include <android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h>
+#include <android/log.h>
+
+#include <hwbinder/IPCThreadState.h>
+#include <private/android_filesystem_config.h>
+#include <utils/SystemClock.h>
 
 #include "VehicleUtils.h"
 
@@ -34,6 +40,10 @@
 
 using namespace std::placeholders;
 
+using ::android::base::EqualsIgnoreCase;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+
 constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10);
 
 const VehiclePropValue kEmptyValue{};
@@ -172,6 +182,251 @@
     return Void();
 }
 
+Return<void> VehicleHalManager::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds == 0) {
+        ALOGE("Invalid parameters passed to debug()");
+        return Void();
+    }
+
+    bool shouldContinue = mHal->dump(fd, options);
+    if (!shouldContinue) {
+        ALOGI("Dumped HAL only");
+        return Void();
+    }
+
+    // Do our dump
+    cmdDump(fd->data[0], options);
+    return Void();
+}
+
+void VehicleHalManager::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
+    if (options.size() == 0) {
+        cmdDumpAllProperties(fd);
+        return;
+    }
+    std::string option = options[0];
+    if (EqualsIgnoreCase(option, "--help")) {
+        cmdHelp(fd);
+    } else if (EqualsIgnoreCase(option, "--list")) {
+        cmdListAllProperties(fd);
+    } else if (EqualsIgnoreCase(option, "--get")) {
+        cmdDumpSpecificProperties(fd, options);
+    } else if (EqualsIgnoreCase(option, "--set")) {
+        cmdSetOneProperty(fd, options);
+    } else {
+        dprintf(fd, "Invalid option: %s\n", option.c_str());
+    }
+}
+
+bool VehicleHalManager::checkCallerHasWritePermissions(int fd) {
+    // Double check that's only called by root - it should be be blocked at the HIDL debug() level,
+    // but it doesn't hurt to make sure...
+    if (hardware::IPCThreadState::self()->getCallingUid() != AID_ROOT) {
+        dprintf(fd, "Must be root\n");
+        return false;
+    }
+    return true;
+}
+
+bool VehicleHalManager::checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options,
+                                           size_t minSize) {
+    size_t size = options.size();
+    if (size >= minSize) {
+        return true;
+    }
+    dprintf(fd, "Invalid number of arguments: required at least %zu, got %zu\n", minSize, size);
+    return false;
+}
+
+bool VehicleHalManager::safelyParseInt(int fd, int index, std::string s, int* out) {
+    if (!android::base::ParseInt(s, out)) {
+        dprintf(fd, "non-integer argument at index %d: %s\n", index, s.c_str());
+        return false;
+    }
+    return true;
+}
+
+void VehicleHalManager::cmdHelp(int fd) const {
+    dprintf(fd, "Usage: \n\n");
+    dprintf(fd, "[no args]: dumps (id and value) all supported properties \n");
+    dprintf(fd, "--help: shows this help\n");
+    dprintf(fd, "--list: lists the ids of all supported properties\n");
+    dprintf(fd, "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n");
+    // TODO: support other formats (int64, float, bytes)
+    dprintf(fd,
+            "--set <PROP> <i|s> <VALUE_1> [<i|s> <VALUE_N>] [a AREA_ID] : sets the value of "
+            "property PROP, using arbitrary number of key/value parameters (i for int32, "
+            "s for string) and an optional area.\n"
+            "Notice that the string value can be set just once, while the other can have multiple "
+            "values (so they're used in the respective array)\n");
+}
+
+void VehicleHalManager::cmdListAllProperties(int fd) const {
+    auto& halConfig = mConfigIndex->getAllConfigs();
+    size_t size = halConfig.size();
+    if (size == 0) {
+        dprintf(fd, "no properties to list\n");
+        return;
+    }
+    int i = 0;
+    dprintf(fd, "listing %zu properties\n", size);
+    for (const auto& config : halConfig) {
+        dprintf(fd, "%d: %d\n", ++i, config.prop);
+    }
+}
+
+void VehicleHalManager::cmdDumpAllProperties(int fd) {
+    auto& halConfig = mConfigIndex->getAllConfigs();
+    size_t size = halConfig.size();
+    if (size == 0) {
+        dprintf(fd, "no properties to dump\n");
+        return;
+    }
+    int rowNumber = 0;
+    dprintf(fd, "dumping %zu properties\n", size);
+    for (auto& config : halConfig) {
+        cmdDumpOneProperty(fd, ++rowNumber, config);
+    }
+}
+
+void VehicleHalManager::cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config) {
+    size_t numberAreas = config.areaConfigs.size();
+    if (numberAreas == 0) {
+        if (rowNumber > 0) {
+            dprintf(fd, "%d: ", rowNumber);
+        }
+        cmdDumpOneProperty(fd, config.prop, /* areaId= */ 0);
+        return;
+    }
+    for (size_t j = 0; j < numberAreas; ++j) {
+        if (rowNumber > 0) {
+            if (numberAreas > 1) {
+                dprintf(fd, "%d/%zu: ", rowNumber, j);
+            } else {
+                dprintf(fd, "%d: ", rowNumber);
+            }
+        }
+        cmdDumpOneProperty(fd, config.prop, config.areaConfigs[j].areaId);
+    }
+}
+
+void VehicleHalManager::cmdDumpSpecificProperties(int fd, const hidl_vec<hidl_string>& options) {
+    if (!checkArgumentsSize(fd, options, 2)) return;
+
+    // options[0] is the command itself...
+    int rowNumber = 0;
+    size_t size = options.size();
+    for (size_t i = 1; i < size; ++i) {
+        int prop;
+        if (!safelyParseInt(fd, i, options[i], &prop)) return;
+        const auto* config = getPropConfigOrNull(prop);
+        if (config == nullptr) {
+            dprintf(fd, "No property %d\n", prop);
+            continue;
+        }
+        if (size > 2) {
+            // Only show row number if there's more than 1
+            rowNumber++;
+        }
+        cmdDumpOneProperty(fd, rowNumber, *config);
+    }
+}
+
+void VehicleHalManager::cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId) {
+    VehiclePropValue input;
+    input.prop = prop;
+    input.areaId = areaId;
+    auto callback = [&](StatusCode status, const VehiclePropValue& output) {
+        if (status == StatusCode::OK) {
+            dprintf(fd, "%s\n", toString(output).c_str());
+        } else {
+            dprintf(fd, "Could not get property %d. Error: %s\n", prop, toString(status).c_str());
+        }
+    };
+    get(input, callback);
+}
+
+void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) {
+    if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return;
+
+    size_t size = options.size();
+
+    // Syntax is --set PROP Type1 Value1 TypeN ValueN, so number of arguments must be even
+    if (size % 2 != 0) {
+        dprintf(fd, "must pass even number of arguments (passed %zu)\n", size);
+        return;
+    }
+    int numberValues = (size - 2) / 2;
+
+    VehiclePropValue prop;
+    if (!safelyParseInt(fd, 1, options[1], &prop.prop)) return;
+    prop.timestamp = elapsedRealtimeNano();
+    prop.status = VehiclePropertyStatus::AVAILABLE;
+
+    // First pass: calculate sizes
+    int sizeInt32 = 0;
+    int stringIndex = 0;
+    int areaIndex = 0;
+    for (int i = 2, kv = 1; kv <= numberValues; kv++) {
+        // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step
+        std::string type = options[i];
+        std::string value = options[i + 1];
+        if (EqualsIgnoreCase(type, "i")) {
+            sizeInt32++;
+        } else if (EqualsIgnoreCase(type, "s")) {
+            if (stringIndex != 0) {
+                dprintf(fd,
+                        "defining string value (%s) again at index %d (already defined at %d=%s"
+                        ")\n",
+                        value.c_str(), i, stringIndex, options[stringIndex + 1].c_str());
+                return;
+            }
+            stringIndex = i;
+        } else if (EqualsIgnoreCase(type, "a")) {
+            if (areaIndex != 0) {
+                dprintf(fd,
+                        "defining area value (%s) again at index %d (already defined at %d=%s"
+                        ")\n",
+                        value.c_str(), i, areaIndex, options[areaIndex + 1].c_str());
+                return;
+            }
+            areaIndex = i;
+        } else {
+            dprintf(fd, "invalid (%s) type at index %d\n", type.c_str(), i);
+            return;
+        }
+        i += 2;
+    }
+    prop.value.int32Values.resize(sizeInt32);
+
+    // Second pass: populate it
+    int indexInt32 = 0;
+    for (int i = 2, kv = 1; kv <= numberValues; kv++) {
+        // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step
+        int valueIndex = i + 1;
+        std::string type = options[i];
+        std::string value = options[valueIndex];
+        if (EqualsIgnoreCase(type, "i")) {
+            int safeInt;
+            if (!safelyParseInt(fd, valueIndex, value, &safeInt)) return;
+            prop.value.int32Values[indexInt32++] = safeInt;
+        } else if (EqualsIgnoreCase(type, "s")) {
+            prop.value.stringValue = value;
+        } else if (EqualsIgnoreCase(type, "a")) {
+            if (!safelyParseInt(fd, valueIndex, value, &prop.areaId)) return;
+        }
+        i += 2;
+    }
+    ALOGD("Setting prop %s", toString(prop).c_str());
+    auto status = set(prop);
+    if (status == StatusCode::OK) {
+        dprintf(fd, "Set property %s\n", toString(prop).c_str());
+    } else {
+        dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(),
+                toString(status).c_str());
+    }
+}
+
 void VehicleHalManager::init() {
     ALOGI("VehicleHalManager::init");
 
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
index 40dd56e..0947c9f 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
@@ -131,7 +131,7 @@
         ALOGE("Discarding value for prop 0x%x because it contains "
                   "data that is not consistent with this pool. "
                   "Expected type: %d, vector size: %zu",
-              o->prop, mPropType, mVectorSize);
+              o->prop, toInt(mPropType), mVectorSize);
         delete o;
     } else {
         ObjectPool<VehiclePropValue>::recycle(o);
diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
index 94ace45..6087bfa 100644
--- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -50,12 +50,20 @@
     VehiclePropValue* valueToUpdate = const_cast<VehiclePropValue*>(getValueOrNullLocked(recId));
     if (valueToUpdate == nullptr) {
         mPropertyValues.insert({ recId, propValue });
-    } else {
-        valueToUpdate->timestamp = propValue.timestamp;
-        valueToUpdate->value = propValue.value;
-        if (updateStatus) {
-            valueToUpdate->status = propValue.status;
-        }
+        return true;
+    }
+
+    // propValue is outdated and drops it.
+    if (valueToUpdate->timestamp > propValue.timestamp) {
+        return false;
+    }
+    // update the propertyValue.
+    // The timestamp in propertyStore should only be updated by the server side. It indicates
+    // the time when the event is generated by the server.
+    valueToUpdate->timestamp = propValue.timestamp;
+    valueToUpdate->value = propValue.value;
+    if (updateStatus) {
+        valueToUpdate->status = propValue.status;
     }
     return true;
 }
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
index 5b6816e..c16b29a 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
@@ -52,7 +52,7 @@
         case VehiclePropertyType::MIXED:
             break; // Valid, but nothing to do.
         default:
-            ALOGE("createVehiclePropValue: unknown type: %d", type);
+            ALOGE("createVehiclePropValue: unknown type: %d", toInt(type));
             val.reset(nullptr);
     }
     return val;
@@ -78,13 +78,6 @@
     }
 }
 
-template<typename T>
-inline void copyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
-    for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) {
-        (*dest)[i] = src[i];
-    }
-}
-
 void copyVehicleRawValue(VehiclePropValue::RawValue* dest,
                          const VehiclePropValue::RawValue& src) {
     dest->int32Values = src.int32Values;
@@ -94,6 +87,15 @@
     dest->stringValue = src.stringValue;
 }
 
+#ifdef __ANDROID__
+
+template<typename T>
+inline void copyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
+    for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) {
+        (*dest)[i] = src[i];
+    }
+}
+
 template<typename T>
 void shallowCopyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
     if (src.size() > 0) {
@@ -123,6 +125,7 @@
     shallowCopyHidlStr(&dest->value.stringValue, src.value.stringValue);
 }
 
+#endif  // __ANDROID__
 
 //}  // namespace utils
 
diff --git a/automotive/vehicle/2.0/default/common/src/WatchdogClient.cpp b/automotive/vehicle/2.0/default/common/src/WatchdogClient.cpp
new file mode 100644
index 0000000..c067216
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/src/WatchdogClient.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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 "automotive.vehicle@2.0-watchdog"
+
+#include <common/include/vhal_v2_0/WatchdogClient.h>
+
+#include <android/binder_manager.h>
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+using aidl::android::automotive::watchdog::ICarWatchdog;
+using aidl::android::automotive::watchdog::TimeoutLength;
+
+namespace {
+
+enum { WHAT_CHECK_ALIVE = 1 };
+
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+WatchdogClient::WatchdogClient(const sp<Looper>& handlerLooper, VehicleHalManager* vhalManager)
+    : mHandlerLooper(handlerLooper), mVhalManager(vhalManager), mCurrentSessionId(-1) {
+    mMessageHandler = new MessageHandlerImpl(this);
+}
+
+ndk::ScopedAStatus WatchdogClient::checkIfAlive(int32_t sessionId, TimeoutLength /*timeout*/) {
+    mHandlerLooper->removeMessages(mMessageHandler, WHAT_CHECK_ALIVE);
+    {
+        Mutex::Autolock lock(mMutex);
+        mCurrentSessionId = sessionId;
+    }
+    mHandlerLooper->sendMessage(mMessageHandler, Message(WHAT_CHECK_ALIVE));
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WatchdogClient::prepareProcessTermination() {
+    return ndk::ScopedAStatus::ok();
+}
+
+bool WatchdogClient::initialize() {
+    ndk::SpAIBinder binder(
+            AServiceManager_getService("android.automotive.watchdog.ICarWatchdog/default"));
+    if (binder.get() == nullptr) {
+        ALOGE("Failed to get carwatchdog daemon");
+        return false;
+    }
+    std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder);
+    if (server == nullptr) {
+        ALOGE("Failed to connect to carwatchdog daemon");
+        return false;
+    }
+    mWatchdogServer = server;
+
+    binder = this->asBinder();
+    if (binder.get() == nullptr) {
+        ALOGE("Failed to get car watchdog client binder object");
+        return false;
+    }
+    std::shared_ptr<ICarWatchdogClient> client = ICarWatchdogClient::fromBinder(binder);
+    if (client == nullptr) {
+        ALOGE("Failed to get ICarWatchdogClient from binder");
+        return false;
+    }
+    mTestClient = client;
+    mWatchdogServer->registerClient(client, TimeoutLength::TIMEOUT_NORMAL);
+    ALOGI("Successfully registered the client to car watchdog server");
+    return true;
+}
+
+void WatchdogClient::respondToWatchdog() {
+    if (mWatchdogServer == nullptr) {
+        ALOGW("Cannot respond to car watchdog daemon: car watchdog daemon is not connected");
+        return;
+    }
+    int sessionId;
+    {
+        Mutex::Autolock lock(mMutex);
+        sessionId = mCurrentSessionId;
+    }
+    if (isClientHealthy()) {
+        ndk::ScopedAStatus status = mWatchdogServer->tellClientAlive(mTestClient, sessionId);
+        if (!status.isOk()) {
+            ALOGE("Failed to call tellClientAlive(session id = %d): %d", sessionId,
+                  status.getStatus());
+            return;
+        }
+    }
+}
+
+bool WatchdogClient::isClientHealthy() const {
+    // We consider that default vehicle HAL is healthy if we can get PERF_VEHICLE_SPEED value.
+    StatusCode status = StatusCode::TRY_AGAIN;
+    VehiclePropValue propValue = {.prop = (int32_t)VehicleProperty::PERF_VEHICLE_SPEED};
+    while (status == StatusCode::TRY_AGAIN) {
+        mVhalManager->get(propValue,
+                          [&propValue, &status](StatusCode s, const VehiclePropValue& v) {
+                              status = s;
+                              if (s == StatusCode::OK) {
+                                  propValue = v;
+                              }
+                          });
+    }
+    return status == StatusCode::OK;
+}
+
+WatchdogClient::MessageHandlerImpl::MessageHandlerImpl(WatchdogClient* client) : mClient(client) {}
+
+void WatchdogClient::MessageHandlerImpl::handleMessage(const Message& message) {
+    switch (message.what) {
+        case WHAT_CHECK_ALIVE:
+            mClient->respondToWatchdog();
+            break;
+        default:
+            ALOGW("Unknown message: %d", message.what);
+    }
+}
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
index bf1de81..136b2e0 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
@@ -41,7 +41,7 @@
     }
 }
 
-void CommConn::sendMessage(emulator::EmulatorMessage const& msg) {
+void CommConn::sendMessage(vhal_proto::EmulatorMessage const& msg) {
     int numBytes = msg.ByteSize();
     std::vector<uint8_t> buffer(static_cast<size_t>(numBytes));
     if (!msg.SerializeToArray(buffer.data(), numBytes)) {
@@ -61,9 +61,9 @@
             break;
         }
 
-        emulator::EmulatorMessage rxMsg;
+        vhal_proto::EmulatorMessage rxMsg;
         if (rxMsg.ParseFromArray(buffer.data(), static_cast<int32_t>(buffer.size()))) {
-            emulator::EmulatorMessage respMsg;
+            vhal_proto::EmulatorMessage respMsg;
             mMessageProcessor->processMessage(rxMsg, respMsg);
 
             sendMessage(respMsg);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
index 87b0dfc..6d36da4 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
@@ -44,8 +44,8 @@
      * Process a single message received over a CommConn. Populate the given respMsg with the reply
      * message we should send.
      */
-    virtual void processMessage(emulator::EmulatorMessage const& rxMsg,
-                                emulator::EmulatorMessage& respMsg) = 0;
+    virtual void processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+                                vhal_proto::EmulatorMessage& respMsg) = 0;
 };
 
 /**
@@ -93,7 +93,7 @@
     /**
      * Serialized and send the given message to the other side.
      */
-    void sendMessage(emulator::EmulatorMessage const& msg);
+    void sendMessage(vhal_proto::EmulatorMessage const& msg);
 
    protected:
     std::unique_ptr<std::thread> mReadThread;
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 3070171..16c33b9 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
@@ -17,9 +17,11 @@
 #ifndef android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
 #define android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
 
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <android/hardware/automotive/vehicle/2.0/types.h>
 #include <vhal_v2_0/VehicleUtils.h>
 
+#include <map>
+
 namespace android {
 namespace hardware {
 namespace automotive {
@@ -70,6 +72,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;
@@ -85,6 +88,34 @@
     0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
 
 /**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * For example: Mocking hard button press triggering a HVAC fan speed change.
+ * Android set kSetPropertyFromVehicleForTest with an array of integer {HVAC_FAN_SPEED, value of
+ * fan speed} and a long value indicates the timestamp of the events .
+ * It only works with integer type properties.
+ */
+const int32_t kSetIntPropertyFromVehicleForTest =
+        0x1112 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * It only works with float type properties.
+ */
+const int32_t kSetFloatPropertyFromVehicleForTest =
+        0x1113 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * It only works with boolean type properties.
+ */
+const int32_t kSetBooleanPropertyFromVehicleForTest =
+        0x1114 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+
+/**
+ * This property is used for test purpose. End to end tests use this property to test set and get
+ * method for MIXED type properties.
+ */
+const int32_t kMixedTypePropertyForTest =
+        0x1111 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
  * FakeDataCommand enum defines the supported command type for kGenerateFakeDataControllingProperty.
  * All those commands can be send independently with each other. And each will override the one sent
  * previously.
@@ -167,7 +198,6 @@
                          .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.floatValues = {15000.0f}}},
 
@@ -177,14 +207,13 @@
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
                  },
-         .initialValue = {.int32Values = {1}}},
+         .initialValue = {.int32Values = {(int)FuelType::FUEL_TYPE_UNLEADED}}},
 
         {.config =
                  {
                          .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.floatValues = {150000.0f}}},
 
@@ -194,14 +223,13 @@
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
                  },
-         .initialValue = {.int32Values = {1}}},
+         .initialValue = {.int32Values = {(int)EvConnectorType::IEC_TYPE_1_AC}}},
 
         {.config =
                  {
                          .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {SEAT_1_LEFT}}},
 
@@ -210,7 +238,6 @@
                          .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}},
 
@@ -219,12 +246,19 @@
                          .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}},
 
         {.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,
@@ -232,6 +266,13 @@
          .initialValue = {.stringValue = "Toy Vehicle"}},
         {.config =
                  {
+                         .prop = toInt(VehicleProperty::INFO_EXTERIOR_DIMENSIONS),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                 },
+         .initialValue = {.floatValues = {1776, 4950, 2008, 2140, 2984, 1665, 1667, 11800}}},
+        {.config =
+                 {
                          .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
@@ -265,10 +306,29 @@
                  {
                          .prop = toInt(VehicleProperty::PERF_ODOMETER),
                          .access = VehiclePropertyAccess::READ,
-                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .minSampleRate = 0.0f,
+                         .maxSampleRate = 10.0f,
                  },
          .initialValue = {.floatValues = {0.0f}}},
-
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::PERF_STEERING_ANGLE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .minSampleRate = 0.0f,
+                         .maxSampleRate = 10.0f,
+                 },
+         .initialValue = {.floatValues = {0.0f}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::PERF_REAR_STEERING_ANGLE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .minSampleRate = 0.0f,
+                         .maxSampleRate = 10.0f,
+                 },
+         .initialValue = {.floatValues = {0.0f}}},
         {
                 .config =
                         {
@@ -285,8 +345,9 @@
                  {
                          .prop = toInt(VehicleProperty::FUEL_LEVEL),
                          .access = VehiclePropertyAccess::READ,
-                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .minSampleRate = 0.0f,
+                         .maxSampleRate = 100.0f,
                  },
          .initialValue = {.floatValues = {15000.0f}}},
 
@@ -295,7 +356,6 @@
                          .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
                          .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {0}}},
 
@@ -303,8 +363,9 @@
                  {
                          .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
                          .access = VehiclePropertyAccess::READ,
-                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .minSampleRate = 0.0f,
+                         .maxSampleRate = 100.0f,
                  },
          .initialValue = {.floatValues = {150000.0f}}},
 
@@ -313,7 +374,6 @@
                          .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN),
                          .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {0}}},
 
@@ -322,7 +382,6 @@
                          .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {0}}},
 
@@ -330,17 +389,17 @@
                  {
                          .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE),
                          .access = VehiclePropertyAccess::READ,
-                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .minSampleRate = 1.0f,
+                         .maxSampleRate = 10.0f,
                  },
          .initialValue = {.floatValues = {0.0f}}},
 
         {.config =
                  {
                          .prop = toInt(VehicleProperty::RANGE_REMAINING),
-                         .access = VehiclePropertyAccess::READ,
+                         .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                          .minSampleRate = 1.0f,
                          .maxSampleRate = 2.0f,
                  },
@@ -374,7 +433,17 @@
                          .minSampleRate = 1.0f,
                          .maxSampleRate = 2.0f,
                  },
-         .initialValue = {.floatValues = {200}}},  // units in kPa
+         .initialValue = {.floatValues = {200.0f}}},  // units in kPa
+
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::TIRE_PRESSURE_DISPLAY_UNITS),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .configArray = {(int)VehicleUnit::KILOPASCAL, (int)VehicleUnit::PSI,
+                                         (int)VehicleUnit::BAR},
+                 },
+         .initialValue = {.int32Values = {toInt(VehicleUnit::PSI)}}},
 
         {.config =
                  {
@@ -397,7 +466,6 @@
                          .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {0}}},
 
@@ -409,6 +477,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,
@@ -430,6 +506,17 @@
                                             .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
                 .initialValue = {.int32Values = {0}}  // Will be used for all areas.
         },
+        {
+                .config = {.prop = toInt(VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON),
+                           .access = VehiclePropertyAccess::READ_WRITE,
+                           .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                           .areaConfigs =
+                                   {VehicleAreaConfig{
+                                            .areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
+                                    VehicleAreaConfig{
+                                            .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
+                .initialValue = {.int32Values = {0}}  // Will be used for all areas.
+        },
 
         {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
                     .access = VehiclePropertyAccess::READ_WRITE,
@@ -558,14 +645,10 @@
                  },
          .initialValue = {.floatValues = {25.0f}}},
 
-        {.config =
-                 {
-                         .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS),
-                         .access = VehiclePropertyAccess::READ_WRITE,
-                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-                         .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS},
-                 },
+        {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}},
          .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}},
 
         {.config =
@@ -573,8 +656,8 @@
                          .prop = toInt(VehicleProperty::DISTANCE_DISPLAY_UNITS),
                          .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                          .configArray = {(int)VehicleUnit::KILOMETER, (int)VehicleUnit::MILE},
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}
                  },
          .initialValue = {.int32Values = {(int)VehicleUnit::MILE}}},
 
@@ -596,6 +679,14 @@
 
         {.config =
                  {
+                         .prop = toInt(VehicleProperty::TURN_SIGNAL_STATE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.int32Values = {toInt(VehicleTurnSignal::NONE)}}},
+
+        {.config =
+                 {
                          .prop = toInt(VehicleProperty::IGNITION_STATE),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -626,6 +717,50 @@
                                 .prop = kGenerateFakeDataControllingProperty,
                                 .access = VehiclePropertyAccess::WRITE,
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {1, 0, 0, 2, 0, 0, 0, 0, 0},
+                        },
+        },
+
+        {
+                .config =
+                        {
+                                .prop = kSetIntPropertyFromVehicleForTest,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {0, 0, 0, 2, 1, 0, 0, 0, 0},
+                        },
+        },
+
+        {
+                .config =
+                        {
+                                .prop = kSetFloatPropertyFromVehicleForTest,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {0, 0, 1, 0, 1, 0, 1, 0, 0},
+                        },
+        },
+
+        {
+                .config =
+                        {
+                                .prop = kSetBooleanPropertyFromVehicleForTest,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {0, 1, 1, 0, 1, 0, 0, 0, 0},
+                        },
+        },
+
+        {
+                .config = {.prop = kMixedTypePropertyForTest,
+                           .access = VehiclePropertyAccess::READ_WRITE,
+                           .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                           .configArray = {1, 1, 0, 2, 0, 0, 1, 0, 0}},
+                .initialValue =
+                        {
+                                .int32Values = {1 /* indicate TRUE boolean value */, 2, 3},
+                                .floatValues = {4.5f},
+                                .stringValue = "MIXED property",
                         },
         },
 
@@ -757,7 +892,6 @@
                          .prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
 
@@ -766,7 +900,6 @@
                          .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
 
@@ -775,7 +908,6 @@
                          .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
 
@@ -784,7 +916,6 @@
                          .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
 
@@ -793,7 +924,6 @@
                          .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH),
                          .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
 
@@ -802,7 +932,6 @@
                          .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH),
                          .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
 
@@ -811,7 +940,6 @@
                          .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH),
                          .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
 
@@ -820,7 +948,6 @@
                          .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH),
                          .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
 
@@ -874,6 +1001,65 @@
                     .access = VehiclePropertyAccess::READ_WRITE,
                     .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
          .initialValue = {.stringValue = "Vendor String Property"}},
+
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .configArray =
+                                 {kMixedTypePropertyForTest,
+                                  (int)VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_INFO,
+                                  (int)VehicleVendorPermission::PERMISSION_SET_VENDOR_CATEGORY_INFO,
+                                  VENDOR_EXTENSION_INT_PROPERTY,
+                                  (int)VehicleVendorPermission::PERMISSION_GET_VENDOR_CATEGORY_SEAT,
+                                  (int)VehicleVendorPermission::PERMISSION_NOT_ACCESSIBLE,
+                                  VENDOR_EXTENSION_FLOAT_PROPERTY,
+                                  (int)VehicleVendorPermission::PERMISSION_DEFAULT,
+                                  (int)VehicleVendorPermission::PERMISSION_DEFAULT},
+                 },
+         .initialValue = {.int32Values = {1}}},
+
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
+                                .access = VehiclePropertyAccess::READ_WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::SWITCH_USER),
+                                .access = VehiclePropertyAccess::READ_WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::CREATE_USER),
+                                .access = VehiclePropertyAccess::READ_WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::REMOVE_USER),
+                                .access = VehiclePropertyAccess::READ_WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION),
+                                .access = VehiclePropertyAccess::READ_WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
new file mode 100644
index 0000000..ea38cb3
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
@@ -0,0 +1,338 @@
+/*
+ * 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 "EmulatedUserHal"
+
+#include <cutils/log.h>
+#include <utils/SystemClock.h>
+
+#include "EmulatedUserHal.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+constexpr int INITIAL_USER_INFO = static_cast<int>(VehicleProperty::INITIAL_USER_INFO);
+constexpr int SWITCH_USER = static_cast<int>(VehicleProperty::SWITCH_USER);
+constexpr int CREATE_USER = static_cast<int>(VehicleProperty::CREATE_USER);
+constexpr int REMOVE_USER = static_cast<int>(VehicleProperty::REMOVE_USER);
+constexpr int USER_IDENTIFICATION_ASSOCIATION =
+        static_cast<int>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
+
+bool EmulatedUserHal::isSupported(int32_t prop) {
+    switch (prop) {
+        case INITIAL_USER_INFO:
+        case SWITCH_USER:
+        case CREATE_USER:
+        case REMOVE_USER:
+        case USER_IDENTIFICATION_ASSOCIATION:
+            return true;
+        default:
+            return false;
+    }
+}
+
+android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetProperty(
+        const VehiclePropValue& value) {
+    ALOGV("onSetProperty(): %s", toString(value).c_str());
+
+    switch (value.prop) {
+        case INITIAL_USER_INFO:
+            return onSetInitialUserInfoResponse(value);
+        case SWITCH_USER:
+            return onSetSwitchUserResponse(value);
+        case CREATE_USER:
+            return onSetCreateUserResponse(value);
+        case REMOVE_USER:
+            ALOGI("REMOVE_USER is FYI only, nothing to do...");
+            return {};
+        case USER_IDENTIFICATION_ASSOCIATION:
+            return onSetUserIdentificationAssociation(value);
+        default:
+            return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+                   << "Unsupported property: " << toString(value);
+    }
+}
+
+android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onGetProperty(
+        const VehiclePropValue& value) {
+    ALOGV("onGetProperty(%s)", toString(value).c_str());
+    switch (value.prop) {
+        case INITIAL_USER_INFO:
+        case SWITCH_USER:
+        case CREATE_USER:
+        case REMOVE_USER:
+            ALOGE("onGetProperty(): %d is only supported on SET", value.prop);
+            return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+                   << "only supported on SET";
+        case USER_IDENTIFICATION_ASSOCIATION:
+            return onGetUserIdentificationAssociation(value);
+        default:
+            ALOGE("onGetProperty(): %d is not supported", value.prop);
+            return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+                   << "not supported by User HAL";
+    }
+}
+
+android::base::Result<std::unique_ptr<VehiclePropValue>>
+EmulatedUserHal::onGetUserIdentificationAssociation(const VehiclePropValue& value) {
+    if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
+        ALOGI("get(USER_IDENTIFICATION_ASSOCIATION): returning %s",
+              toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
+        auto newValue = std::unique_ptr<VehiclePropValue>(
+                new VehiclePropValue(*mSetUserIdentificationAssociationResponseFromCmd));
+        // Must use the same requestId
+        if (value.value.int32Values.size() > 0) {
+            newValue->value.int32Values[0] = value.value.int32Values[0];
+        } else {
+            ALOGE("get(USER_IDENTIFICATION_ASSOCIATION): no requestId on %s",
+                  toString(value).c_str());
+        }
+        return newValue;
+    }
+    return defaultUserIdentificationAssociation(value);
+}
+
+android::base::Result<std::unique_ptr<VehiclePropValue>>
+EmulatedUserHal::onSetInitialUserInfoResponse(const VehiclePropValue& value) {
+    if (value.value.int32Values.size() == 0) {
+        ALOGE("set(INITIAL_USER_INFO): no int32values, ignoring it: %s", toString(value).c_str());
+        return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+               << "no int32values on " << toString(value);
+    }
+
+    if (value.areaId != 0) {
+        ALOGD("set(INITIAL_USER_INFO) called from lshal; storing it: %s", toString(value).c_str());
+        mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
+        return {};
+    }
+
+    ALOGD("set(INITIAL_USER_INFO) called from Android: %s", toString(value).c_str());
+
+    int32_t requestId = value.value.int32Values[0];
+    if (mInitialUserResponseFromCmd != nullptr) {
+        ALOGI("replying INITIAL_USER_INFO with lshal value:  %s",
+              toString(*mInitialUserResponseFromCmd).c_str());
+        return sendUserHalResponse(std::move(mInitialUserResponseFromCmd), requestId);
+    }
+
+    // Returns default response
+    auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
+    updatedValue->prop = INITIAL_USER_INFO;
+    updatedValue->timestamp = elapsedRealtimeNano();
+    updatedValue->value.int32Values.resize(2);
+    updatedValue->value.int32Values[0] = requestId;
+    updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;
+
+    ALOGI("no lshal response; replying with InitialUserInfoResponseAction::DEFAULT: %s",
+          toString(*updatedValue).c_str());
+
+    return updatedValue;
+}
+
+android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetSwitchUserResponse(
+        const VehiclePropValue& value) {
+    if (value.value.int32Values.size() == 0) {
+        ALOGE("set(SWITCH_USER): no int32values, ignoring it: %s", toString(value).c_str());
+        return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+               << "no int32values on " << toString(value);
+    }
+
+    if (value.areaId != 0) {
+        ALOGD("set(SWITCH_USER) called from lshal; storing it: %s", toString(value).c_str());
+        mSwitchUserResponseFromCmd.reset(new VehiclePropValue(value));
+        return {};
+    }
+    ALOGD("set(SWITCH_USER) called from Android: %s", toString(value).c_str());
+
+    int32_t requestId = value.value.int32Values[0];
+    if (mSwitchUserResponseFromCmd != nullptr) {
+        ALOGI("replying SWITCH_USER with lshal value:  %s",
+              toString(*mSwitchUserResponseFromCmd).c_str());
+        return sendUserHalResponse(std::move(mSwitchUserResponseFromCmd), requestId);
+    }
+
+    if (value.value.int32Values.size() > 1) {
+        auto messageType = static_cast<SwitchUserMessageType>(value.value.int32Values[1]);
+        switch (messageType) {
+            case SwitchUserMessageType::LEGACY_ANDROID_SWITCH:
+                ALOGI("request is LEGACY_ANDROID_SWITCH; ignoring it");
+                return {};
+            case SwitchUserMessageType::ANDROID_POST_SWITCH:
+                ALOGI("request is ANDROID_POST_SWITCH; ignoring it");
+                return {};
+            default:
+                break;
+        }
+    }
+
+    // Returns default response
+    auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
+    updatedValue->prop = SWITCH_USER;
+    updatedValue->timestamp = elapsedRealtimeNano();
+    updatedValue->value.int32Values.resize(3);
+    updatedValue->value.int32Values[0] = requestId;
+    updatedValue->value.int32Values[1] = (int32_t)SwitchUserMessageType::VEHICLE_RESPONSE;
+    updatedValue->value.int32Values[2] = (int32_t)SwitchUserStatus::SUCCESS;
+
+    ALOGI("no lshal response; replying with VEHICLE_RESPONSE / SUCCESS: %s",
+          toString(*updatedValue).c_str());
+
+    return updatedValue;
+}
+
+android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetCreateUserResponse(
+        const VehiclePropValue& value) {
+    if (value.value.int32Values.size() == 0) {
+        ALOGE("set(CREATE_USER): no int32values, ignoring it: %s", toString(value).c_str());
+        return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+               << "no int32values on " << toString(value);
+    }
+
+    if (value.areaId != 0) {
+        ALOGD("set(CREATE_USER) called from lshal; storing it: %s", toString(value).c_str());
+        mCreateUserResponseFromCmd.reset(new VehiclePropValue(value));
+        return {};
+    }
+    ALOGD("set(CREATE_USER) called from Android: %s", toString(value).c_str());
+
+    int32_t requestId = value.value.int32Values[0];
+    if (mCreateUserResponseFromCmd != nullptr) {
+        ALOGI("replying CREATE_USER with lshal value:  %s",
+              toString(*mCreateUserResponseFromCmd).c_str());
+        return sendUserHalResponse(std::move(mCreateUserResponseFromCmd), requestId);
+    }
+
+    // Returns default response
+    auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
+    updatedValue->prop = CREATE_USER;
+    updatedValue->timestamp = elapsedRealtimeNano();
+    updatedValue->value.int32Values.resize(2);
+    updatedValue->value.int32Values[0] = requestId;
+    updatedValue->value.int32Values[1] = (int32_t)CreateUserStatus::SUCCESS;
+
+    ALOGI("no lshal response; replying with SUCCESS: %s", toString(*updatedValue).c_str());
+
+    return updatedValue;
+}
+
+android::base::Result<std::unique_ptr<VehiclePropValue>>
+EmulatedUserHal::onSetUserIdentificationAssociation(const VehiclePropValue& value) {
+    if (value.value.int32Values.size() == 0) {
+        ALOGE("set(USER_IDENTIFICATION_ASSOCIATION): no int32values, ignoring it: %s",
+              toString(value).c_str());
+        return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
+               << "no int32values on " << toString(value);
+    }
+
+    if (value.areaId != 0) {
+        ALOGD("set(USER_IDENTIFICATION_ASSOCIATION) called from lshal; storing it: %s",
+              toString(value).c_str());
+        mSetUserIdentificationAssociationResponseFromCmd.reset(new VehiclePropValue(value));
+        return {};
+    }
+    ALOGD("set(USER_IDENTIFICATION_ASSOCIATION) called from Android: %s", toString(value).c_str());
+
+    int32_t requestId = value.value.int32Values[0];
+    if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
+        ALOGI("replying USER_IDENTIFICATION_ASSOCIATION with lshal value:  %s",
+              toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
+        // Not moving response so it can be used on GET requests
+        auto copy = std::unique_ptr<VehiclePropValue>(
+                new VehiclePropValue(*mSetUserIdentificationAssociationResponseFromCmd));
+        return sendUserHalResponse(std::move(copy), requestId);
+    }
+
+    // Returns default response
+    return defaultUserIdentificationAssociation(value);
+}
+
+android::base::Result<std::unique_ptr<VehiclePropValue>>
+EmulatedUserHal::defaultUserIdentificationAssociation(const VehiclePropValue& request) {
+    // TODO(b/159498909): return a response with NOT_ASSOCIATED_ANY_USER for all requested types
+    ALOGE("no lshal response for %s; replying with NOT_AVAILABLE", toString(request).c_str());
+    return android::base::Error(static_cast<int>(StatusCode::NOT_AVAILABLE)) << "not set by lshal";
+}
+
+android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::sendUserHalResponse(
+        std::unique_ptr<VehiclePropValue> response, int32_t requestId) {
+    switch (response->areaId) {
+        case 1:
+            ALOGD("returning response with right request id");
+            response->value.int32Values[0] = requestId;
+            break;
+        case 2:
+            ALOGD("returning response with wrong request id");
+            response->value.int32Values[0] = -requestId;
+            break;
+        case 3:
+            ALOGD("not generating a property change event because of lshal prop: %s",
+                  toString(*response).c_str());
+            return android::base::Error(static_cast<int>(StatusCode::NOT_AVAILABLE))
+                   << "not generating a property change event because of lshal prop: "
+                   << toString(*response);
+        default:
+            ALOGE("invalid action on lshal response: %s", toString(*response).c_str());
+            return android::base::Error(static_cast<int>(StatusCode::INTERNAL_ERROR))
+                   << "invalid action on lshal response: " << toString(*response);
+    }
+
+    ALOGD("updating property to: %s", toString(*response).c_str());
+
+    return response;
+}
+
+void EmulatedUserHal::showDumpHelp(int fd) {
+    dprintf(fd, "%s: dumps state used for user management\n", kUserHalDumpOption);
+}
+
+void EmulatedUserHal::dump(int fd, std::string indent) {
+    if (mInitialUserResponseFromCmd != nullptr) {
+        dprintf(fd, "%sInitialUserInfo response: %s\n", indent.c_str(),
+                toString(*mInitialUserResponseFromCmd).c_str());
+    } else {
+        dprintf(fd, "%sNo InitialUserInfo response\n", indent.c_str());
+    }
+    if (mSwitchUserResponseFromCmd != nullptr) {
+        dprintf(fd, "%sSwitchUser response: %s\n", indent.c_str(),
+                toString(*mSwitchUserResponseFromCmd).c_str());
+    } else {
+        dprintf(fd, "%sNo SwitchUser response\n", indent.c_str());
+    }
+    if (mCreateUserResponseFromCmd != nullptr) {
+        dprintf(fd, "%sCreateUser response: %s\n", indent.c_str(),
+                toString(*mCreateUserResponseFromCmd).c_str());
+    } else {
+        dprintf(fd, "%sNo CreateUser response\n", indent.c_str());
+    }
+    if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
+        dprintf(fd, "%sSetUserIdentificationAssociation response: %s\n", indent.c_str(),
+                toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
+    } else {
+        dprintf(fd, "%sNo SetUserIdentificationAssociation response\n", indent.c_str());
+    }
+}
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h
new file mode 100644
index 0000000..db2f117
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h
@@ -0,0 +1,151 @@
+/*
+ * 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_automotive_vehicle_V2_0_impl_EmulatedUserHal_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedUserHal_H_
+
+#include <android-base/result.h>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+constexpr char kUserHalDumpOption[] = "--user-hal";
+
+/**
+ * Class used to emulate User HAL behavior through lshal debug requests.
+ */
+class EmulatedUserHal {
+  public:
+    EmulatedUserHal() {}
+
+    ~EmulatedUserHal() = default;
+
+    /**
+     * Checks if the emulator can handle the property.
+     */
+    bool isSupported(int32_t prop);
+
+    /**
+     * Lets the emulator set the property.
+     *
+     * @return updated property and StatusCode
+     */
+    android::base::Result<std::unique_ptr<VehiclePropValue>> onSetProperty(
+            const VehiclePropValue& value);
+
+    /**
+     * Gets the property value from the emulator.
+     *
+     * @return property value and StatusCode
+     */
+    android::base::Result<std::unique_ptr<VehiclePropValue>> onGetProperty(
+            const VehiclePropValue& value);
+
+    /**
+     * Shows the User HAL emulation help.
+     */
+    void showDumpHelp(int fd);
+
+    /**
+     * Dump its contents.
+     */
+    void dump(int fd, std::string indent);
+
+  private:
+    /**
+     * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change
+     * indicating what the initial user should be.
+     *
+     * During normal circumstances, the emulator will reply right away, passing a response if
+     * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which
+     * user to boot).
+     *
+     * But during development / testing, the behavior can be changed using lshal dump, which must
+     * use the areaId to indicate what should happen next.
+     *
+     * So, the behavior of set(INITIAL_USER_INFO) is:
+     *
+     * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called
+     * by lshal).
+     * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id
+     * and InitialUserInfoResponseAction::DEFAULT
+     * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd:
+     * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id
+     * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can
+     * test this error scenario)
+     * - if it's 3, then don't send a property change (so Android can emulate a timeout)
+     *
+     */
+    android::base::Result<std::unique_ptr<VehiclePropValue>> onSetInitialUserInfoResponse(
+            const VehiclePropValue& value);
+
+    /**
+     * Used to emulate SWITCH_USER - see onSetInitialUserInfoResponse() for usage.
+     */
+    android::base::Result<std::unique_ptr<VehiclePropValue>> onSetSwitchUserResponse(
+            const VehiclePropValue& value);
+
+    /**
+     * Used to emulate CREATE_USER - see onSetInitialUserInfoResponse() for usage.
+     */
+    android::base::Result<std::unique_ptr<VehiclePropValue>> onSetCreateUserResponse(
+            const VehiclePropValue& value);
+
+    /**
+     * Used to emulate set USER_IDENTIFICATION_ASSOCIATION - see onSetInitialUserInfoResponse() for
+     * usage.
+     */
+    android::base::Result<std::unique_ptr<VehiclePropValue>> onSetUserIdentificationAssociation(
+            const VehiclePropValue& value);
+
+    /**
+     * Used to emulate get USER_IDENTIFICATION_ASSOCIATION - see onSetInitialUserInfoResponse() for
+     * usage.
+     */
+    android::base::Result<std::unique_ptr<VehiclePropValue>> onGetUserIdentificationAssociation(
+            const VehiclePropValue& value);
+
+    /**
+     * Creates a default USER_IDENTIFICATION_ASSOCIATION when it was not set by lshal.
+     */
+    android::base::Result<std::unique_ptr<VehiclePropValue>> defaultUserIdentificationAssociation(
+            const VehiclePropValue& request);
+
+    android::base::Result<std::unique_ptr<VehiclePropValue>> sendUserHalResponse(
+            std::unique_ptr<VehiclePropValue> response, int32_t requestId);
+
+    std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
+    std::unique_ptr<VehiclePropValue> mSwitchUserResponseFromCmd;
+    std::unique_ptr<VehiclePropValue> mCreateUserResponseFromCmd;
+    std::unique_ptr<VehiclePropValue> mSetUserIdentificationAssociationResponseFromCmd;
+};
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_EmulatedUserHal_H_
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
new file mode 100644
index 0000000..7f9362f
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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 "automotive.vehicle@2.0-connector"
+
+#include <fstream>
+
+#include <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "DefaultConfig.h"
+#include "EmulatedVehicleConnector.h"
+#include "JsonFakeValueGenerator.h"
+#include "LinearFakeValueGenerator.h"
+#include "Obd2SensorStore.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+class EmulatedPassthroughConnector : public PassthroughConnector {
+  public:
+    bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
+};
+
+bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle,
+                                          const hidl_vec<hidl_string>& options) {
+    int fd = handle->data[0];
+
+    if (options.size() > 0) {
+        if (options[0] == "--help") {
+            dprintf(fd, "Emulator-specific usage:\n");
+            mEmulatedUserHal.showDumpHelp(fd);
+            dprintf(fd, "\n");
+            // Include caller's help options
+            return true;
+        } else if (options[0] == kUserHalDumpOption) {
+            mEmulatedUserHal.dump(fd, "");
+            return false;
+
+        } else {
+            // Let caller handle the options...
+            return true;
+        }
+    }
+
+    dprintf(fd, "Emulator-specific state:\n");
+    mEmulatedUserHal.dump(fd, "  ");
+    dprintf(fd, "\n");
+
+    return true;
+}
+
+PassthroughConnectorPtr makeEmulatedPassthroughConnector() {
+    return std::make_unique<EmulatedPassthroughConnector>();
+}
+
+}  // 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/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
new file mode 100644
index 0000000..57cbb8b
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
@@ -0,0 +1,46 @@
+/*
+ * 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_EmulatedVehicleConnector_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
+
+#include <vhal_v2_0/VehicleConnector.h>
+
+#include "VehicleHalClient.h"
+#include "VehicleHalServer.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+using PassthroughConnector = IPassThroughConnector<VehicleHalClient, VehicleHalServer>;
+using PassthroughConnectorPtr = std::unique_ptr<PassthroughConnector>;
+
+PassthroughConnectorPtr makeEmulatedPassthroughConnector();
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 9b687ec..a0b566d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -16,8 +16,12 @@
 #define LOG_TAG "DefaultVehicleHal_v2_0"
 
 #include <android-base/macros.h>
+#include <android-base/properties.h>
 #include <android/log.h>
+#include <dirent.h>
 #include <sys/system_properties.h>
+#include <fstream>
+#include <regex>
 
 #include "EmulatedVehicleHal.h"
 #include "JsonFakeValueGenerator.h"
@@ -88,22 +92,52 @@
     return sensorStore;
 }
 
-EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
+EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client,
+                                       EmulatedUserHal* emulatedUserHal)
     : mPropStore(propStore),
       mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
-      mRecurrentTimer(
-          std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
-      mGeneratorHub(
-          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) {
+      mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this,
+                                std::placeholders::_1)),
+      mVehicleClient(client),
+      mEmulatedUserHal(emulatedUserHal) {
     initStaticConfig();
     for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
         mPropStore->registerProperty(kVehicleProperties[i].config);
     }
+    mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue,
+                                                            this, std::placeholders::_1,
+                                                            std::placeholders::_2));
+
+    mInitVhalValueOverride =
+            android::base::GetBoolProperty("persist.vendor.vhal_init_value_override", false);
+    if (mInitVhalValueOverride) {
+        getAllPropertiesOverride();
+    }
+}
+
+void EmulatedVehicleHal::getAllPropertiesOverride() {
+    if (auto dir = opendir("/vendor/etc/vhaloverride/")) {
+        std::regex reg_json(".*[.]json", std::regex::icase);
+        while (auto f = readdir(dir)) {
+            if (!regex_match(f->d_name, reg_json)) {
+                continue;
+            }
+            std::string file = "/vendor/etc/vhaloverride/" + std::string(f->d_name);
+            JsonFakeValueGenerator tmpGenerator(file);
+
+            std::vector<VehiclePropValue> propvalues = tmpGenerator.getAllEvents();
+            mVehiclePropertiesOverride.insert(std::end(mVehiclePropertiesOverride),
+                                              std::begin(propvalues), std::end(propvalues));
+        }
+        closedir(dir);
+    }
 }
 
 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
         const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
     auto propId = requestedPropValue.prop;
+    ALOGV("get(%d)", propId);
+
     auto& pool = *getValuePool();
     VehiclePropValuePtr v = nullptr;
 
@@ -117,6 +151,26 @@
             *outStatus = fillObd2DtcInfo(v.get());
             break;
         default:
+            if (mEmulatedUserHal != nullptr && mEmulatedUserHal->isSupported(propId)) {
+                ALOGI("get(): getting value for prop %d from User HAL", propId);
+                const auto& ret = mEmulatedUserHal->onGetProperty(requestedPropValue);
+                if (!ret.ok()) {
+                    ALOGE("get(): User HAL returned error: %s", ret.error().message().c_str());
+                    *outStatus = StatusCode(ret.error().code());
+                } else {
+                    auto value = ret.value().get();
+                    if (value != nullptr) {
+                        ALOGI("get(): User HAL returned value: %s", toString(*value).c_str());
+                        v = getValuePool()->obtain(*value);
+                        *outStatus = StatusCode::OK;
+                    } else {
+                        ALOGE("get(): User HAL returned null value");
+                        *outStatus = StatusCode::INTERNAL_ERROR;
+                    }
+                }
+                break;
+            }
+
             auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
             if (internalPropValue != nullptr) {
                 v = getValuePool()->obtain(*internalPropValue);
@@ -125,18 +179,27 @@
             *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
             break;
     }
-
+    if (v.get()) {
+        v->timestamp = elapsedRealtimeNano();
+    }
     return v;
 }
 
+bool EmulatedVehicleHal::dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+    return mVehicleClient->dump(fd, options);
+}
+
 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
-    static constexpr bool shouldUpdateStatus = false;
+    constexpr bool updateStatus = false;
 
     if (propValue.prop == kGenerateFakeDataControllingProperty) {
-        StatusCode status = handleGenerateFakeDataRequest(propValue);
-        if (status != StatusCode::OK) {
-            return status;
-        }
+        // Send the generator controlling request to the server.
+        // 'updateStatus' flag is only for the value sent by setProperty (propValue in this case)
+        // instead of the generated values triggered by it. 'propValue' works as a control signal
+        // here, since we never send the control signal back, the value of 'updateStatus' flag
+        // does not matter here.
+        auto status = mVehicleClient->setProperty(propValue, updateStatus);
+        return status;
     } else if (mHvacPowerProps.count(propValue.prop)) {
         auto hvacPowerOn = mPropStore->readValueOrNull(
             toInt(VehicleProperty::HVAC_POWER_ON),
@@ -157,29 +220,6 @@
                 // Placeholder for future implementation of VMS property in the default hal. For
                 // now, just returns OK; otherwise, hal clients crash with property not supported.
                 return StatusCode::OK;
-            case AP_POWER_STATE_REPORT:
-                switch (propValue.value.int32Values[0]) {
-                    case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
-                    case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
-                    case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
-                        // CPMS is in WAIT_FOR_VHAL state, simply move to ON
-                        doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::ON, 0));
-                        break;
-                    case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
-                    case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
-                        // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
-                        doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0));
-                        break;
-                    case toInt(VehicleApPowerStateReport::ON):
-                    case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
-                    case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
-                        // Do nothing
-                        break;
-                    default:
-                        // Unknown state
-                        break;
-                }
-                break;
         }
     }
 
@@ -199,12 +239,6 @@
         return StatusCode::NOT_AVAILABLE;
     }
 
-    if (!mPropStore->writeValue(propValue, shouldUpdateStatus)) {
-        return StatusCode::INVALID_ARG;
-    }
-
-    getEmulatorOrDie()->doSetValueFromClient(propValue);
-
     if (mInEmulator && propValue.prop == toInt(VehicleProperty::DISPLAY_BRIGHTNESS)) {
         // Emulator does not support remote brightness control, b/139959479
         // do not send it down so that it does not bring unnecessary property change event
@@ -213,7 +247,17 @@
         return StatusCode::OK;
     }
 
-    doHalEvent(getValuePool()->obtain(propValue));
+    /**
+     * After checking all conditions, such as the property is available, a real vhal will
+     * sent the events to Car ECU to take actions.
+     */
+
+    // Send the value to the vehicle server, the server will talk to the (real or emulated) car
+    auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus);
+    if (setValueStatus != StatusCode::OK) {
+        return setValueStatus;
+    }
+
     return StatusCode::OK;
 }
 
@@ -283,6 +327,13 @@
                 }
             } else {
                 prop.value = it.initialValue;
+                if (mInitVhalValueOverride) {
+                    for (auto& itOverride : mVehiclePropertiesOverride) {
+                        if (itOverride.prop == cfg.prop) {
+                            prop.value = itOverride.value;
+                        }
+                    }
+                }
             }
             mPropStore->writeValue(prop, shouldUpdateStatus);
         }
@@ -346,144 +397,20 @@
 }
 
 bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
-    static constexpr bool shouldUpdateStatus = true;
-
-    if (propValue.prop == kGenerateFakeDataControllingProperty) {
-        StatusCode status = handleGenerateFakeDataRequest(propValue);
-        if (status != StatusCode::OK) {
-            return false;
-        }
-    }
-
-    if (mPropStore->writeValue(propValue, shouldUpdateStatus)) {
-        doHalEvent(getValuePool()->obtain(propValue));
-        return true;
-    } else {
-        return false;
-    }
+    constexpr bool updateStatus = true;
+    return mVehicleClient->setProperty(propValue, updateStatus) == StatusCode::OK;
 }
 
 std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const  {
     return mPropStore->readAllValues();
 }
 
-StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
-    ALOGI("%s", __func__);
-    const auto& v = request.value;
-    if (!v.int32Values.size()) {
-        ALOGE("%s: expected at least \"command\" field in int32Values", __func__);
-        return StatusCode::INVALID_ARG;
-    }
-
-    FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
-
-    switch (command) {
-        case FakeDataCommand::StartLinear: {
-            ALOGI("%s, FakeDataCommand::StartLinear", __func__);
-            if (v.int32Values.size() < 2) {
-                ALOGE("%s: expected property ID in int32Values", __func__);
-                return StatusCode::INVALID_ARG;
-            }
-            if (!v.int64Values.size()) {
-                ALOGE("%s: interval is not provided in int64Values", __func__);
-                return StatusCode::INVALID_ARG;
-            }
-            if (v.floatValues.size() < 3) {
-                ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
-                      v.floatValues.size());
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = v.int32Values[1];
-            mGeneratorHub.registerGenerator(cookie,
-                                            std::make_unique<LinearFakeValueGenerator>(request));
-            break;
-        }
-        case FakeDataCommand::StartJson: {
-            ALOGI("%s, FakeDataCommand::StartJson", __func__);
-            if (v.stringValue.empty()) {
-                ALOGE("%s: path to JSON file is missing", __func__);
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = std::hash<std::string>()(v.stringValue);
-            mGeneratorHub.registerGenerator(cookie,
-                                            std::make_unique<JsonFakeValueGenerator>(request));
-            break;
-        }
-        case FakeDataCommand::StopLinear: {
-            ALOGI("%s, FakeDataCommand::StopLinear", __func__);
-            if (v.int32Values.size() < 2) {
-                ALOGE("%s: expected property ID in int32Values", __func__);
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = v.int32Values[1];
-            mGeneratorHub.unregisterGenerator(cookie);
-            break;
-        }
-        case FakeDataCommand::StopJson: {
-            ALOGI("%s, FakeDataCommand::StopJson", __func__);
-            if (v.stringValue.empty()) {
-                ALOGE("%s: path to JSON file is missing", __func__);
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = std::hash<std::string>()(v.stringValue);
-            mGeneratorHub.unregisterGenerator(cookie);
-            break;
-        }
-        case FakeDataCommand::KeyPress: {
-            ALOGI("%s, FakeDataCommand::KeyPress", __func__);
-            int32_t keyCode = request.value.int32Values[2];
-            int32_t display = request.value.int32Values[3];
-            doHalEvent(
-                createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
-            doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
-            break;
-        }
-        default: {
-            ALOGE("%s: unexpected command: %d", __func__, command);
-            return StatusCode::INVALID_ARG;
-        }
-    }
-    return StatusCode::OK;
-}
-
-VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createApPowerStateReq(
-    VehicleApPowerStateReq state, int32_t param) {
-    auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
-    req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
-    req->areaId = 0;
-    req->timestamp = elapsedRealtimeNano();
-    req->status = VehiclePropertyStatus::AVAILABLE;
-    req->value.int32Values[0] = toInt(state);
-    req->value.int32Values[1] = param;
-    return req;
-}
-
-VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp(
-    VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
-    auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
-    keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
-    keyEvent->areaId = 0;
-    keyEvent->timestamp = elapsedRealtimeNano();
-    keyEvent->status = VehiclePropertyStatus::AVAILABLE;
-    keyEvent->value.int32Values[0] = toInt(action);
-    keyEvent->value.int32Values[1] = keyCode;
-    keyEvent->value.int32Values[2] = targetDisplay;
-    return keyEvent;
-}
-
-void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) {
-    ALOGD("%s: %s", __func__, toString(value).c_str());
-    static constexpr bool shouldUpdateStatus = false;
-
+void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
     VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
-    if (updatedPropValue) {
-        updatedPropValue->timestamp = elapsedRealtimeNano();
-        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
-        mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
-        auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
-        if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
-            doHalEvent(std::move(updatedPropValue));
-        }
+
+    if (mPropStore->writeValue(*updatedPropValue, updateStatus)) {
+        getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
+        doHalEvent(std::move(updatedPropValue));
     }
 }
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index 367a6ec..eb38d7d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -30,6 +30,8 @@
 #include "vhal_v2_0/VehiclePropertyStore.h"
 
 #include "DefaultConfig.h"
+#include "EmulatedUserHal.h"
+#include "EmulatedVehicleConnector.h"
 #include "GeneratorHub.h"
 #include "VehicleEmulator.h"
 
@@ -44,7 +46,8 @@
 /** Implementation of VehicleHal that connected to emulator instead of real vehicle network. */
 class EmulatedVehicleHal : public EmulatedVehicleHalIface {
 public:
-    EmulatedVehicleHal(VehiclePropertyStore* propStore);
+    EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client,
+                       EmulatedUserHal* emulatedUserHal = nullptr);
     ~EmulatedVehicleHal() = default;
 
     //  Methods from VehicleHal
@@ -55,10 +58,12 @@
     StatusCode set(const VehiclePropValue& propValue) override;
     StatusCode subscribe(int32_t property, float sampleRate) override;
     StatusCode unsubscribe(int32_t property) override;
+    bool dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
     //  Methods from EmulatedVehicleHalIface
     bool setPropertyFromVehicle(const VehiclePropValue& propValue) override;
     std::vector<VehiclePropValue> getAllProperties() const override;
+    void getAllPropertiesOverride();
 
 private:
     constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const {
@@ -66,10 +71,7 @@
     }
 
     StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
-    void onFakeValueGenerated(const VehiclePropValue& value);
-    VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
-    VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
-                                             int32_t targetDisplay);
+    void onPropertyValue(const VehiclePropValue& value, bool updateStatus);
 
     void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
     bool isContinuousProperty(int32_t propId) const;
@@ -85,8 +87,11 @@
     VehiclePropertyStore* mPropStore;
     std::unordered_set<int32_t> mHvacPowerProps;
     RecurrentTimer mRecurrentTimer;
-    GeneratorHub mGeneratorHub;
+    VehicleHalClient* mVehicleClient;
     bool mInEmulator;
+    bool mInitVhalValueOverride;
+    std::vector<VehiclePropValue> mVehiclePropertiesOverride;
+    EmulatedUserHal* mEmulatedUserHal;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
index d6ad77d..2dc502b 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
@@ -19,6 +19,8 @@
 
 #include <android/hardware/automotive/vehicle/2.0/types.h>
 
+#include <chrono>
+
 namespace android {
 namespace hardware {
 namespace automotive {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
index 8677f83..890eb33 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
@@ -48,6 +48,22 @@
     mNumOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1];
 }
 
+JsonFakeValueGenerator::JsonFakeValueGenerator(std::string path) {
+    std::ifstream ifs(path);
+    if (!ifs) {
+        ALOGE("%s: couldn't open %s for parsing.", __func__, path.c_str());
+    }
+    mGenCfg = {
+        .index = 0,
+        .events = parseFakeValueJson(ifs),
+    };
+    mNumOfIterations = mGenCfg.events.size();
+}
+
+std::vector<VehiclePropValue> JsonFakeValueGenerator::getAllEvents() {
+    return mGenCfg.events;
+}
+
 VehiclePropValue JsonFakeValueGenerator::nextEvent() {
     VehiclePropValue generatedValue;
     if (!hasNext()) {
@@ -109,6 +125,7 @@
 
         Json::Value rawEventValue = rawEvent["value"];
         auto& value = event.value;
+        int32_t count;
         switch (getPropType(event.prop)) {
             case VehiclePropertyType::BOOLEAN:
             case VehiclePropertyType::INT32:
@@ -126,6 +143,13 @@
             case VehiclePropertyType::STRING:
                 value.stringValue = rawEventValue.asString();
                 break;
+            case VehiclePropertyType::INT32_VEC:
+                value.int32Values.resize(rawEventValue.size());
+                count = 0;
+                for (auto& it : rawEventValue) {
+                    value.int32Values[count++] = it.asInt();
+                }
+                break;
             case VehiclePropertyType::MIXED:
                 copyMixedValueJson(value, rawEventValue);
                 if (isDiagnosticProperty(event.prop)) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
index 70575f7..dc8ff66 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
@@ -41,9 +41,12 @@
 
 public:
     JsonFakeValueGenerator(const VehiclePropValue& request);
+    JsonFakeValueGenerator(std::string path);
+
     ~JsonFakeValueGenerator() = default;
 
     VehiclePropValue nextEvent();
+    std::vector<VehiclePropValue> getAllEvents();
 
     bool hasNext();
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
index 7bdc97c..96aaafe 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
@@ -46,7 +46,8 @@
     if (mGenCfg.currentValue > mGenCfg.initialValue + mGenCfg.dispersion) {
         mGenCfg.currentValue = mGenCfg.initialValue - mGenCfg.dispersion;
     }
-    VehiclePropValue event = {.prop = mGenCfg.propId};
+    // TODO: (chenhaosjtuacm) remove "{}" if AGL compiler updated
+    VehiclePropValue event = {.timestamp = {}, .areaId = {}, .prop = mGenCfg.propId};
     auto& value = event.value;
     switch (getPropType(event.prop)) {
         case VehiclePropertyType::INT32:
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp
new file mode 100644
index 0000000..77cb114
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp
@@ -0,0 +1,216 @@
+/*
+ * 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 "ProtoMsgConverter"
+
+#include <memory>
+#include <vector>
+
+#include <log/log.h>
+
+#include <vhal_v2_0/VehicleUtils.h>
+
+#include "ProtoMessageConverter.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+namespace proto_msg_converter {
+
+// If protobuf class PROTO_VALUE has value in field PROTO_VARNAME,
+// then casting the value by CAST and copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME
+#define CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \
+                                                  VHAL_TYPE_VARNAME, CAST)                     \
+    if (PROTO_VALUE.has_##PROTO_VARNAME()) {                                                   \
+        (VHAL_TYPE_VALUE)->VHAL_TYPE_VARNAME = CAST(PROTO_VALUE.PROTO_VARNAME());              \
+    }
+
+// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to
+// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME, every element of PROTO_VECNAME
+// is casted by CAST
+#define CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \
+                                            VHAL_TYPE_VECNAME, CAST)                     \
+    do {                                                                                 \
+        (VHAL_TYPE_VALUE)->VHAL_TYPE_VECNAME.resize(PROTO_VALUE.PROTO_VECNAME##_size()); \
+        size_t idx = 0;                                                                  \
+        for (auto& value : PROTO_VALUE.PROTO_VECNAME()) {                                \
+            VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME[idx++] = CAST(value);                     \
+        }                                                                                \
+    } while (0)
+
+// If protobuf message has value in field PROTO_VARNAME,
+// then copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME
+#define CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \
+                                             VHAL_TYPE_VARNAME)                           \
+    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(                                            \
+            PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VARNAME, /*NO CAST*/)
+
+// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to
+// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME
+#define COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \
+                                       VHAL_TYPE_VECNAME)                           \
+    CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(                                            \
+            PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VECNAME, /*NO CAST*/)
+
+void toProto(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) {
+    protoCfg->set_prop(cfg.prop);
+    protoCfg->set_access(toInt(cfg.access));
+    protoCfg->set_change_mode(toInt(cfg.changeMode));
+    protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
+
+    for (auto& configElement : cfg.configArray) {
+        protoCfg->add_config_array(configElement);
+    }
+
+    if (cfg.configString.size() > 0) {
+        protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
+    }
+
+    protoCfg->clear_area_configs();
+    for (auto& areaConfig : cfg.areaConfigs) {
+        auto* protoACfg = protoCfg->add_area_configs();
+        protoACfg->set_area_id(areaConfig.areaId);
+
+        switch (getPropType(cfg.prop)) {
+            case VehiclePropertyType::STRING:
+            case VehiclePropertyType::BOOLEAN:
+            case VehiclePropertyType::INT32_VEC:
+            case VehiclePropertyType::INT64_VEC:
+            case VehiclePropertyType::FLOAT_VEC:
+            case VehiclePropertyType::BYTES:
+            case VehiclePropertyType::MIXED:
+                // Do nothing.  These types don't have min/max values
+                break;
+            case VehiclePropertyType::INT64:
+                protoACfg->set_min_int64_value(areaConfig.minInt64Value);
+                protoACfg->set_max_int64_value(areaConfig.maxInt64Value);
+                break;
+            case VehiclePropertyType::FLOAT:
+                protoACfg->set_min_float_value(areaConfig.minFloatValue);
+                protoACfg->set_max_float_value(areaConfig.maxFloatValue);
+                break;
+            case VehiclePropertyType::INT32:
+                protoACfg->set_min_int32_value(areaConfig.minInt32Value);
+                protoACfg->set_max_int32_value(areaConfig.maxInt32Value);
+                break;
+            default:
+                ALOGW("%s: Unknown property type:  0x%x", __func__, toInt(getPropType(cfg.prop)));
+                break;
+        }
+    }
+
+    protoCfg->set_min_sample_rate(cfg.minSampleRate);
+    protoCfg->set_max_sample_rate(cfg.maxSampleRate);
+}
+
+void fromProto(VehiclePropConfig* cfg, const vhal_proto::VehiclePropConfig& protoCfg) {
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, prop, cfg, prop);
+    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, access, cfg, access,
+                                              static_cast<VehiclePropertyAccess>);
+    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, change_mode, cfg, changeMode,
+                                              static_cast<VehiclePropertyChangeMode>);
+    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, config_array, cfg, configArray);
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, config_string, cfg, configString);
+
+    auto cast_to_acfg = [](const vhal_proto::VehicleAreaConfig& protoAcfg) {
+        VehicleAreaConfig acfg;
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, area_id, &acfg, areaId);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int32_value, &acfg, minInt32Value);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int32_value, &acfg, maxInt32Value);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int64_value, &acfg, minInt64Value);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int64_value, &acfg, maxInt64Value);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_float_value, &acfg, minFloatValue);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_float_value, &acfg, maxFloatValue);
+        return acfg;
+    };
+
+    CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, area_configs, cfg, areaConfigs, cast_to_acfg);
+
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, min_sample_rate, cfg, minSampleRate);
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, max_sample_rate, cfg, maxSampleRate);
+}
+
+void toProto(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue& val) {
+    protoVal->set_prop(val.prop);
+    protoVal->set_value_type(toInt(getPropType(val.prop)));
+    protoVal->set_timestamp(val.timestamp);
+    protoVal->set_status((vhal_proto::VehiclePropStatus)(val.status));
+    protoVal->set_area_id(val.areaId);
+
+    // Copy value data if it is set.
+    //  - for bytes and strings, this is indicated by size > 0
+    //  - for int32, int64, and float, copy the values if vectors have data
+    if (val.value.stringValue.size() > 0) {
+        protoVal->set_string_value(val.value.stringValue.c_str(), val.value.stringValue.size());
+    }
+
+    if (val.value.bytes.size() > 0) {
+        protoVal->set_bytes_value(val.value.bytes.data(), val.value.bytes.size());
+    }
+
+    for (auto& int32Value : val.value.int32Values) {
+        protoVal->add_int32_values(int32Value);
+    }
+
+    for (auto& int64Value : val.value.int64Values) {
+        protoVal->add_int64_values(int64Value);
+    }
+
+    for (auto& floatValue : val.value.floatValues) {
+        protoVal->add_float_values(floatValue);
+    }
+}
+
+void fromProto(VehiclePropValue* val, const vhal_proto::VehiclePropValue& protoVal) {
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, prop, val, prop);
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, timestamp, val, timestamp);
+    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, status, val, status,
+                                              static_cast<VehiclePropertyStatus>);
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, area_id, val, areaId);
+
+    // Copy value data
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, string_value, val, value.stringValue);
+
+    auto cast_proto_bytes_to_vec = [](auto&& bytes) {
+        return std::vector<uint8_t>(bytes.begin(), bytes.end());
+    };
+    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, bytes_value, val, value.bytes,
+                                              cast_proto_bytes_to_vec);
+
+    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int32_values, val, value.int32Values);
+    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int64_values, val, value.int64Values);
+    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, float_values, val, value.floatValues);
+}
+
+#undef COPY_PROTOBUF_VEC_TO_VHAL_TYPE
+#undef CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE
+#undef CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE
+#undef CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE
+
+}  // namespace proto_msg_converter
+
+}  // 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/ProtoMessageConverter.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h
new file mode 100644
index 0000000..01f3beb
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h
@@ -0,0 +1,56 @@
+/*
+ * 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_ProtoMessageConverter_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_ProtoMessageConverter_H_
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+#include "VehicleHalProto.pb.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+namespace proto_msg_converter {
+
+// VehiclePropConfig
+
+void toProto(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg);
+
+void fromProto(VehiclePropConfig* cfg, const vhal_proto::VehiclePropConfig& protoCfg);
+
+// VehiclePropValue
+
+void toProto(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue& val);
+
+void fromProto(VehiclePropValue* val, const vhal_proto::VehiclePropValue& protoVal);
+
+}  // namespace proto_msg_converter
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
index 9eb8894..916c320 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
@@ -60,7 +60,7 @@
     }
 }
 
-void SocketComm::sendMessage(emulator::EmulatorMessage const& msg) {
+void SocketComm::sendMessage(vhal_proto::EmulatorMessage const& msg) {
     std::lock_guard<std::mutex> lock(mMutex);
     for (std::unique_ptr<SocketConn> const& conn : mOpenConnections) {
         conn->sendMessage(msg);
@@ -92,7 +92,10 @@
     }
 
     ALOGI("%s: Listening for connections on port %d", __FUNCTION__, DEBUG_SOCKET);
-    ::listen(mListenFd, 1);
+    if (::listen(mListenFd, 1) == -1) {
+        ALOGE("%s: Error on listening: errno: %d: %s", __FUNCTION__, errno, strerror(errno));
+        return false;
+    }
     return true;
 }
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
index 88b852b..52326b9 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
@@ -47,7 +47,7 @@
     /**
      * Serialized and send the given message to all connected clients.
      */
-    void sendMessage(emulator::EmulatorMessage const& msg);
+    void sendMessage(vhal_proto::EmulatorMessage const& msg);
 
    private:
     int mListenFd;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
index 9dc7085..263ca62 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
@@ -24,6 +24,7 @@
 #include <vhal_v2_0/VehicleUtils.h>
 
 #include "PipeComm.h"
+#include "ProtoMessageConverter.h"
 #include "SocketComm.h"
 
 #include "VehicleEmulator.h"
@@ -62,11 +63,11 @@
  * changed.
  */
 void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) {
-    emulator::EmulatorMessage msg;
-    emulator::VehiclePropValue *val = msg.add_value();
+    vhal_proto::EmulatorMessage msg;
+    vhal_proto::VehiclePropValue* val = msg.add_value();
     populateProtoVehiclePropValue(val, &propValue);
-    msg.set_status(emulator::RESULT_OK);
-    msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
+    msg.set_status(vhal_proto::RESULT_OK);
+    msg.set_msg_type(vhal_proto::SET_PROPERTY_ASYNC);
 
     mSocketComm->sendMessage(msg);
     if (mPipeComm) {
@@ -77,17 +78,17 @@
 void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage const& rxMsg,
                                   VehicleEmulator::EmulatorMessage& respMsg) {
     std::vector<VehiclePropConfig> configs = mHal->listProperties();
-    emulator::VehiclePropGet getProp = rxMsg.prop(0);
+    vhal_proto::VehiclePropGet getProp = rxMsg.prop(0);
 
-    respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
-    respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
+    respMsg.set_msg_type(vhal_proto::GET_CONFIG_RESP);
+    respMsg.set_status(vhal_proto::ERROR_INVALID_PROPERTY);
 
     for (auto& config : configs) {
         // Find the config we are looking for
         if (config.prop == getProp.prop()) {
-            emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+            vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config();
             populateProtoVehicleConfig(protoCfg, config);
-            respMsg.set_status(emulator::RESULT_OK);
+            respMsg.set_status(vhal_proto::RESULT_OK);
             break;
         }
     }
@@ -97,11 +98,11 @@
                                      VehicleEmulator::EmulatorMessage& respMsg) {
     std::vector<VehiclePropConfig> configs = mHal->listProperties();
 
-    respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
-    respMsg.set_status(emulator::RESULT_OK);
+    respMsg.set_msg_type(vhal_proto::GET_CONFIG_ALL_RESP);
+    respMsg.set_status(vhal_proto::RESULT_OK);
 
     for (auto& config : configs) {
-        emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+        vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config();
         populateProtoVehicleConfig(protoCfg, config);
     }
 }
@@ -109,11 +110,11 @@
 void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
                                     VehicleEmulator::EmulatorMessage& respMsg) {
     int32_t areaId = 0;
-    emulator::VehiclePropGet getProp = rxMsg.prop(0);
+    vhal_proto::VehiclePropGet getProp = rxMsg.prop(0);
     int32_t propId = getProp.prop();
-    emulator::Status status = emulator::ERROR_INVALID_PROPERTY;
+    vhal_proto::Status status = vhal_proto::ERROR_INVALID_PROPERTY;
 
-    respMsg.set_msg_type(emulator::GET_PROPERTY_RESP);
+    respMsg.set_msg_type(vhal_proto::GET_PROPERTY_RESP);
 
     if (getProp.has_area_id()) {
         areaId = getProp.area_id();
@@ -127,9 +128,9 @@
         StatusCode halStatus;
         auto val = mHal->get(request, &halStatus);
         if (val != nullptr) {
-            emulator::VehiclePropValue* protoVal = respMsg.add_value();
+            vhal_proto::VehiclePropValue* protoVal = respMsg.add_value();
             populateProtoVehiclePropValue(protoVal, val.get());
-            status = emulator::RESULT_OK;
+            status = vhal_proto::RESULT_OK;
         }
     }
 
@@ -138,12 +139,12 @@
 
 void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage const& /* rxMsg */,
                                        VehicleEmulator::EmulatorMessage& respMsg) {
-    respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP);
-    respMsg.set_status(emulator::RESULT_OK);
+    respMsg.set_msg_type(vhal_proto::GET_PROPERTY_ALL_RESP);
+    respMsg.set_status(vhal_proto::RESULT_OK);
 
     {
         for (const auto& prop : mHal->getAllProperties()) {
-            emulator::VehiclePropValue* protoVal = respMsg.add_value();
+            vhal_proto::VehiclePropValue* protoVal = respMsg.add_value();
             populateProtoVehiclePropValue(protoVal, &prop);
         }
     }
@@ -151,7 +152,7 @@
 
 void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
                                     VehicleEmulator::EmulatorMessage& respMsg) {
-    emulator::VehiclePropValue protoVal = rxMsg.value(0);
+    vhal_proto::VehiclePropValue protoVal = rxMsg.value(0);
     VehiclePropValue val = {
             .timestamp = elapsedRealtimeNano(),
             .areaId = protoVal.area_id(),
@@ -159,7 +160,7 @@
             .status = (VehiclePropertyStatus)protoVal.status(),
     };
 
-    respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
+    respMsg.set_msg_type(vhal_proto::SET_PROPERTY_RESP);
 
     // Copy value data if it is set.  This automatically handles complex data types if needed.
     if (protoVal.has_string_value()) {
@@ -187,120 +188,42 @@
     }
 
     bool halRes = mHal->setPropertyFromVehicle(val);
-    respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY);
+    respMsg.set_status(halRes ? vhal_proto::RESULT_OK : vhal_proto::ERROR_INVALID_PROPERTY);
 }
 
-void VehicleEmulator::processMessage(emulator::EmulatorMessage const& rxMsg,
-                                     emulator::EmulatorMessage& respMsg) {
+void VehicleEmulator::processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+                                     vhal_proto::EmulatorMessage& respMsg) {
     switch (rxMsg.msg_type()) {
-        case emulator::GET_CONFIG_CMD:
+        case vhal_proto::GET_CONFIG_CMD:
             doGetConfig(rxMsg, respMsg);
             break;
-        case emulator::GET_CONFIG_ALL_CMD:
+        case vhal_proto::GET_CONFIG_ALL_CMD:
             doGetConfigAll(rxMsg, respMsg);
             break;
-        case emulator::GET_PROPERTY_CMD:
+        case vhal_proto::GET_PROPERTY_CMD:
             doGetProperty(rxMsg, respMsg);
             break;
-        case emulator::GET_PROPERTY_ALL_CMD:
+        case vhal_proto::GET_PROPERTY_ALL_CMD:
             doGetPropertyAll(rxMsg, respMsg);
             break;
-        case emulator::SET_PROPERTY_CMD:
+        case vhal_proto::SET_PROPERTY_CMD:
             doSetProperty(rxMsg, respMsg);
             break;
         default:
             ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
-            respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
+            respMsg.set_status(vhal_proto::ERROR_UNIMPLEMENTED_CMD);
             break;
     }
 }
 
-void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+void VehicleEmulator::populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg,
                                                  const VehiclePropConfig& cfg) {
-    protoCfg->set_prop(cfg.prop);
-    protoCfg->set_access(toInt(cfg.access));
-    protoCfg->set_change_mode(toInt(cfg.changeMode));
-    protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
-
-    for (auto& configElement : cfg.configArray) {
-        protoCfg->add_config_array(configElement);
-    }
-
-    if (cfg.configString.size() > 0) {
-        protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
-    }
-
-    // Populate the min/max values based on property type
-    switch (getPropType(cfg.prop)) {
-        case VehiclePropertyType::STRING:
-        case VehiclePropertyType::BOOLEAN:
-        case VehiclePropertyType::INT32_VEC:
-        case VehiclePropertyType::INT64_VEC:
-        case VehiclePropertyType::FLOAT_VEC:
-        case VehiclePropertyType::BYTES:
-        case VehiclePropertyType::MIXED:
-            // Do nothing.  These types don't have min/max values
-            break;
-        case VehiclePropertyType::INT64:
-            if (cfg.areaConfigs.size() > 0) {
-                emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
-                aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
-                aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
-            }
-            break;
-        case VehiclePropertyType::FLOAT:
-            if (cfg.areaConfigs.size() > 0) {
-                emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
-                aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
-                aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
-            }
-            break;
-        case VehiclePropertyType::INT32:
-            if (cfg.areaConfigs.size() > 0) {
-                emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
-                aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
-                aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
-            }
-            break;
-        default:
-            ALOGW("%s: Unknown property type:  0x%x", __func__, toInt(getPropType(cfg.prop)));
-            break;
-    }
-
-    protoCfg->set_min_sample_rate(cfg.minSampleRate);
-    protoCfg->set_max_sample_rate(cfg.maxSampleRate);
+    return proto_msg_converter::toProto(protoCfg, cfg);
 }
 
-void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+void VehicleEmulator::populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal,
                                                     const VehiclePropValue* val) {
-    protoVal->set_prop(val->prop);
-    protoVal->set_value_type(toInt(getPropType(val->prop)));
-    protoVal->set_timestamp(val->timestamp);
-    protoVal->set_status((emulator::VehiclePropStatus)(val->status));
-    protoVal->set_area_id(val->areaId);
-
-    // Copy value data if it is set.
-    //  - for bytes and strings, this is indicated by size > 0
-    //  - for int32, int64, and float, copy the values if vectors have data
-    if (val->value.stringValue.size() > 0) {
-        protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
-    }
-
-    if (val->value.bytes.size() > 0) {
-        protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
-    }
-
-    for (auto& int32Value : val->value.int32Values) {
-        protoVal->add_int32_values(int32Value);
-    }
-
-    for (auto& int64Value : val->value.int64Values) {
-        protoVal->add_int64_values(int64Value);
-    }
-
-    for (auto& floatValue : val->value.floatValues) {
-        protoVal->add_float_values(floatValue);
-    }
+    return proto_msg_converter::toProto(protoVal, *val);
 }
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
index 58e387a..82947be 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
@@ -72,21 +72,21 @@
     virtual ~VehicleEmulator();
 
     void doSetValueFromClient(const VehiclePropValue& propValue);
-    void processMessage(emulator::EmulatorMessage const& rxMsg,
-                        emulator::EmulatorMessage& respMsg) override;
+    void processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+                        vhal_proto::EmulatorMessage& respMsg) override;
 
    private:
     friend class ConnectionThread;
-    using EmulatorMessage = emulator::EmulatorMessage;
+    using EmulatorMessage = vhal_proto::EmulatorMessage;
 
     void doGetConfig(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
     void doGetConfigAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
     void doGetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
     void doGetPropertyAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
     void doSetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
-    void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+    void populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg,
                                     const VehiclePropConfig& cfg);
-    void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+    void populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal,
                                        const VehiclePropValue* val);
 
 private:
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp
new file mode 100644
index 0000000..25ffc6d
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp
@@ -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.
+ */
+
+#include "VehicleHalClient.h"
+
+#include <android-base/logging.h>
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+void VehicleHalClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
+    if (!mPropCallback) {
+        LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
+        return;
+    }
+    return mPropCallback(value, updateStatus);
+}
+
+void VehicleHalClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
+    if (mPropCallback) {
+        LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!";
+        return;
+    }
+    mPropCallback = std::move(callback);
+}
+
+}  // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h
new file mode 100644
index 0000000..6559e2a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.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.
+ */
+
+#pragma once
+
+#include <vhal_v2_0/VehicleClient.h>
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+// The common client operations that may be used by both native and
+// virtualized VHAL clients.
+class VehicleHalClient : public IVehicleClient {
+  public:
+    // Type of callback function for handling the new property values
+    using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;
+
+    // Method from IVehicleClient
+    void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;
+
+    void registerPropertyValueCallback(PropertyCallBackType&& callback);
+
+  private:
+    PropertyCallBackType mPropCallback;
+};
+
+}  // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
new file mode 100644
index 0000000..36f2534
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
@@ -0,0 +1,283 @@
+/*
+ * 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 "VehicleHalServer"
+
+#include "VehicleHalServer.h"
+
+#include <fstream>
+
+#include <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "DefaultConfig.h"
+#include "JsonFakeValueGenerator.h"
+#include "LinearFakeValueGenerator.h"
+#include "Obd2SensorStore.h"
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+GeneratorHub* VehicleHalServer::getGenerator() {
+    return &mGeneratorHub;
+}
+
+VehiclePropValuePool* VehicleHalServer::getValuePool() const {
+    if (!mValuePool) {
+        LOG(WARNING) << __func__ << ": Value pool not set!";
+    }
+    return mValuePool;
+}
+
+EmulatedUserHal* VehicleHalServer::getEmulatedUserHal() {
+    return &mEmulatedUserHal;
+}
+
+void VehicleHalServer::setValuePool(VehiclePropValuePool* valuePool) {
+    if (!valuePool) {
+        LOG(WARNING) << __func__ << ": Setting value pool to nullptr!";
+    }
+    mValuePool = valuePool;
+}
+
+void VehicleHalServer::onFakeValueGenerated(const VehiclePropValue& value) {
+    constexpr bool updateStatus = true;
+    LOG(DEBUG) << __func__ << ": " << toString(value);
+    auto updatedPropValue = getValuePool()->obtain(value);
+    if (updatedPropValue) {
+        updatedPropValue->timestamp = value.timestamp;
+        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
+        onPropertyValueFromCar(*updatedPropValue, updateStatus);
+    }
+}
+
+std::vector<VehiclePropConfig> VehicleHalServer::onGetAllPropertyConfig() const {
+    std::vector<VehiclePropConfig> vehiclePropConfigs;
+    constexpr size_t numOfVehiclePropConfigs =
+            sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]);
+    vehiclePropConfigs.reserve(numOfVehiclePropConfigs);
+    for (auto& it : kVehicleProperties) {
+        vehiclePropConfigs.emplace_back(it.config);
+    }
+    return vehiclePropConfigs;
+}
+
+StatusCode VehicleHalServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
+    constexpr bool updateStatus = true;
+
+    LOG(INFO) << __func__;
+    const auto& v = request.value;
+    if (!v.int32Values.size()) {
+        LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values";
+        return StatusCode::INVALID_ARG;
+    }
+
+    FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
+
+    switch (command) {
+        case FakeDataCommand::StartLinear: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
+            if (v.int32Values.size() < 2) {
+                LOG(ERROR) << __func__ << ": expected property ID in int32Values";
+                return StatusCode::INVALID_ARG;
+            }
+            if (!v.int64Values.size()) {
+                LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
+                return StatusCode::INVALID_ARG;
+            }
+            if (v.floatValues.size() < 3) {
+                LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
+                           << v.floatValues.size();
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = v.int32Values[1];
+            getGenerator()->registerGenerator(cookie,
+                                              std::make_unique<LinearFakeValueGenerator>(request));
+            break;
+        }
+        case FakeDataCommand::StartJson: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
+            if (v.stringValue.empty()) {
+                LOG(ERROR) << __func__ << ": path to JSON file is missing";
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = std::hash<std::string>()(v.stringValue);
+            getGenerator()->registerGenerator(cookie,
+                                              std::make_unique<JsonFakeValueGenerator>(request));
+            break;
+        }
+        case FakeDataCommand::StopLinear: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
+            if (v.int32Values.size() < 2) {
+                LOG(ERROR) << __func__ << ": expected property ID in int32Values";
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = v.int32Values[1];
+            getGenerator()->unregisterGenerator(cookie);
+            break;
+        }
+        case FakeDataCommand::StopJson: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
+            if (v.stringValue.empty()) {
+                LOG(ERROR) << __func__ << ": path to JSON file is missing";
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = std::hash<std::string>()(v.stringValue);
+            getGenerator()->unregisterGenerator(cookie);
+            break;
+        }
+        case FakeDataCommand::KeyPress: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
+            int32_t keyCode = request.value.int32Values[2];
+            int32_t display = request.value.int32Values[3];
+            // Send back to HAL
+            onPropertyValueFromCar(
+                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
+                    updateStatus);
+            onPropertyValueFromCar(
+                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
+                    updateStatus);
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
+            return StatusCode::INVALID_ARG;
+        }
+    }
+    return StatusCode::OK;
+}
+
+VehicleHalServer::VehiclePropValuePtr VehicleHalServer::createApPowerStateReq(
+        VehicleApPowerStateReq state, int32_t param) {
+    auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
+    req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
+    req->areaId = 0;
+    req->timestamp = elapsedRealtimeNano();
+    req->status = VehiclePropertyStatus::AVAILABLE;
+    req->value.int32Values[0] = toInt(state);
+    req->value.int32Values[1] = param;
+    return req;
+}
+
+VehicleHalServer::VehiclePropValuePtr VehicleHalServer::createHwInputKeyProp(
+        VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
+    auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
+    keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
+    keyEvent->areaId = 0;
+    keyEvent->timestamp = elapsedRealtimeNano();
+    keyEvent->status = VehiclePropertyStatus::AVAILABLE;
+    keyEvent->value.int32Values[0] = toInt(action);
+    keyEvent->value.int32Values[1] = keyCode;
+    keyEvent->value.int32Values[2] = targetDisplay;
+    return keyEvent;
+}
+
+StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
+    if (mEmulatedUserHal.isSupported(value.prop)) {
+        LOG(INFO) << "onSetProperty(): property " << value.prop << " will be handled by UserHal";
+
+        const auto& ret = mEmulatedUserHal.onSetProperty(value);
+        if (!ret.ok()) {
+            LOG(ERROR) << "onSetProperty(): HAL returned error: " << ret.error().message();
+            return StatusCode(ret.error().code());
+        }
+        auto updatedValue = ret.value().get();
+        if (updatedValue != nullptr) {
+            LOG(INFO) << "onSetProperty(): updating property returned by HAL: "
+                      << toString(*updatedValue);
+            onPropertyValueFromCar(*updatedValue, updateStatus);
+        }
+        return StatusCode::OK;
+    }
+    LOG(DEBUG) << "onSetProperty(" << value.prop << ")";
+
+    // Some properties need to be treated non-trivially
+    switch (value.prop) {
+        case kGenerateFakeDataControllingProperty:
+            return handleGenerateFakeDataRequest(value);
+
+        // set the value from vehicle side, used in end to end test.
+        case kSetIntPropertyFromVehicleForTest: {
+            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
+            updatedPropValue->prop = value.value.int32Values[0];
+            updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
+            updatedPropValue->timestamp = value.value.int64Values[0];
+            updatedPropValue->areaId = value.areaId;
+            onPropertyValueFromCar(*updatedPropValue, updateStatus);
+            return StatusCode::OK;
+        }
+        case kSetFloatPropertyFromVehicleForTest: {
+            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
+            updatedPropValue->prop = value.value.int32Values[0];
+            updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
+            updatedPropValue->timestamp = value.value.int64Values[0];
+            updatedPropValue->areaId = value.areaId;
+            onPropertyValueFromCar(*updatedPropValue, updateStatus);
+            return StatusCode::OK;
+        }
+        case kSetBooleanPropertyFromVehicleForTest: {
+            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
+            updatedPropValue->prop = value.value.int32Values[1];
+            updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
+            updatedPropValue->timestamp = value.value.int64Values[0];
+            updatedPropValue->areaId = value.areaId;
+            onPropertyValueFromCar(*updatedPropValue, updateStatus);
+            return StatusCode::OK;
+        }
+
+        case AP_POWER_STATE_REPORT:
+            switch (value.value.int32Values[0]) {
+                case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
+                case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
+                    // CPMS is in WAIT_FOR_VHAL state, simply move to ON
+                    // Send back to HAL
+                    // ALWAYS update status for generated property value
+                    onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
+                                           true /* updateStatus */);
+                    break;
+                case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
+                    // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
+                    // Send back to HAL
+                    // ALWAYS update status for generated property value
+                    onPropertyValueFromCar(
+                            *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
+                            true /* updateStatus */);
+                    break;
+                case toInt(VehicleApPowerStateReport::ON):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
+                    // Do nothing
+                    break;
+                default:
+                    // Unknown state
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+
+    // In the real vhal, the value will be sent to Car ECU.
+    // We just pretend it is done here and send back to HAL
+    auto updatedPropValue = getValuePool()->obtain(value);
+    updatedPropValue->timestamp = elapsedRealtimeNano();
+
+    onPropertyValueFromCar(*updatedPropValue, updateStatus);
+    return StatusCode::OK;
+}
+
+}  // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h
new file mode 100644
index 0000000..fca78bc
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vhal_v2_0/VehicleObjectPool.h>
+#include <vhal_v2_0/VehicleServer.h>
+
+#include "EmulatedUserHal.h"
+#include "GeneratorHub.h"
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+// This contains the common server operations that will be used by
+// both native and virtualized VHAL server. Notice that in the virtualized
+// scenario, the server may be run on a different OS than Android.
+class VehicleHalServer : public IVehicleServer {
+  public:
+    // Methods from IVehicleServer
+
+    std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
+
+    StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
+
+    // Set the Property Value Pool used in this server
+    void setValuePool(VehiclePropValuePool* valuePool);
+
+    EmulatedUserHal* getEmulatedUserHal();
+
+  private:
+    using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>;
+
+    GeneratorHub* getGenerator();
+
+    VehiclePropValuePool* getValuePool() const;
+
+    void onFakeValueGenerated(const VehiclePropValue& value);
+
+    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
+
+    VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
+
+    VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
+                                             int32_t targetDisplay);
+
+    // data members
+
+  protected:
+    EmulatedUserHal mEmulatedUserHal;
+
+  private:
+    GeneratorHub mGeneratorHub{
+            std::bind(&VehicleHalServer::onFakeValueGenerated, this, std::placeholders::_1)};
+
+    VehiclePropValuePool* mValuePool{nullptr};
+};
+
+}  // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
index 6754843..c5b9ed6 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
@@ -16,6 +16,7 @@
 cc_library_static {
     name: "android.hardware.automotive.vehicle@2.0-libproto-native",
     vendor: true,
+    host_supported: true,
     proto: {
         export_proto_headers: true,
         type: "lite",
@@ -27,5 +28,47 @@
         "-Wall",
         "-Werror",
     ],
-    srcs: ["VehicleHalProto.proto"]
+    srcs: ["VehicleHalProto.proto"],
+}
+
+filegroup {
+    name: "vhal-proto-src",
+    visibility: [
+        "//device/google/trout/hal/vehicle/2.0:__subpackages__",
+    ],
+    srcs: [
+        "VehicleHalProto.proto",
+    ],
+}
+
+genrule {
+    name: "DefaultVehicleHalProtoStub_h",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        "VehicleHalProto.proto",
+    ],
+    out: [
+        "VehicleHalProto.pb.h",
+        "VehicleHalProto.grpc.pb.h",
+    ],
+}
+
+genrule {
+    name: "DefaultVehicleHalProtoStub_cc",
+    tools: [
+        "aprotoc",
+        "protoc-gen-grpc-cpp-plugin",
+    ],
+    cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    srcs: [
+        "VehicleHalProto.proto",
+    ],
+    out: [
+        "VehicleHalProto.pb.cc",
+        "VehicleHalProto.grpc.pb.cc",
+    ],
 }
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
index 2ef64fb..4902a5d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
@@ -15,9 +15,8 @@
  */
 
 syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
 
-package emulator;
+package vhal_proto;
 
 // CMD messages are from workstation --> VHAL
 // RESP messages are from VHAL --> workstation
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp
new file mode 100644
index 0000000..3817e44
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <utils/SystemClock.h>
+
+#include "vhal_v2_0/DefaultConfig.h"
+#include "vhal_v2_0/ProtoMessageConverter.h"
+#include "vhal_v2_0/VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace impl {
+namespace proto_msg_converter {
+
+namespace {
+
+void CheckPropConfigConversion(const VehiclePropConfig& config) {
+    vhal_proto::VehiclePropConfig protoCfg;
+    VehiclePropConfig tmpConfig;
+
+    toProto(&protoCfg, config);
+    fromProto(&tmpConfig, protoCfg);
+
+    EXPECT_EQ(config.prop, tmpConfig.prop);
+    EXPECT_EQ(config.access, tmpConfig.access);
+    EXPECT_EQ(config.changeMode, tmpConfig.changeMode);
+    EXPECT_EQ(config.configString, tmpConfig.configString);
+    EXPECT_EQ(config.minSampleRate, tmpConfig.minSampleRate);
+    EXPECT_EQ(config.maxSampleRate, tmpConfig.maxSampleRate);
+    EXPECT_EQ(config.configArray, tmpConfig.configArray);
+
+    EXPECT_EQ(config.areaConfigs.size(), tmpConfig.areaConfigs.size());
+
+    auto cfgType = getPropType(config.prop);
+    for (size_t idx = 0; idx < std::min(config.areaConfigs.size(), tmpConfig.areaConfigs.size());
+         ++idx) {
+        auto& lhs = config.areaConfigs[idx];
+        auto& rhs = tmpConfig.areaConfigs[idx];
+        EXPECT_EQ(lhs.areaId, rhs.areaId);
+        switch (cfgType) {
+            case VehiclePropertyType::INT64:
+                EXPECT_EQ(lhs.minInt64Value, rhs.minInt64Value);
+                EXPECT_EQ(lhs.maxInt64Value, rhs.maxInt64Value);
+                break;
+            case VehiclePropertyType::FLOAT:
+                EXPECT_EQ(lhs.minFloatValue, rhs.minFloatValue);
+                EXPECT_EQ(lhs.maxFloatValue, rhs.maxFloatValue);
+                break;
+            case VehiclePropertyType::INT32:
+                EXPECT_EQ(lhs.minInt32Value, rhs.minInt32Value);
+                EXPECT_EQ(lhs.maxInt32Value, rhs.maxInt32Value);
+                break;
+            default:
+                // ignore min/max values
+                break;
+        }
+    }
+}
+
+void CheckPropValueConversion(const VehiclePropValue& val) {
+    vhal_proto::VehiclePropValue protoVal;
+    VehiclePropValue tmpVal;
+
+    toProto(&protoVal, val);
+    fromProto(&tmpVal, protoVal);
+
+    EXPECT_EQ(val, tmpVal);
+}
+
+TEST(ProtoMessageConverterTest, basic) {
+    for (auto& property : impl::kVehicleProperties) {
+        CheckPropConfigConversion(property.config);
+
+        VehiclePropValue prop;
+        prop.timestamp = elapsedRealtimeNano();
+        prop.areaId = 123;
+        prop.prop = property.config.prop;
+        prop.value = property.initialValue;
+        prop.status = VehiclePropertyStatus::ERROR;
+        CheckPropValueConversion(prop);
+    }
+}
+
+}  // namespace
+
+}  // namespace proto_msg_converter
+}  // namespace impl
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/manifest.vehicle.xml b/automotive/vehicle/2.0/manifest.vehicle.xml
deleted file mode 100644
index 832b302..0000000
--- a/automotive/vehicle/2.0/manifest.vehicle.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="device" target-level="3">
-    <hal format="hidl">
-        <name>android.hardware.automotive.vehicle</name>
-        <transport>hwbinder</transport>
-        <version>2.0</version>
-        <interface>
-            <name>IVehicle</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</manifest>
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 0f20dd1..f7a42e9 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -35,6 +35,21 @@
     /**
      * Any combination of scalar or vector types. The exact format must be
      * provided in the description of the property.
+     *
+     * For vendor MIXED type properties, configArray needs to be formatted in this
+     * structure.
+     * configArray[0], 1 indicates the property has a String value
+     * configArray[1], 1 indicates the property has a Boolean value .
+     * configArray[2], 1 indicates the property has an Integer value.
+     * configArray[3], the number indicates the size of Integer[] in the property.
+     * configArray[4], 1 indicates the property has a Long value.
+     * configArray[5], the number indicates the size of Long[] in the property.
+     * configArray[6], 1 indicates the property has a Float value.
+     * configArray[7], the number indicates the size of Float[] in the property.
+     * configArray[8], the number indicates the size of byte[] in the property.
+     * For example:
+     * {@code configArray = {1, 1, 1, 3, 0, 0, 0, 0, 0}} indicates the property has
+     * a String value, a Boolean value, an Integer value and an array with 3 integers.
      */
     MIXED           = 0x00e00000,
 
@@ -50,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.
@@ -64,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
@@ -125,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:
@@ -283,6 +298,47 @@
         | VehicleArea:SEAT),
 
     /**
+     * Exterior dimensions of vehicle.
+     *
+     *  int32Values[0] = height
+     *  int32Values[1] = length
+     *  int32Values[2] = width
+     *  int32Values[3] = width including mirrors
+     *  int32Values[4] = wheel base
+     *  int32Values[5] = track width front
+     *  int32Values[6] = track width rear
+     *  int32Values[7] = curb to curb turning radius
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     * @unit VehicleUnit:MILLIMETER
+     */
+    INFO_EXTERIOR_DIMENSIONS = (
+        0x010B
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:INT32_VEC
+        | 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
@@ -325,7 +381,7 @@
         | VehicleArea:GLOBAL),
 
     /**
-     * Steering angle of the vehicle
+     * Front bicycle model steering angle for vehicle
      *
      * Angle is in degrees.  Left is negative.
      *
@@ -340,6 +396,21 @@
         | VehicleArea:GLOBAL),
 
     /**
+     * Rear bicycle model steering angle for vehicle
+     *
+     * Angle is in degrees.  Left is negative.
+     *
+     * @change_mode VehiclePropertyChangeMode:CONTINUOUS
+     * @access VehiclePropertyAccess:READ
+     * @unit VehicleUnit:DEGREES
+     */
+    PERF_REAR_STEERING_ANGLE = (
+        0x0210
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:FLOAT
+        | VehicleArea:GLOBAL),
+
+    /**
      * Temperature of engine coolant
      *
      * @change_mode VehiclePropertyChangeMode:CONTINUOUS
@@ -535,8 +606,23 @@
     /**
      * Tire pressure
      *
-     * min/max value indicates tire pressure sensor range.  Each tire will have a separate min/max
-     * value denoted by its areaConfig.areaId.
+     * Each tires is identified by its areaConfig.areaId config and their
+     * minFloatValue/maxFloatValue are used to store OEM recommended pressure
+     * range.
+     * The Min value in the areaConfig data represents the lower bound of
+     * the recommended tire pressure.
+     * The Max value in the areaConfig data represents the upper bound of
+     * the recommended tire pressure.
+     * For example:
+     * The following areaConfig indicates the recommended tire pressure
+     * of left_front tire is from 200.0 KILOPASCAL to 240.0 KILOPASCAL.
+     * .areaConfigs = {
+     *      VehicleAreaConfig {
+     *          .areaId = VehicleAreaWheel::LEFT_FRONT,
+     *          .minFloatValue = 200.0,
+     *          .maxFloatValue = 240.0,
+     *      }
+     * },
      *
      * @change_mode VehiclePropertyChangeMode:CONTINUOUS
      * @access VehiclePropertyAccess:READ
@@ -715,7 +801,8 @@
     /*
      * HVAC Properties
      *
-     * Additional rules for mapping a zoned HVAC property to AreaIDs:
+     * Additional rules for mapping a zoned HVAC property (except
+     * HVAC_MAX_DEFROST_ON) to AreaIDs:
      *  - Every seat in VehicleAreaSeat that is available in the car, must be
      *    part of an AreaID in the AreaID array.
      *
@@ -799,7 +886,7 @@
         | VehicleArea:SEAT),
 
     /**
-     * On/off defrost for designated window
+     * Fan-based defrost for designated window.
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ_WRITE
@@ -848,6 +935,11 @@
      * possible.  Any parameters modified as a side effect of turning on/off
      * the MAX DEFROST parameter shall generate onPropertyEvent() callbacks to
      * the VHAL.
+     * The AreaIDs for HVAC_MAX_DEFROST_ON indicate MAX DEFROST can be controlled
+     * in the area.
+     * For example:
+     * areaConfig.areaId = {ROW_1_LEFT | ROW_1_RIGHT} indicates HVAC_MAX_DEFROST_ON
+     * only can be controlled for the front rows.
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ_WRITE
@@ -1076,6 +1168,7 @@
      *
      * @change_mode VehiclePropertyChangeMode:STATIC
      * @access VehiclePropertyAccess:READ
+     * @data_enum VehicleHvacFanDirection
      */
     HVAC_FAN_DIRECTION_AVAILABLE = (
         0x0511
@@ -1118,6 +1211,18 @@
         | VehiclePropertyType:INT32
         | VehicleArea:SEAT),
 
+    /**
+     * Electric defrosters' status
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    HVAC_ELECTRIC_DEFROSTER_ON = (
+        0x0514
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BOOLEAN
+        | VehicleArea:WINDOW),
+
    /**
      * Distance units for display
      *
@@ -1348,6 +1453,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
@@ -2321,6 +2453,503 @@
         | VehiclePropertyType:INT32
         | VehicleArea:SEAT),
 
+    /**
+     * Support customize permissions for vendor properties
+     *
+     * Implement this property if vehicle hal support customize vendor permissions feature.
+     * VehiclePropConfig.configArray is used to indicate vendor properties and permissions
+     * which selected for this vendor property. The permission must be one of enum in
+     * VehicleVendorPermission.
+     * The configArray is set as follows:
+     *      configArray[n] = propId : property ID for the vendor property
+     *      configArray[n+1] = one of enums in VehicleVendorPermission. It indicates the permission
+     *      for reading value of the property.
+     *      configArray[n+2] = one of enums in VehicleVendorPermission. It indicates the permission
+     *      for writing value of the property.
+     *
+     * For example:
+     * configArray = {
+     *      vendor_prop_1, PERMISSION_VENDOR_SEAT_READ, PERMISSION_VENDOR_SEAT_WRITE,
+     *      vendor_prop_2, PERMISSION_VENDOR_INFO, PERMISSION_NOT_ACCESSIBLE,
+     * }
+     * If vendor properties are not in this array, they will have the default vendor permission.
+     * If vendor chose PERMISSION_NOT_ACCESSIBLE, android will not have access to the property. In
+     * the example, Android can not write value for vendor_prop_2.
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     */
+    SUPPORT_CUSTOMIZE_VENDOR_PERMISSION = (
+        0x0F05
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BOOLEAN
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Allow disabling optional featurs from vhal.
+     *
+     * This property reports optional features that should be disabled.
+     * All allowed optional features for the system is declared in Car service overlay,
+     * config_allowed_optional_car_features.
+     * This property allows disabling features defined in the overlay. Without this property,
+     * all the features declared in the overlay will be enabled.
+     *
+     * Value read should include all features disabled with ',' separation.
+     * ex) "com.android.car.user.CarUserNoticeService,storage_monitoring"
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     */
+    DISABLED_OPTIONAL_FEATURES = (
+        0x0F06
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:STRING
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Defines the initial Android user to be used during initialization.
+     *
+     * This property is called by the Android system when it initializes and it lets the HAL
+     * define which Android user should be started.
+     *
+     * This request is made by setting a VehiclePropValue (defined by InitialUserInfoRequest),
+     * and the HAL must respond with a property change event (defined by InitialUserInfoResponse).
+     * If the HAL doesn't respond after some time (defined by the Android system), the Android
+     * system will proceed as if HAL returned a response of action
+     * InitialUserInfoResponseAction:DEFAULT.
+     *
+     * For example, on first boot, the request could be:
+     *
+     * int32[0]: 42  // request id (arbitrary number set by Android system)
+     * int32[1]: 1   // InitialUserInfoRequestType::FIRST_BOOT
+     * int32[2]: 0   // id of current user (usersInfo.currentUser.userId)
+     * int32[3]: 1   // flag of current user (usersInfo.currentUser.flags = SYSTEM)
+     * int32[4]: 1   // number of existing users (usersInfo.numberUsers);
+     * int32[5]: 0   // user #0  (usersInfo.existingUsers[0].userId)
+     * int32[6]: 1   // flags of user #0  (usersInfo.existingUsers[0].flags)
+     *
+     * And if the HAL want to respond with the creation of an admin user called "Owner", the
+     * response would be:
+     *
+     * int32[0]: 42      // must match the request id from the request
+     * int32[1]:  2      // action = InitialUserInfoResponseAction::CREATE
+     * int32[2]: -10000  // userToSwitchOrCreate.userId (not used as user will be created)
+     * int32[3]:  8      // userToSwitchOrCreate.flags = ADMIN
+     * string: "||Owner" // userLocales + separator + userNameToCreate
+     *
+     * Notice the string value represents multiple values, separated by ||. The first value is the
+     * (optional) system locales for the user to be created (in this case, it's empty, meaning it
+     * will use Android's default value), while the second value is the (also optional) name of the
+     * to user to be created (when the type of response is InitialUserInfoResponseAction:CREATE).
+     * For example, to create the same "Owner" user with "en-US" and "pt-BR" locales, the string
+     * value of the response would be "en-US,pt-BR||Owner". As such, neither the locale nor the
+     * name can have || on it, although a single | is fine.
+     *
+     * NOTE: if the HAL doesn't support user management, then it should not define this property,
+     * which in turn would disable the other user-related properties (for example, the Android
+     * system would never issue them and user-related requests from the HAL layer would be ignored
+     * by the Android System). But if it supports user management, then it must support all core
+     * user-related properties (INITIAL_USER_INFO, SWITCH_USER, CREATE_USER, and REMOVE_USER).
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    INITIAL_USER_INFO = (
+        0x0F07
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Defines a request to switch the foreground Android user.
+     *
+     * This property is used primarily by the Android System to inform the HAL that the
+     * current foreground Android user is switching, but it could also be used by the HAL to request
+     * the Android system to switch users - the
+     *
+     * When the request is made by Android, it sets a VehiclePropValue and the HAL must responde
+     * with a property change event; when the HAL is making the request, it must also do it through
+     * a property change event (the main difference is that the request id will be positive in the
+     * former case, and negative in the latter; the SwitchUserMessageType will also be different).
+     *
+     * The format of both request is defined by SwitchUserRequest and the format of the response
+     * (when needed) is defined by SwitchUserResponse. How the HAL (or Android System) should
+     * proceed depends on the message type (which is defined by the SwitchUserMessageType
+     * parameter), as defined below.
+     *
+     * 1.LEGACY_ANDROID_SWITCH
+     * -----------------------
+     *
+     * Called by the Android System to indicate the Android user is about to change, when the change
+     * request was made in a way that is not integrated with the HAL (for example, through
+     * adb shell am switch-user).
+     *
+     * The HAL can switch its internal user once it receives this request, but it doesn't need to
+     * reply back to the Android System. If its internal user cannot be changed for some reason,
+     * then it must wait for the SWITCH_USER(type=ANDROID_POST_SWITCH) call to recover
+     * (for example, it could issue a SWITCH_USER(type=VEHICLE_REQUEST) to switch back to
+     * the previous user), but ideally it should never fail (as switching back could result in a
+     * confusing experience for the end user).
+     *
+     * For example, if the system have users (0, 10, 11) and it's switching from 0 to 11 (where none
+     * of them have any special flag), the request would be:
+     *
+     * int32[0]:  42  // request id
+     * int32[1]:  1   // SwitchUserMessageType::LEGACY_ANDROID_SWITCH
+     * int32[2]:  11  // target user id
+     * int32[3]:  0   // target user flags (none)
+     * int32[4]:  10  // current user
+     * int32[5]:  0   // current user flags (none)
+     * int32[6]:  3   // number of users
+     * int32[7]:  0   // user #0 (Android user id 0)
+     * int32[8]:  0   // flags of user #0 (none)
+     * int32[9]:  10  // user #1 (Android user id 10)
+     * int32[10]: 0   // flags of user #1 (none)
+     * int32[11]: 11  // user #2 (Android user id 11)
+     * int32[12]: 0   // flags of user #2 (none)
+     *
+     * 2.ANDROID_SWITCH
+     * ----------------
+     * Called by the Android System to indicate the Android user is about to change, but Android
+     * will wait for the HAL's response (up to some time) before proceeding.
+     *
+     * The HAL must switch its internal user once it receives this request, then respond back to
+     * Android with a SWITCH_USER(type=VEHICLE_RESPONSE) indicating whether its internal
+     * user was switched or not (through the SwitchUserStatus enum).
+     *
+     * For example, if Android has users (0, 10, 11) and it's switching from 10 to 11 (where
+     * none of them have any special flag), the request would be:
+     *
+     * int32[0]:  42  // request id
+     * int32[1]:  2   // SwitchUserMessageType::ANDROID_SWITCH
+     * int32[2]:  11  // target user id
+     * int32[3]:  0   // target user flags (none)
+     * int32[4]:  10  // current user
+     * int32[5]:  0   // current user flags (none)
+     * int32[6]:  3   // number of users
+     * int32[7]:  0   // 1st user (user 0)
+     * int32[8]:  1   // 1st user flags (SYSTEM)
+     * int32[9]:  10  // 2nd user (user 10)
+     * int32[10]: 0   // 2nd user flags (none)
+     * int32[11]: 11  // 3rd user (user 11)
+     * int32[12]: 0   // 3rd user flags (none)
+     *
+     * If the request succeeded, the HAL must update the propery with:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 3   // messageType = SwitchUserMessageType::VEHICLE_RESPONSE
+     * int32[2]: 1   // status = SwitchUserStatus::SUCCESS
+     *
+     * But if it failed, the response would be something like:
+     *
+     * int32[0]: 42   // request id
+     * int32[1]: 3    // messageType = SwitchUserMessageType::VEHICLE_RESPONSE
+     * int32[2]: 2    // status = SwitchUserStatus::FAILURE
+     * string: "108-D'OH!" // OEM-spefic error message
+     *
+     * 3.VEHICLE_RESPONSE
+     * ------------------
+     * Called by the HAL to indicate whether a request of type ANDROID_SWITCH should proceed or
+     * abort - see the ANDROID_SWITCH section above for more info.
+     *
+     * 4.VEHICLE_REQUEST
+     * ------------------
+     * Called by the HAL to request that the current foreground Android user is switched.
+     *
+     * This is useful in situations where Android started as one user, but the vehicle identified
+     * the driver as another user. For example, user A unlocked the car using the key fob of user B;
+     * the INITIAL_USER_INFO request returned user B, but then a face recognition subsubsystem
+     * identified the user as A.
+     *
+     * The HAL makes this request by a property change event (passing a negative request id), and
+     * the Android system will response by issue an ANDROID_POST_SWITCH call which the same
+     * request id.
+     *
+     * For example, if the current foreground Android user is 10 and the HAL asked it to switch to
+     * 11, the request would be:
+     *
+     * int32[0]: -108  // request id
+     * int32[1]: 4     // messageType = SwitchUserMessageType::VEHICLE_REQUEST
+     * int32[2]: 11    // Android user id
+     *
+     * If the request succeeded and Android has 3 users (0, 10, 11), the response would be:
+     *
+     * int32[0]: -108 // request id
+     * int32[1]:  5   // messageType = SwitchUserMessageType::ANDROID_POST_SWITCH
+     * int32[2]:  11  // target user id
+     * int32[3]:  0   // target user id flags (none)
+     * int32[4]:  11  // current user
+     * int32[5]:  0   // current user flags (none)
+     * int32[6]:  3   // number of users
+     * int32[7]:  0   // 1st user (user 0)
+     * int32[8]:  0   // 1st user flags (none)
+     * int32[9]:  10  // 2nd user (user 10)
+     * int32[10]: 4   // 2nd user flags (none)
+     * int32[11]: 11  // 3rd user (user 11)
+     * int32[12]: 3   // 3rd user flags (none)
+     *
+     * Notice that both the current and target user ids are the same - if the request failed, then
+     * they would be different (i.e, target user would be 11, but current user would still be 10).
+     *
+     * 5.ANDROID_POST_SWITCH
+     * ---------------------
+     * Called by the Android System after a request to switch a user was made.
+     *
+     * This property is called after switch requests of any type (i.e., LEGACY_ANDROID_SWITCH,
+     * ANDROID_SWITCH, or VEHICLE_REQUEST) and can be used to determine if the request succeeded or
+     * failed:
+     *
+     * 1. When it succeeded, it's called when the Android user is in the unlocked state and the
+     *    value of the current and target users ids in the response are the same. This would be
+     *    equivalent to receiving an Intent.ACTION_USER_UNLOCKED in an Android app.
+     * 2. When it failed it's called right away and the value of the current and target users ids
+     *    in the response are different (as the current user didn't change to the target).
+     * 3. If a new switch request is made before the HAL responded to the previous one or before
+     *    the user was unlocked, then the ANDROID_POST_SWITCH request is not made. For example,
+     *    the driver could accidentally switch to the wrong user which has lock credentials, then
+     *    switch to the right one before entering the credentials.
+     *
+     * The HAL can update its internal state once it receives this request, but it doesn't need to
+     * reply back to the Android System.
+     *
+     * Request: the first N values as defined by INITIAL_USER_INFO (where the request-specific
+     * value at index 1 is SwitchUserMessageType::ANDROID_POST_SWITCH), then 2 more values for the
+     * target user id (i.e., the Android user id that was requested to be switched to) and its flags
+     * (as defined by  UserFlags).
+     *
+     * Response: none.
+     *
+     * Example: see VEHICLE_REQUEST section above.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    SWITCH_USER = (
+        0x0F08
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Called by the Android System after an Android user was created.
+     *
+     * The HAL can use this property to create its equivalent user.
+     *
+     * This is an async request: Android makes the request by setting a VehiclePropValue, and HAL
+     * must respond with a property change indicating whether the request succeeded or failed. If
+     * it failed, the Android system will remove the user.
+     *
+     * The format of the request is defined by CreateUserRequest and the format of the response by
+     * CreateUserResponse.
+     *
+     * For example, if system had 2 users (0 and 10) and a 3rd one (which is an ephemeral guest) was
+     * created, the request would be:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 11  // Android id of the created user
+     * int32[2]: 3   // Android flags (ephemeral guest) of the created user
+     * int32[3]: 10  // current user
+     * int32[4]: 0   // current user flags (none)
+     * int32[5]: 3   // number of users
+     * int32[6]: 0   // 1st user (user 0)
+     * int32[7]: 0   // 1st user flags (none)
+     * int32[8]: 10  // 2nd user (user 10)
+     * int32[9]: 0   // 2nd user flags (none)
+     * int32[19]: 11 // 3rd user (user 11)
+     * int32[11]: 3  // 3rd user flags (ephemeral guest)
+     * string: "ElGuesto" // name of the new user
+     *
+     * Then if the request succeeded, the HAL would return:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 1   // CreateUserStatus::SUCCESS
+     *
+     * But if it failed:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 2   // CreateUserStatus::FAILURE
+     * string: "D'OH!" // The meaning is a blackbox - it's passed to the caller (like Settings UI),
+     *                 // which in turn can take the proper action.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    CREATE_USER = (
+        0x0F09
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Called by the Android System after an Android user was removed.
+     *
+     * The HAL can use this property to remove its equivalent user.
+     *
+     * This is write-only call - the Android System is not expecting a reply from the HAL. Hence,
+     * this request should not fail - if the equivalent HAL user cannot be removed, then HAL should
+     * mark it as inactive or recover in some other way.
+     *
+     * The request is made by setting the VehiclePropValue with the contents defined by
+     * RemoveUserRequest.
+     *
+     * For example, if system had 3 users (0, 10, and 11) and user 11 was removed, the request
+     * would be:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 11  // (Android user id of the removed user)
+     * int32[2]: 0   // (Android user flags of the removed user)
+     * int32[3]: 10  // current user
+     * int32[4]: 0   // current user flags (none)
+     * int32[5]: 2   // number of users
+     * int32[6]: 0   // 1st user (user 0)
+     * int32[7]: 0   // 1st user flags (none)
+     * int32[8]: 10  // 2nd user (user 10)
+     * int32[9]: 0   // 2nd user flags (none)
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:WRITE
+     */
+    REMOVE_USER = (
+        0x0F0A
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Property used to associate (or query the association) the current user with vehicle-specific
+     * identification mechanisms (such as key FOB).
+     *
+     * This is an optional user management property - the OEM could still support user management
+     * without defining it. In fact, this property could be used without supporting the core
+     * user-related functions described on INITIAL_USER_INFO.
+     *
+     * To query the association, the Android system gets the property, passing a VehiclePropValue
+     * containing the types of associations are being queried, as defined by
+     * UserIdentificationGetRequest. The HAL must return right away, returning a VehiclePropValue
+     * with a UserIdentificationResponse. Notice that user identification should have already
+     * happened while system is booting up and the VHAL implementation should only return the
+     * already identified association (like the key FOB used to unlock the car), instead of starting
+     * a new association from the get call.
+     *
+     * To associate types, the Android system sets the property, passing a VehiclePropValue
+     * containing the types and values of associations being set, as defined by the
+     * UserIdentificationSetRequest. The HAL will then use a property change event (whose
+     * VehiclePropValue is defined by UserIdentificationResponse) indicating the current status of
+     * the types after the request.
+     *
+     * For example, to query if the current user (10) is associated with the FOB that unlocked the
+     * car and a custom mechanism provided by the OEM, the request would be:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 10  (Android user id)
+     * int32[2]: 0   (Android user flags)
+     * int32[3]: 2   (number of types queried)
+     * int32[4]: 1   (1st type queried, UserIdentificationAssociationType::KEY_FOB)
+     * int32[5]: 101 (2nd type queried, UserIdentificationAssociationType::CUSTOM_1)
+     *
+     * If the user is associated with the FOB but not with the custom mechanism, the response would
+     * be:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 2   (number of associations in the response)
+     * int32[2]: 1   (1st type: UserIdentificationAssociationType::KEY_FOB)
+     * int32[3]: 2   (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER)
+     * int32[4]: 101 (2st type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[5]: 4   (2nd value: UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER)
+     *
+     * Then to associate the user with the custom mechanism, a set request would be made:
+     *
+     * int32[0]: 43  // request id
+     * int32[1]: 10  (Android user id)
+     * int32[2]: 0   (Android user flags)
+     * int32[3]: 1   (number of associations being set)
+     * int32[4]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[5]: 1   (1st value: UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER)
+     *
+     * If the request succeeded, the response would be simply:
+     *
+     * int32[0]: 43  // request id
+     * int32[1]: 1   (number of associations in the response)
+     * int32[2]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[3]: 1   (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER)
+     *
+     * Notice that the set request adds associations, but doesn't remove the existing ones. In the
+     * example above, the end state would be 2 associations (FOB and CUSTOM_1). If we wanted to
+     * associate the user with just CUSTOM_1 but not FOB, then the request should have been:
+     *
+     * int32[0]: 43  // request id
+     * int32[1]: 10  (Android user id)
+     * int32[2]: 2   (number of types set)
+     * int32[3]: 1   (1st type: UserIdentificationAssociationType::KEY_FOB)
+     * int32[4]: 2   (1st value: UserIdentificationAssociationValue::DISASSOCIATE_CURRENT_USER)
+     * int32[5]: 101 (2nd type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[6]: 1   (2nd value: UserIdentificationAssociationValue::ASSOCIATE_CURRENT_USER)
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    USER_IDENTIFICATION_ASSOCIATION = (
+        0x0F0B
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+};
+
+/**
+ * Used by SUPPORT_CUSTOMIZE_VENDOR_PERMISSION to indicate the permission of vendor properties.
+ */
+enum VehicleVendorPermission : int32_t {
+    PERMISSION_DEFAULT = 0x00000000,
+
+    // permissions for the property related with window
+    PERMISSION_SET_VENDOR_CATEGORY_WINDOW= 0X00000001,
+    PERMISSION_GET_VENDOR_CATEGORY_WINDOW = 0x00000002,
+    // permissions for the property related with door
+    PERMISSION_SET_VENDOR_CATEGORY_DOOR  = 0x00000003,
+    PERMISSION_GET_VENDOR_CATEGORY_DOOR   = 0x00000004,
+    // permissions for the property related with seat
+    PERMISSION_SET_VENDOR_CATEGORY_SEAT  = 0x00000005,
+    PERMISSION_GET_VENDOR_CATEGORY_SEAT   = 0x00000006,
+    // permissions for the property related with mirror
+    PERMISSION_SET_VENDOR_CATEGORY_MIRROR= 0x00000007,
+    PERMISSION_GET_VENDOR_CATEGORY_MIRROR = 0x00000008,
+
+    // permissions for the property related with car's information
+    PERMISSION_SET_VENDOR_CATEGORY_INFO  = 0x00000009,
+    PERMISSION_GET_VENDOR_CATEGORY_INFO   = 0x0000000A,
+    // permissions for the property related with car's engine
+    PERMISSION_SET_VENDOR_CATEGORY_ENGINE= 0x0000000B,
+    PERMISSION_GET_VENDOR_CATEGORY_ENGINE = 0x0000000C,
+    // permissions for the property related with car's HVAC
+    PERMISSION_SET_VENDOR_CATEGORY_HVAC  = 0x0000000D,
+    PERMISSION_GET_VENDOR_CATEGORY_HVAC   = 0x0000000E,
+    // permissions for the property related with car's light
+    PERMISSION_SET_VENDOR_CATEGORY_LIGHT = 0x0000000F,
+    PERMISSION_GET_VENDOR_CATEGORY_LIGHT  = 0x00000010,
+
+    // permissions reserved for other vendor permission
+    PERMISSION_SET_VENDOR_CATEGORY_1  = 0x00010000,
+    PERMISSION_GET_VENDOR_CATEGORY_1   = 0x00011000,
+    PERMISSION_SET_VENDOR_CATEGORY_2  = 0x00020000,
+    PERMISSION_GET_VENDOR_CATEGORY_2   = 0x00021000,
+    PERMISSION_SET_VENDOR_CATEGORY_3  = 0x00030000,
+    PERMISSION_GET_VENDOR_CATEGORY_3   = 0x00031000,
+    PERMISSION_SET_VENDOR_CATEGORY_4  = 0x00040000,
+    PERMISSION_GET_VENDOR_CATEGORY_4   = 0x00041000,
+    PERMISSION_SET_VENDOR_CATEGORY_5  = 0x00050000,
+    PERMISSION_GET_VENDOR_CATEGORY_5   = 0x00051000,
+    PERMISSION_SET_VENDOR_CATEGORY_6  = 0x00060000,
+    PERMISSION_GET_VENDOR_CATEGORY_6   = 0x00061000,
+    PERMISSION_SET_VENDOR_CATEGORY_7  = 0x00070000,
+    PERMISSION_GET_VENDOR_CATEGORY_7   = 0x00071000,
+    PERMISSION_SET_VENDOR_CATEGORY_8  = 0x00080000,
+    PERMISSION_GET_VENDOR_CATEGORY_8   = 0x00081000,
+    PERMISSION_SET_VENDOR_CATEGORY_9  = 0x00090000,
+    PERMISSION_GET_VENDOR_CATEGORY_9   = 0x00091000,
+    PERMISSION_SET_VENDOR_CATEGORY_10 = 0x000A0000,
+    PERMISSION_GET_VENDOR_CATEGORY_10  = 0x000A1000,
+
+    // Indicate not available for android to access.
+    PERMISSION_NOT_ACCESSIBLE = 0xF0000000
 };
 
 /**
@@ -2458,9 +3087,19 @@
  * Bit flags for fan direction
  */
 enum VehicleHvacFanDirection : int32_t {
+    UNKNOWN = 0x0,
+
     FACE = 0x1,
     FLOOR = 0x2,
+    /**
+     * FACE_AND_FLOOR = FACE | FLOOR
+     */
+    FACE_AND_FLOOR = 0x3,
     DEFROST = 0x4,
+    /**
+     * DEFROST_AND_FLOOR = DEFROST | FLOOR
+     */
+    DEFROST_AND_FLOOR = 0x06,
 };
 
 enum VehicleOilLevel : int32_t {
@@ -2489,26 +3128,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 enum_vehicle_ap_power_state_shutdown_param_type
-     *
-     * 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,
 };
 
@@ -2531,65 +3196,89 @@
 
     /** AP can only shutdown with postponing allowed. */
     SHUTDOWN_ONLY = 3,
+
+    /**
+     * AP may enter deep sleep, but must either sleep or shut down immediately.
+     * Postponing is not allowed. */
+    SLEEP_IMMEDIATELY = 4,
 };
 
 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,
 };
@@ -2723,6 +3412,8 @@
  * Various gears which can be selected by user and chosen in system.
  */
 enum VehicleGear : int32_t {
+    GEAR_UNKNOWN = 0x0000,
+
     GEAR_NEUTRAL = 0x0001,
     GEAR_REVERSE = 0x0002,
     GEAR_PARK = 0x0004,
@@ -3542,3 +4233,560 @@
     PUBLISHER_ID = 1,
 };
 
+/**
+ * Information about a specific Android user.
+ */
+struct UserInfo {
+
+    UserId userId;
+
+    UserFlags flags;
+};
+
+/**
+ * Id of an Android user.
+ *
+ * Must be > 0 for valid ids, or -10000 (which is the same as Android.UserHandle.USER_NULL) when
+ * it's not used.
+ */
+typedef int32_t UserId;
+
+/**
+ * Flags used to define the characteristics of an Android user.
+ */
+enum UserFlags: int32_t {
+    /**
+     * No flags.
+     */
+    NONE = 0x0,
+
+    /**
+     * System user.
+     * On automotive, that user is always running, although never on foreground (except during
+     * boot or exceptional circumstances).
+     */
+    SYSTEM = 0x01,
+
+    /**
+     * Guest users have restrictions.
+     */
+    GUEST = 0x02,
+
+    /**
+     * Ephemeral users have non-persistent state.
+     */
+    EPHEMERAL = 0x04,
+
+    /**
+     * Admin users have additional privileges such as permission to create other users.
+     */
+    ADMIN = 0x08,
+
+    /**
+     * Disabled users are marked for deletion.
+     */
+    DISABLED = 0x10,
+
+     /**
+     * Profile user is a profile of another user.
+     */
+    PROFILE = 0x20,
+};
+
+/**
+ * Information about all Android users.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it's part of other structs, which
+ * in turn are converted to a VehiclePropValue.RawValue through libraries provided by the default
+ * Vehicle HAL implementation.
+ */
+struct UsersInfo {
+
+    /** The current foreground user. */
+    UserInfo currentUser;
+
+    /**
+     * Number of existing users; includes the current user, recently removed users (with DISABLED
+     * flag), and profile users (with PROFILE flag).
+     */
+    int32_t numberUsers;
+
+    /**
+     * List of existing users; includes the current user, recently removed users (with DISABLED
+     * flag), and profile users (with PROFILE flag).
+     */
+    vec<UserInfo> existingUsers;
+ };
+
+/**
+ * Id of a request related to user management.
+ *
+ * This id can be used by the Android system to map responses sent by the HAL, and vice-versa.
+ *
+ * For requests originated by Android, the value is positive (> 0), while for requests originated by
+ * the HAL it must be negative (< 0).
+ */
+typedef int32_t UserRequestId;
+
+/**
+ * Defines the format of a INITIAL_USER_INFO request made by the Android system.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct InitialUserInfoRequest {
+    /**
+     * Arbitrary id used to map the HAL response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Type of request.
+     */
+    InitialUserInfoRequestType requestType;
+
+    /**
+     * Information about the current state of the Android system.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+ * Defines when a INITIAL_USER_INFO request was made.
+ */
+enum InitialUserInfoRequestType : int32_t {
+  /** At the first time Android was booted (or after a factory reset). */
+  FIRST_BOOT = 1,
+
+  /** At the first time Android was booted after the system was updated. */
+  FIRST_BOOT_AFTER_OTA = 2,
+
+  /** When Android was booted "from scratch". */
+  COLD_BOOT = 3,
+
+  /** When Android was resumed after the system was suspended to memory. */
+  RESUME = 4,
+};
+
+/**
+ * Defines the format of a HAL response to a INITIAL_USER_INFO request.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct InitialUserInfoResponse {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * which action the Android system should take.
+     */
+    InitialUserInfoResponseAction action;
+
+    /**
+     * Information about the user that should be switched to or created.
+     */
+    UserInfo userToSwitchOrCreate;
+
+    /**
+     * System locales of the initial user (value will be passed as-is to
+     * android.provider.Settings.System.SYSTEM_LOCALES)
+     */
+    string userLocales;
+
+    /**
+     * Name of the user that should be created.
+     */
+    string userNameToCreate;
+};
+
+/**
+ * Defines which action the Android system should take in an INITIAL_USER_INFO request.
+ */
+enum InitialUserInfoResponseAction : int32_t {
+   /**
+    * Let the Android System decide what to do.
+    *
+    * For example, it might create a new user on first boot, and switch to the last
+    * active user afterwards.
+    */
+   DEFAULT = 0,
+
+   /**
+    * Switch to an existing Android user.
+    */
+   SWITCH = 1,
+
+   /**
+    * Create a new Android user (and switch to it).
+    */
+   CREATE = 2,
+};
+
+/**
+ * Defines the format of a SWITCH_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct SwitchUserRequest {
+    /**
+     * Arbitrary id used to map the response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Type of message.
+     */
+    SwitchUserMessageType messageType;
+
+    /**
+     * Information about the Android user being switched to.
+     *
+     * Only the user id (but not the flags) should be set when the request is made by HAL.
+     */
+    UserInfo targetUser;
+
+    /**
+     * Information about the current state of the Android system.
+     *
+     * Should not be set when the request is made by HAL.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+ * Defines the reason a SWITCH_USER call was made.
+ *
+ * The meaning of each constant is explained in that property.
+ */
+enum SwitchUserMessageType: int32_t {
+   LEGACY_ANDROID_SWITCH = 1,
+   ANDROID_SWITCH = 2,
+   VEHICLE_RESPONSE = 3,
+   VEHICLE_REQUEST = 4,
+   ANDROID_POST_SWITCH = 5,
+};
+
+/**
+ * Defines the result of a SwitchUserRequest.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct SwitchUserResponse {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Type of message.
+     */
+    SwitchUserMessageType messageType;
+
+    /**
+     * Status of the request.
+     */
+    SwitchUserStatus status;
+
+    /**
+     * HAL-specific error message.
+     *
+     * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be
+     * used to show custom error messages to the end user.
+     */
+    string errorMessage;
+};
+
+/**
+ * Status of the response to a SwitchUserRequest.
+ */
+enum SwitchUserStatus : int32_t {
+   /** The request succeeded and the HAL user was switched. */
+   SUCCESS = 1,
+   /** The request failed and the HAL user remained the same. */
+   FAILURE = 2,
+};
+
+/**
+ * Defines the format of a CREATE_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct CreateUserRequest {
+    /**
+     * Arbitrary id used to map the response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Basic information about Android user that was created.
+     */
+    UserInfo newUserInfo;
+
+    /**
+     * Name of the new Android user.
+     */
+     string newUserName;
+
+    /**
+     * Information about the current state of the Android system.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+ * Defines the result of a CreateUserRequest.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct CreateUserResponse {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Status of the request.
+     */
+    CreateUserStatus status;
+
+    /**
+     * HAL-specific error message.
+     *
+     * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be
+     * used to show custom error messages to the end user.
+     */
+    string errorMessage;
+};
+
+/**
+ * Status of the response to a CreateUserRequest.
+ */
+enum CreateUserStatus : int32_t {
+   /**
+    * The request succeeded (for example, HAL created a new internal user, or associated the
+    * Android user to an existing internal user).
+    */
+   SUCCESS = 1,
+
+   /**
+     * The request failed (and Android will remove the Android user).
+     */
+   FAILURE = 2,
+};
+
+/**
+ * Defines the format of a REMOVE_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct RemoveUserRequest {
+    /**
+     * Arbitrary id used to map the response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Information about the Android user that was removed.
+     */
+    UserInfo removedUserInfo;
+
+    /**
+     * Information about the current state of the Android system.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+  * Types of mechanisms used to identify an Android user.
+  *
+  * See USER_IDENTIFICATION_ASSOCIATION for more details and example.
+  */
+enum UserIdentificationAssociationType: int32_t {
+   /** Key used to unlock the car. */
+   KEY_FOB = 1,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_1 = 101,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_2 = 102,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_3 = 103,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_4 = 104,
+};
+
+/**
+ * Whether a UserIdentificationAssociationType is associate with an Android user.
+ */
+enum UserIdentificationAssociationValue : int32_t {
+   /**
+    * Used when the status of an association could not be determined.
+    *
+    * For example, in a set() request, it would indicate a failure to set the given type.
+    */
+   UNKNOWN = 1,
+
+   /**
+    * The identification type is associated with the current foreground Android user.
+    */
+   ASSOCIATED_CURRENT_USER = 2,
+
+   /**
+    * The identification type is associated with another Android user.
+    */
+   ASSOCIATED_ANOTHER_USER = 3,
+
+   /**
+    * The identification type is not associated with any Android user.
+    */
+   NOT_ASSOCIATED_ANY_USER = 4,
+};
+
+/**
+ * Used to set a UserIdentificationAssociationType with an Android user.
+ */
+enum UserIdentificationAssociationSetValue : int32_t {
+   /**
+    * Associate the identification type with the current foreground Android user.
+    */
+   ASSOCIATE_CURRENT_USER = 1,
+
+   /**
+    * Disassociate the identification type from the current foreground Android user.
+    */
+   DISASSOCIATE_CURRENT_USER = 2,
+
+   /**
+    * Disassociate the identification type from all Android users.
+    */
+   DISASSOCIATE_ALL_USERS = 3,
+};
+
+/**
+ * Defines the format of a get() call to USER_IDENTIFICATION_ASSOCIATION.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct UserIdentificationGetRequest {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Information about the current foreground Android user.
+     */
+    UserInfo userInfo;
+
+    /**
+     * Number of association being queried.
+     */
+    int32_t numberAssociationTypes;
+
+    /**
+     * Types of association being queried.
+     */
+    vec<UserIdentificationAssociationType> associationTypes;
+};
+
+/**
+ * Defines the format of a set() call to USER_IDENTIFICATION_ASSOCIATION.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct UserIdentificationSetRequest {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Information about the current foreground Android user.
+     */
+    UserInfo userInfo;
+
+    /**
+     * Number of association being set.
+     */
+    int32_t numberAssociations;
+
+    /**
+     * Associations being set.
+     */
+    vec<UserIdentificationSetAssociation> associations;
+};
+
+/**
+ * Defines the result of a USER_IDENTIFICATION_ASSOCIATION - both for get() and set().
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct UserIdentificationResponse {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Number of associations being returned.
+     */
+    int32_t numberAssociation;
+
+    /**
+     * Values associated with the user.
+     */
+    vec<UserIdentificationAssociation> associations;
+
+    /**
+     * HAL-specific error message.
+     *
+     * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be
+     * used to show custom error messages to the end user.
+     */
+    string errorMessage;
+};
+
+/**
+ * Helper struct used when getting a user/identification association type.
+ */
+struct UserIdentificationAssociation {
+
+    UserIdentificationAssociationType type;
+
+    UserIdentificationAssociationValue value;
+};
+
+/**
+ * Helper struct used when setting a user/identification association type.
+ */
+struct UserIdentificationSetAssociation {
+
+    UserIdentificationAssociationType type;
+
+    UserIdentificationAssociationSetValue value;
+};
+
+/**
+ * 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/biometrics/face/1.0/default/Android.bp b/biometrics/face/1.0/default/Android.bp
new file mode 100644
index 0000000..d6ff087
--- /dev/null
+++ b/biometrics/face/1.0/default/Android.bp
@@ -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.
+ */
+
+cc_binary {
+    name: "android.hardware.biometrics.face@1.0-service.example",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    init_rc: ["android.hardware.biometrics.face@1.0-service.rc"],
+    vintf_fragments: ["manifest_face_default.xml"],
+    relative_install_path: "hw",
+    proprietary: true,
+    srcs: [
+        "BiometricsFace.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libutils",
+        "liblog",
+        "android.hardware.biometrics.face@1.0",
+    ],
+}
diff --git a/biometrics/face/1.0/default/BiometricsFace.cpp b/biometrics/face/1.0/default/BiometricsFace.cpp
new file mode 100644
index 0000000..2dd6476
--- /dev/null
+++ b/biometrics/face/1.0/default/BiometricsFace.cpp
@@ -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.
+ */
+
+#include "BiometricsFace.h"
+
+namespace android::hardware::biometrics::face::implementation {
+using android::hardware::biometrics::face::V1_0::FaceError;
+using android::hardware::biometrics::face::V1_0::OptionalUint64;
+
+// Arbitrary value.
+constexpr uint64_t kDeviceId = 123;
+// Arbitrary value.
+constexpr uint64_t kAuthenticatorId = 987;
+// Arbitrary value.
+constexpr uint64_t kLockoutDuration = 555;
+
+BiometricsFace::BiometricsFace() : mRandom(std::mt19937::default_seed) {}
+
+// Methods from IBiometricsFace follow.
+Return<void> BiometricsFace::setCallback(const sp<IBiometricsFaceClientCallback>& clientCallback,
+                                         setCallback_cb _hidl_cb) {
+    mClientCallback = clientCallback;
+    _hidl_cb({Status::OK, kDeviceId});
+    return Void();
+}
+
+Return<Status> BiometricsFace::setActiveUser(int32_t userId, const hidl_string& storePath) {
+    if (userId < 0 || storePath.empty() || std::string(storePath).find("/data") != 0) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+    mUserId = userId;
+    mClientCallback->onLockoutChanged(kLockoutDuration);
+    return Status::OK;
+}
+
+Return<void> BiometricsFace::generateChallenge(uint32_t /* challengeTimeoutSec */,
+                                               generateChallenge_cb _hidl_cb) {
+    std::uniform_int_distribution<uint64_t> dist;
+    _hidl_cb({Status::OK, dist(mRandom)});
+    return Void();
+}
+
+Return<Status> BiometricsFace::enroll(const hidl_vec<uint8_t>& /* hat */, uint32_t /* timeoutSec */,
+                                      const hidl_vec<Feature>& /* disabledFeatures */) {
+    // hat can never be valid in this implementation.
+    mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+    return Status::OK;
+}
+
+Return<Status> BiometricsFace::revokeChallenge() {
+    return Status::OK;
+}
+
+Return<Status> BiometricsFace::setFeature(Feature /* feature */, bool /* enabled */,
+                                          const hidl_vec<uint8_t>& /* hat */,
+                                          uint32_t /* faceId */) {
+    // hat can never be valid in this implementation.
+    return Status::ILLEGAL_ARGUMENT;
+}
+
+Return<void> BiometricsFace::getFeature(Feature /* feature */, uint32_t /* faceId */,
+                                        getFeature_cb _hidl_cb) {
+    // hat can never be valid in this implementation.
+    _hidl_cb({Status::ILLEGAL_ARGUMENT, false});
+    return Void();
+}
+
+Return<void> BiometricsFace::getAuthenticatorId(getAuthenticatorId_cb _hidl_cb) {
+    _hidl_cb({Status::OK, kAuthenticatorId});
+    return Void();
+}
+
+Return<Status> BiometricsFace::cancel() {
+    mClientCallback->onError(kDeviceId, mUserId, FaceError::CANCELED, 0 /* vendorCode */);
+    return Status::OK;
+}
+
+Return<Status> BiometricsFace::enumerate() {
+    mClientCallback->onEnumerate(kDeviceId, {}, mUserId);
+    return Status::OK;
+}
+
+Return<Status> BiometricsFace::remove(uint32_t /* faceId */) {
+    return Status::OK;
+}
+
+Return<Status> BiometricsFace::authenticate(uint64_t /* operationId */) {
+    mClientCallback->onError(kDeviceId, mUserId, FaceError::HW_UNAVAILABLE, 0 /* vendorCode */);
+    return Status::OK;
+}
+
+Return<Status> BiometricsFace::userActivity() {
+    return Status::OK;
+}
+
+Return<Status> BiometricsFace::resetLockout(const hidl_vec<uint8_t>& /* hat */) {
+    return Status::OK;
+}
+
+}  // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.0/default/BiometricsFace.h b/biometrics/face/1.0/default/BiometricsFace.h
new file mode 100644
index 0000000..1d99ed2
--- /dev/null
+++ b/biometrics/face/1.0/default/BiometricsFace.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <random>
+
+namespace android::hardware::biometrics::face::implementation {
+
+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;
+using ::android::hardware::biometrics::face::V1_0::Feature;
+using ::android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
+using ::android::hardware::biometrics::face::V1_0::Status;
+
+class BiometricsFace : public V1_0::IBiometricsFace {
+  public:
+    BiometricsFace();
+
+    // Methods from ::android::hardware::biometrics::face::V1_0::IBiometricsFace follow.
+    Return<void> setCallback(const sp<IBiometricsFaceClientCallback>& clientCallback,
+                             setCallback_cb _hidl_cb) override;
+
+    Return<Status> setActiveUser(int32_t userId, const hidl_string& storePath) override;
+
+    Return<void> generateChallenge(uint32_t challengeTimeoutSec,
+                                   generateChallenge_cb _hidl_cb) override;
+
+    Return<Status> enroll(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+                          const hidl_vec<Feature>& disabledFeatures) override;
+
+    Return<Status> revokeChallenge() override;
+
+    Return<Status> setFeature(Feature feature, bool enabled, const hidl_vec<uint8_t>& hat,
+                              uint32_t faceId) override;
+
+    Return<void> getFeature(Feature feature, uint32_t faceId, getFeature_cb _hidl_cb) override;
+
+    Return<void> getAuthenticatorId(getAuthenticatorId_cb _hidl_cb) override;
+
+    Return<Status> cancel() override;
+
+    Return<Status> enumerate() override;
+
+    Return<Status> remove(uint32_t faceId) override;
+
+    Return<Status> authenticate(uint64_t operationId) override;
+
+    Return<Status> userActivity() override;
+
+    Return<Status> resetLockout(const hidl_vec<uint8_t>& hat) override;
+
+  private:
+    std::mt19937 mRandom;
+    int32_t mUserId;
+    sp<IBiometricsFaceClientCallback> mClientCallback;
+};
+
+}  // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc b/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
new file mode 100644
index 0000000..6c7362f
--- /dev/null
+++ b/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
@@ -0,0 +1,10 @@
+service vendor.face-hal-1-0-default /vendor/bin/hw/android.hardware.biometrics.face@1.0-service.example
+    # "class hal" causes a race condition on some devices due to files created
+    # in /data. As a workaround, postpone startup until later in boot once
+    # /data is mounted.
+    class late_start
+    user system
+    group system
+    writepid /dev/cpuset/foreground/tasks
+    capabilities SYS_NICE
+    rlimit rtprio 10 10
diff --git a/biometrics/face/1.0/default/manifest_face_default.xml b/biometrics/face/1.0/default/manifest_face_default.xml
new file mode 100644
index 0000000..380ae49
--- /dev/null
+++ b/biometrics/face/1.0/default/manifest_face_default.xml
@@ -0,0 +1,11 @@
+<manifest version="2.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.biometrics.face</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IBiometricsFace</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/biometrics/face/1.0/default/service.cpp b/biometrics/face/1.0/default/service.cpp
new file mode 100644
index 0000000..9818c95
--- /dev/null
+++ b/biometrics/face/1.0/default/service.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.biometrics.face@1.0-service"
+
+#include <android/hardware/biometrics/face/1.0/types.h>
+#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
+#include <android/log.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include "BiometricsFace.h"
+
+using android::sp;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::biometrics::face::implementation::BiometricsFace;
+using android::hardware::biometrics::face::V1_0::IBiometricsFace;
+
+int main() {
+    ALOGI("BiometricsFace HAL is being started.");
+
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    android::sp<IBiometricsFace> face = new BiometricsFace();
+    const android::status_t status = face->registerAsService();
+
+    if (status != android::OK) {
+        ALOGE("Error starting the BiometricsFace HAL.");
+        return 1;
+    }
+
+    ALOGI("BiometricsFace HAL has started successfully.");
+    joinRpcThreadpool();
+
+    ALOGI("BiometricsFace HAL is terminating.");
+    return 1;  // should never get here
+}
diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
index c21d0a6..379f37f 100644
--- a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
+++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
@@ -28,6 +28,7 @@
 #include <chrono>
 #include <cstdint>
 #include <random>
+#include <thread>
 
 using android::sp;
 using android::hardware::hidl_vec;
@@ -144,7 +145,10 @@
         ASSERT_EQ(Status::OK, static_cast<Status>(ret2));
     }
 
-    void TearDown() override {}
+    void TearDown() override {
+        // Hack to allow the asynchronous operations to finish on time.
+        std::this_thread::sleep_for(std::chrono::milliseconds(250));
+    }
 
     sp<IBiometricsFace> mService;
     sp<FaceCallback> mCallback;
diff --git a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
index c4cb356..b928314 100644
--- a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
+++ b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
@@ -49,7 +49,7 @@
 static const std::chrono::seconds kTimeoutInSeconds = std::chrono::seconds(kTimeout);
 static const uint32_t kGroupId = 99;
 static std::string kTmpDir = "";
-static const uint32_t kIterations = 1000;
+static const uint32_t kIterations = 10;
 
 // 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
diff --git a/biometrics/fingerprint/2.2/Android.bp b/biometrics/fingerprint/2.2/Android.bp
new file mode 100644
index 0000000..a8f202c
--- /dev/null
+++ b/biometrics/fingerprint/2.2/Android.bp
@@ -0,0 +1,16 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.biometrics.fingerprint@2.2",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IBiometricsFingerprint.hal",
+        "IBiometricsFingerprintClientCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.biometrics.fingerprint@2.1",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal
new file mode 100644
index 0000000..249830a
--- /dev/null
+++ b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal
@@ -0,0 +1,28 @@
+/*
+ * 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.biometrics.fingerprint@2.2;
+
+import @2.1::IBiometricsFingerprint;
+
+/**
+ * The HAL interface for biometric fingerprint authentication.
+ *
+ * This interface is required because all top-level interfaces need to be
+ * updated in a minor uprev.
+ */
+interface IBiometricsFingerprint extends @2.1::IBiometricsFingerprint {
+};
diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal
new file mode 100644
index 0000000..14c2b12
--- /dev/null
+++ b/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.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.biometrics.fingerprint@2.2;
+
+import @2.1::IBiometricsFingerprintClientCallback;
+
+/*
+ * This HAL interface communicates asynchronous results from the
+ * fingerprint driver in response to user actions on the fingerprint sensor
+ */
+interface IBiometricsFingerprintClientCallback extends @2.1::IBiometricsFingerprintClientCallback {
+    /**
+     * Sent when a fingerprint image is acquired by the sensor
+     * @param deviceId the instance of this fingerprint device
+     * @param acquiredInfo a message about the quality of the acquired image
+     * @param vendorCode a vendor-specific message about the quality of the image. Only
+     *        valid when acquiredInfo == ACQUIRED_VENDOR
+     */
+    oneway onAcquired_2_2(uint64_t deviceId, FingerprintAcquiredInfo acquiredInfo,
+        int32_t vendorCode);
+};
diff --git a/biometrics/fingerprint/2.2/types.hal b/biometrics/fingerprint/2.2/types.hal
new file mode 100644
index 0000000..2c1d3f3
--- /dev/null
+++ b/biometrics/fingerprint/2.2/types.hal
@@ -0,0 +1,42 @@
+/*
+ * 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.biometrics.fingerprint@2.2;
+
+import @2.1::FingerprintAcquiredInfo;
+
+/**
+ * Fingerprint acquisition info is meant as feedback for the current operation.
+ * Anything but START and ACQUIRED_GOOD must be shown to the user as feedback on
+ * how to take action on the current operation. For example,
+ * ACQUIRED_IMAGER_DIRTY may be used to tell the user to clean the sensor if it
+ * is detected to be dirty.
+ * If this causes the current operation to fail, an additional ERROR_CANCELED
+ * must be sent to stop the operation in progress (e.g. enrollment).
+ * In general, these messages will result in a "Try again" message.
+ */
+enum FingerprintAcquiredInfo : @2.1::FingerprintAcquiredInfo {
+    /**
+     * This message represents the earliest message sent at the beginning of the
+     * authentication pipeline. It is expected to be used to measure latency. For
+     * example, in a camera-based authentication system it's expected to be sent
+     * prior to camera initialization. Note this should be sent whenever
+     * authentication is restarted (see IBiometricsFace#userActivity).
+     * The framework will measure latency based on the time between the last START
+     * message and the onAuthenticated callback.
+     */
+    START = 7,
+};
diff --git a/biometrics/fingerprint/2.2/vts/functional/Android.bp b/biometrics/fingerprint/2.2/vts/functional/Android.bp
new file mode 100644
index 0000000..496570c
--- /dev/null
+++ b/biometrics/fingerprint/2.2/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+    name: "VtsHalBiometricsFingerprintV2_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBiometricsFingerprintV2_2TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.biometrics.fingerprint@2.1",
+        "android.hardware.biometrics.fingerprint@2.2",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
new file mode 100644
index 0000000..df29fd4
--- /dev/null
+++ b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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 "fingerprint_hidl_hal_test"
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/properties.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
+#include <android/hardware/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+#include <cinttypes>
+
+namespace {
+
+namespace hidl_interface = android::hardware::biometrics::fingerprint::V2_1;
+namespace hidl_interface_2_2 = android::hardware::biometrics::fingerprint::V2_2;
+
+using hidl_interface::FingerprintError;
+using hidl_interface::IBiometricsFingerprint;
+using hidl_interface::RequestStatus;
+
+using android::sp;
+using android::base::GetUintProperty;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr uint32_t kGroupId = 99;
+constexpr char kCallbackNameOnAcquired[] = "onAcquired";
+
+// Callback arguments that need to be captured for the tests.
+struct FingerprintCallbackArgs {
+    // The info passed to the last onAcquired() callback.
+    hidl_interface_2_2::FingerprintAcquiredInfo info;
+};
+
+// Test callback class for the BiometricsFingerprint HAL.
+// The HAL will call these callback methods to notify about completed operations
+// or encountered errors.
+class FingerprintCallback : public ::testing::VtsHalHidlTargetCallbackBase<FingerprintCallbackArgs>,
+                            public hidl_interface_2_2::IBiometricsFingerprintClientCallback {
+  public:
+    Return<void> onEnrollResult(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+
+    Return<void> onAcquired(uint64_t, hidl_interface::FingerprintAcquiredInfo, int32_t) override {
+        return Void();
+    }
+
+    Return<void> onAcquired_2_2(uint64_t, hidl_interface_2_2::FingerprintAcquiredInfo info,
+                                int32_t) override {
+        FingerprintCallbackArgs args = {};
+        args.info = info;
+        NotifyFromCallback(kCallbackNameOnAcquired, args);
+        return Void();
+    }
+
+    Return<void> onAuthenticated(uint64_t, uint32_t, uint32_t, const hidl_vec<uint8_t>&) override {
+        return Void();
+    }
+
+    Return<void> onError(uint64_t, FingerprintError, int32_t) override { return Void(); }
+
+    Return<void> onRemoved(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+
+    Return<void> onEnumerate(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+};
+
+class FingerprintHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        mService = IBiometricsFingerprint::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        mCallback = new FingerprintCallback();
+        mCallback->SetWaitTimeoutDefault(kTimeout);
+        Return<uint64_t> ret1 = mService->setNotify(mCallback);
+        ASSERT_NE(0UL, static_cast<uint64_t>(ret1));
+
+        /*
+         * Devices shipped from now on will instead store
+         * fingerprint data under /data/vendor_de/<user-id>/fpdata.
+         * Support for /data/vendor_de and /data/vendor_ce has been added to vold.
+         */
+
+        auto api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+        if (api_level == 0) {
+            api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+        }
+        ASSERT_NE(api_level, 0);
+
+        // 27 is the API number for O-MR1
+        string tmpDir;
+        if (api_level <= 27) {
+            tmpDir = "/data/system/users/0/fpdata/";
+        } else {
+            tmpDir = "/data/vendor_de/0/fpdata/";
+        }
+
+        Return<RequestStatus> res = mService->setActiveGroup(kGroupId, tmpDir);
+        ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+    }
+
+    sp<IBiometricsFingerprint> mService;
+    sp<FingerprintCallback> mCallback;
+};
+
+// The START message and onAcquired_2_2 method should exist and work together correctly.
+// Note, this test doesn't use the HAL. It just makes sure that the newly added constant and
+// callback compile. Unfortunately, there is no way to test the usage of the constant within the
+// actual HAL.
+TEST_P(FingerprintHidlTest, acquiredInfoStartTest) {
+    mCallback->SetWaitTimeoutDefault(kTimeout);
+    mCallback->onAcquired_2_2(0 /* deviceId */, hidl_interface_2_2::FingerprintAcquiredInfo::START,
+                              0 /* vendorCode */);
+    auto res = mCallback->WaitForCallback(kCallbackNameOnAcquired);
+    ASSERT_EQ(hidl_interface_2_2::FingerprintAcquiredInfo::START, res.args->info);
+}
+
+}  // anonymous namespace
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IBiometricsFingerprint::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/bluetooth/1.0/vts/functional/Android.bp b/bluetooth/1.0/vts/functional/Android.bp
index 463ed84..e9f867f 100644
--- a/bluetooth/1.0/vts/functional/Android.bp
+++ b/bluetooth/1.0/vts/functional/Android.bp
@@ -26,4 +26,5 @@
         "general-tests",
         "vts",
     ],
+    disable_framework: true,
 }
diff --git a/boot/1.1/vts/functional/Android.bp b/boot/1.1/vts/functional/Android.bp
index 49ea09a..9f0c74a 100644
--- a/boot/1.1/vts/functional/Android.bp
+++ b/boot/1.1/vts/functional/Android.bp
@@ -23,6 +23,8 @@
         "android.hardware.boot@1.1",
         "libgmock",
     ],
-    test_suites: ["device-tests"],
+    test_suites: [
+        "device-tests",
+        "vts",
+    ],
 }
-
diff --git a/broadcastradio/1.0/vts/functional/Android.bp b/broadcastradio/1.0/vts/functional/Android.bp
index 9ba9fbe..2a4f942 100644
--- a/broadcastradio/1.0/vts/functional/Android.bp
+++ b/broadcastradio/1.0/vts/functional/Android.bp
@@ -22,5 +22,8 @@
         "android.hardware.broadcastradio@1.0",
         "android.hardware.broadcastradio@vts-utils-lib",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
index 90c8463..9897ab7 100644
--- a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
+++ b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
@@ -15,11 +15,13 @@
  */
 
 #define LOG_TAG "BroadcastRadioHidlHalTest"
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
 #include <utils/threads.h>
 
 #include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
@@ -27,28 +29,28 @@
 #include <android/hardware/broadcastradio/1.0/ITuner.h>
 #include <android/hardware/broadcastradio/1.0/ITunerCallback.h>
 #include <android/hardware/broadcastradio/1.0/types.h>
-#include <broadcastradio-vts-utils/environment-utils.h>
+#include <broadcastradio-vts-utils/hal-1.x-enum-utils.h>
 
-using ::android::sp;
-using ::android::Mutex;
 using ::android::Condition;
+using ::android::Mutex;
+using ::android::sp;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
-using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
-using ::android::hardware::broadcastradio::V1_0::ITuner;
-using ::android::hardware::broadcastradio::V1_0::ITunerCallback;
-using ::android::hardware::broadcastradio::V1_0::Result;
-using ::android::hardware::broadcastradio::V1_0::Class;
-using ::android::hardware::broadcastradio::V1_0::Properties;
 using ::android::hardware::broadcastradio::V1_0::Band;
 using ::android::hardware::broadcastradio::V1_0::BandConfig;
+using ::android::hardware::broadcastradio::V1_0::Class;
 using ::android::hardware::broadcastradio::V1_0::Direction;
-using ::android::hardware::broadcastradio::V1_0::ProgramInfo;
+using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
+using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
+using ::android::hardware::broadcastradio::V1_0::ITuner;
+using ::android::hardware::broadcastradio::V1_0::ITunerCallback;
 using ::android::hardware::broadcastradio::V1_0::MetaData;
 using ::android::hardware::broadcastradio::V1_0::MetadataKey;
 using ::android::hardware::broadcastradio::V1_0::MetadataType;
-using ::android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment;
+using ::android::hardware::broadcastradio::V1_0::ProgramInfo;
+using ::android::hardware::broadcastradio::V1_0::Properties;
+using ::android::hardware::broadcastradio::V1_0::Result;
+using ::android::hardware::broadcastradio::V1_0::vts::RadioClassFromString;
 
 #define RETURN_IF_SKIPPED \
     if (skipped) { \
@@ -56,19 +58,19 @@
         return; \
     }
 
-static BroadcastRadioHidlEnvironment<IBroadcastRadioFactory>* gEnv = nullptr;
 // The main test class for Broadcast Radio HIDL HAL.
-class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase,
-        public ::testing::WithParamInterface<Class> {
- protected:
+class BroadcastRadioHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+  protected:
     virtual void SetUp() override {
         ASSERT_EQ(nullptr, mRadio.get());
 
-        radioClass = GetParam();
+        radioClass = RadioClassFromString(std::get<1>(GetParam()));
+
         skipped = false;
 
         sp<IBroadcastRadioFactory> factory =
-            getService<IBroadcastRadioFactory>(gEnv->getServiceName<IBroadcastRadioFactory>());
+                IBroadcastRadioFactory::getService(std::get<0>(GetParam()));
         ASSERT_NE(nullptr, factory.get());
 
         Result connectResult;
@@ -727,16 +729,8 @@
 }
 
 INSTANTIATE_TEST_CASE_P(
-    BroadcastRadioHidlTestCases,
-    BroadcastRadioHidlTest,
-    ::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
-
-int main(int argc, char** argv) {
-    gEnv = new BroadcastRadioHidlEnvironment<IBroadcastRadioFactory>;
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+        PerInstance, BroadcastRadioHidlTest,
+        testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IBroadcastRadioFactory::descriptor)),
+                         ::testing::Values("AM_FM", "SAT", "DT")),
+        android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp
index 0a02a69..661439a 100644
--- a/broadcastradio/1.1/vts/functional/Android.bp
+++ b/broadcastradio/1.1/vts/functional/Android.bp
@@ -25,5 +25,8 @@
         "android.hardware.broadcastradio@vts-utils-lib",
         "libgmock",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
index 6687731..4833beb 100644
--- a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
+++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -16,7 +16,6 @@
 
 #define LOG_TAG "broadcastradio.vts"
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
@@ -25,13 +24,16 @@
 #include <android/hardware/broadcastradio/1.1/types.h>
 #include <broadcastradio-utils-1x/Utils.h>
 #include <broadcastradio-vts-utils/call-barrier.h>
-#include <broadcastradio-vts-utils/environment-utils.h>
+#include <broadcastradio-vts-utils/hal-1.x-enum-utils.h>
 #include <broadcastradio-vts-utils/mock-timeout.h>
 #include <broadcastradio-vts-utils/pointer-utils.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
 #include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
 #include <utils/threads.h>
 
 #include <chrono>
@@ -51,6 +53,7 @@
 using testing::Invoke;
 using testing::SaveArg;
 
+using broadcastradio::V1_0::vts::RadioClassFromString;
 using broadcastradio::vts::CallBarrier;
 using V1_0::BandConfig;
 using V1_0::Class;
@@ -59,7 +62,6 @@
 using V1_0::MetadataType;
 
 using broadcastradio::vts::clearAndWait;
-using broadcastradio::vts::BroadcastRadioHidlEnvironment;
 
 static constexpr auto kConfigTimeout = 10s;
 static constexpr auto kConnectModuleTimeout = 1s;
@@ -93,11 +95,9 @@
     MOCK_TIMEOUT_METHOD1(currentProgramInfoChanged, Return<void>(const ProgramInfo&));
 };
 
-static BroadcastRadioHidlEnvironment<IBroadcastRadioFactory>* gEnv = nullptr;
-
-class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase,
-                              public ::testing::WithParamInterface<Class> {
-   protected:
+class BroadcastRadioHalTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+  protected:
     virtual void SetUp() override;
     virtual void TearDown() override;
 
@@ -120,11 +120,10 @@
 };
 
 void BroadcastRadioHalTest::SetUp() {
-    radioClass = GetParam();
+    radioClass = RadioClassFromString(std::get<1>(GetParam()));
 
     // lookup HIDL service
-    auto factory =
-        getService<IBroadcastRadioFactory>(gEnv->getServiceName<IBroadcastRadioFactory>());
+    auto factory = IBroadcastRadioFactory::getService(std::get<0>(GetParam()));
     ASSERT_NE(nullptr, factory.get());
 
     // connect radio module
@@ -601,24 +600,15 @@
     } while (nextBand());
 }
 
-INSTANTIATE_TEST_CASE_P(BroadcastRadioHalTestCases, BroadcastRadioHalTest,
-                        ::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
+INSTANTIATE_TEST_CASE_P(
+        PerInstance, BroadcastRadioHalTest,
+        testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IBroadcastRadioFactory::descriptor)),
+                         ::testing::Values("AM_FM", "SAT", "DT")),
+        android::hardware::PrintInstanceTupleNameToString<>);
 
 }  // namespace vts
 }  // namespace V1_1
 }  // namespace broadcastradio
 }  // namespace hardware
 }  // namespace android
-
-int main(int argc, char** argv) {
-    using android::hardware::broadcastradio::V1_1::vts::gEnv;
-    using android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory;
-    using android::hardware::broadcastradio::vts::BroadcastRadioHidlEnvironment;
-    gEnv = new BroadcastRadioHidlEnvironment<IBroadcastRadioFactory>;
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
diff --git a/broadcastradio/common/vts/utils/Android.bp b/broadcastradio/common/vts/utils/Android.bp
index d3edc76..24fea0b 100644
--- a/broadcastradio/common/vts/utils/Android.bp
+++ b/broadcastradio/common/vts/utils/Android.bp
@@ -25,8 +25,5 @@
         "-Wextra",
         "-Werror",
     ],
-    static_libs: [
-        "VtsHalHidlTargetTestBase",
-    ],
     group_static_libs: true,
 }
diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/environment-utils.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/environment-utils.h
deleted file mode 100644
index 274e632..0000000
--- a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/environment-utils.h
+++ /dev/null
@@ -1,41 +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_BROADCASTRADIO_VTS_ENVIRONMENT_UTILS
-#define ANDROID_HARDWARE_BROADCASTRADIO_VTS_ENVIRONMENT_UTILS
-
-#include <VtsHalHidlTargetTestEnvBase.h>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace vts {
-
-// Test environment for BroadcastRadio HIDL HAL.
-template <typename... T>
-class BroadcastRadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    virtual void registerTestServices() override {
-        using expander = int[];
-        (void)expander{0, (registerTestService<T>(), 0)...};
-    }
-};
-
-}  // namespace vts
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_VTS_ENVIRONMENT_UTILS
diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/hal-1.x-enum-utils.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/hal-1.x-enum-utils.h
new file mode 100644
index 0000000..6059ef8
--- /dev/null
+++ b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/hal-1.x-enum-utils.h
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+namespace android::hardware::broadcastradio::V1_0::vts {
+
+using android::hardware::broadcastradio::V1_0::Class;
+
+/**
+ * Convert a string of Class name to its enum value. Fail the test if the enum
+ * value is not found.
+ *
+ * @param className string value of a Class enum.
+ * @return Class enum that matches the string value.
+ */
+Class RadioClassFromString(std::string className) {
+    if (className == "AM_FM") return Class::AM_FM;
+    if (className == "SAT") return Class::SAT;
+    if (className == "DT") return Class::DT;
+    // Fail the test run.
+    CHECK(false) << "Class name not found: " << className;
+    // Return some arbitrary enum.
+    return Class::AM_FM;
+}
+}  // namespace android::hardware::broadcastradio::V1_0::vts
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
index 3e5c6d7..3b8b239 100644
--- a/camera/common/1.0/default/Android.bp
+++ b/camera/common/1.0/default/Android.bp
@@ -8,7 +8,7 @@
         "CameraParameters.cpp",
         "VendorTagDescriptor.cpp",
         "HandleImporter.cpp",
-        "Exif.cpp"
+        "Exif.cpp",
     ],
     cflags: [
         "-Werror",
@@ -17,13 +17,14 @@
     ],
     shared_libs: [
         "liblog",
+        "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "libexif",
     ],
     include_dirs: ["system/media/private/camera/include"],
-    export_include_dirs : ["include"]
+    export_include_dirs: ["include"],
 }
-
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
index 467c121..86f26e4 100644
--- a/camera/common/1.0/default/CameraModule.cpp
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -194,16 +194,6 @@
         }
     }
 
-    // Always add a default for the pre-correction active array if the vendor chooses to omit this
-    camera_metadata_entry entry = chars.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
-    if (entry.count == 0) {
-        Vector<int32_t> preCorrectionArray;
-        entry = chars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
-        preCorrectionArray.appendArray(entry.data.i32, entry.count);
-        chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectionArray);
-        derivedCharKeys.push(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
-    }
-
     // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS
     // This has to be done at this end of this function.
     if (derivedCharKeys.size() > 0) {
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index b8c40e9..05a552c 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "HandleImporter"
 #include "HandleImporter.h"
+
+#include <gralloctypes/Gralloc4.h>
 #include <log/log.h>
 
 namespace android {
@@ -25,9 +27,14 @@
 namespace V1_0 {
 namespace helper {
 
+using aidl::android::hardware::graphics::common::PlaneLayout;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
 using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
 using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
+using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error;
 using IMapperV3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapperV4 = android::hardware::graphics::mapper::V4_0::IMapper;
 
 HandleImporter::HandleImporter() : mInitialized(false) {}
 
@@ -36,6 +43,12 @@
         return;
     }
 
+    mMapperV4 = IMapperV4::getService();
+    if (mMapperV4 != nullptr) {
+        mInitialized = true;
+        return;
+    }
+
     mMapperV3 = IMapperV3::getService();
     if (mMapperV3 != nullptr) {
         mInitialized = true;
@@ -53,6 +66,7 @@
 }
 
 void HandleImporter::cleanup() {
+    mMapperV4.clear();
     mMapperV3.clear();
     mMapperV2.clear();
     mInitialized = false;
@@ -109,6 +123,79 @@
     return layout;
 }
 
+template <>
+YCbCrLayout HandleImporter::lockYCbCrInternal<IMapperV4, MapperErrorV4>(
+        const sp<IMapperV4> mapper, buffer_handle_t& buf, uint64_t cpuUsage,
+        const IMapper::Rect& accessRegion) {
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    YCbCrLayout layout = {};
+    void* mapped = nullptr;
+
+    typename IMapperV4::Rect accessRegionV4 = {accessRegion.left, accessRegion.top,
+                                               accessRegion.width, accessRegion.height};
+    mapper->lock(buffer, cpuUsage, accessRegionV4, acquireFenceHandle,
+                 [&](const auto& tmpError, const auto& tmpPtr) {
+                     if (tmpError == MapperErrorV4::NONE) {
+                         mapped = tmpPtr;
+                     } else {
+                         ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                     }
+                 });
+
+    if (mapped == nullptr) {
+        return layout;
+    }
+
+    hidl_vec<uint8_t> encodedPlaneLayouts;
+    mapper->get(buffer, gralloc4::MetadataType_PlaneLayouts,
+                [&](const auto& tmpError, const auto& tmpEncodedPlaneLayouts) {
+                    if (tmpError == MapperErrorV4::NONE) {
+                        encodedPlaneLayouts = tmpEncodedPlaneLayouts;
+                    } else {
+                        ALOGE("%s: failed to get plane layouts %d!", __FUNCTION__, tmpError);
+                    }
+                });
+
+    std::vector<PlaneLayout> planeLayouts;
+    gralloc4::decodePlaneLayouts(encodedPlaneLayouts, &planeLayouts);
+
+    for (const auto& planeLayout : planeLayouts) {
+        for (const auto& planeLayoutComponent : planeLayout.components) {
+            const auto& type = planeLayoutComponent.type;
+
+            if (!gralloc4::isStandardPlaneLayoutComponentType(type)) {
+                continue;
+            }
+
+            uint8_t* data = reinterpret_cast<uint8_t*>(mapped);
+            data += planeLayout.offsetInBytes;
+            data += planeLayoutComponent.offsetInBits / 8;
+
+            switch (static_cast<PlaneLayoutComponentType>(type.value)) {
+                case PlaneLayoutComponentType::Y:
+                    layout.y = data;
+                    layout.yStride = planeLayout.strideInBytes;
+                    break;
+                case PlaneLayoutComponentType::CB:
+                    layout.cb = data;
+                    layout.cStride = planeLayout.strideInBytes;
+                    layout.chromaStep = planeLayout.sampleIncrementInBits / 8;
+                    break;
+                case PlaneLayoutComponentType::CR:
+                    layout.cr = data;
+                    layout.cStride = planeLayout.strideInBytes;
+                    layout.chromaStep = planeLayout.sampleIncrementInBits / 8;
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    return layout;
+}
+
 template<class M, class E>
 int HandleImporter::unlockInternal(const sp<M> mapper, buffer_handle_t& buf) {
     int releaseFence = -1;
@@ -151,6 +238,10 @@
         initializeLocked();
     }
 
+    if (mMapperV4 != nullptr) {
+        return importBufferInternal<IMapperV4, MapperErrorV4>(mMapperV4, handle);
+    }
+
     if (mMapperV3 != nullptr) {
         return importBufferInternal<IMapperV3, MapperErrorV3>(mMapperV3, handle);
     }
@@ -159,7 +250,7 @@
         return importBufferInternal<IMapper, MapperErrorV2>(mMapperV2, handle);
     }
 
-    ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
     return false;
 }
 
@@ -169,12 +260,16 @@
     }
 
     Mutex::Autolock lock(mLock);
-    if (mMapperV3 == nullptr && mMapperV2 == nullptr) {
-        ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
-        return;
+    if (!mInitialized) {
+        initializeLocked();
     }
 
-    if (mMapperV3 != nullptr) {
+    if (mMapperV4 != nullptr) {
+        auto ret = mMapperV4->freeBuffer(const_cast<native_handle_t*>(handle));
+        if (!ret.isOk()) {
+            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+        }
+    } else if (mMapperV3 != nullptr) {
         auto ret = mMapperV3->freeBuffer(const_cast<native_handle_t*>(handle));
         if (!ret.isOk()) {
             ALOGE("%s: mapper freeBuffer failed: %s",
@@ -215,48 +310,67 @@
 
 void* HandleImporter::lock(
         buffer_handle_t& buf, uint64_t cpuUsage, size_t size) {
+    IMapper::Rect accessRegion{0, 0, static_cast<int>(size), 1};
+    return lock(buf, cpuUsage, accessRegion);
+}
+
+void* HandleImporter::lock(buffer_handle_t& buf, uint64_t cpuUsage,
+                           const IMapper::Rect& accessRegion) {
     Mutex::Autolock lock(mLock);
-    void *ret = 0;
 
     if (!mInitialized) {
         initializeLocked();
     }
 
-    if (mMapperV3 == nullptr && mMapperV2 == nullptr) {
-        ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+    void* ret = nullptr;
+
+    if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
+        ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
         return ret;
     }
 
     hidl_handle acquireFenceHandle;
     auto buffer = const_cast<native_handle_t*>(buf);
-    if (mMapperV3 != nullptr) {
-        IMapperV3::Rect accessRegion { 0, 0, static_cast<int>(size), 1 };
-        // No need to use bytesPerPixel and bytesPerStride because we are using
-        // an 1-D buffer and accressRegion.
-        mMapperV3->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/,
-                        const auto& /*bytesPerStride*/) {
-                    if (tmpError == MapperErrorV3::NONE) {
-                        ret = tmpPtr;
-                    } else {
-                        ALOGE("%s: failed to lock error %d!",
-                              __FUNCTION__, tmpError);
-                    }
-               });
+    if (mMapperV4 != nullptr) {
+        IMapperV4::Rect accessRegionV4{accessRegion.left, accessRegion.top, accessRegion.width,
+                                       accessRegion.height};
+
+        mMapperV4->lock(buffer, cpuUsage, accessRegionV4, acquireFenceHandle,
+                        [&](const auto& tmpError, const auto& tmpPtr) {
+                            if (tmpError == MapperErrorV4::NONE) {
+                                ret = tmpPtr;
+                            } else {
+                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                            }
+                        });
+    } else if (mMapperV3 != nullptr) {
+        IMapperV3::Rect accessRegionV3{accessRegion.left, accessRegion.top, accessRegion.width,
+                                       accessRegion.height};
+
+        mMapperV3->lock(buffer, cpuUsage, accessRegionV3, acquireFenceHandle,
+                        [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/,
+                            const auto& /*bytesPerStride*/) {
+                            if (tmpError == MapperErrorV3::NONE) {
+                                ret = tmpPtr;
+                            } else {
+                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                            }
+                        });
     } else {
-        IMapper::Rect accessRegion { 0, 0, static_cast<int>(size), 1 };
         mMapperV2->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
                 [&](const auto& tmpError, const auto& tmpPtr) {
                     if (tmpError == MapperErrorV2::NONE) {
                         ret = tmpPtr;
                     } else {
-                        ALOGE("%s: failed to lock error %d!",
-                              __FUNCTION__, tmpError);
+                        ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
                     }
                });
     }
 
-    ALOGV("%s: ptr %p size: %zu", __FUNCTION__, ret, size);
+    ALOGV("%s: ptr %p accessRegion.top: %d accessRegion.left: %d accessRegion.width: %d "
+          "accessRegion.height: %d",
+          __FUNCTION__, ret, accessRegion.top, accessRegion.left, accessRegion.width,
+          accessRegion.height);
     return ret;
 }
 
@@ -269,6 +383,10 @@
         initializeLocked();
     }
 
+    if (mMapperV4 != nullptr) {
+        return lockYCbCrInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf, cpuUsage, accessRegion);
+    }
+
     if (mMapperV3 != nullptr) {
         return lockYCbCrInternal<IMapperV3, MapperErrorV3>(
                 mMapperV3, buf, cpuUsage, accessRegion);
@@ -279,11 +397,14 @@
                 mMapperV2, buf, cpuUsage, accessRegion);
     }
 
-    ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
     return {};
 }
 
 int HandleImporter::unlock(buffer_handle_t& buf) {
+    if (mMapperV4 != nullptr) {
+        return unlockInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf);
+    }
     if (mMapperV3 != nullptr) {
         return unlockInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf);
     }
@@ -291,7 +412,7 @@
         return unlockInternal<IMapper, MapperErrorV2>(mMapperV2, buf);
     }
 
-    ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
     return -1;
 }
 
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
index a93d455..edc97ad 100644
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -17,10 +17,11 @@
 #ifndef CAMERA_COMMON_1_0_HANDLEIMPORTED_H
 #define CAMERA_COMMON_1_0_HANDLEIMPORTED_H
 
-#include <utils/Mutex.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <cutils/native_handle.h>
+#include <utils/Mutex.h>
 
 using android::hardware::graphics::mapper::V2_0::IMapper;
 using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
@@ -45,10 +46,13 @@
     bool importFence(const native_handle_t* handle, int& fd) const;
     void closeFence(int fd) const;
 
-    // Assume caller has done waiting for acquire fences
+    // Locks 1-D buffer. Assumes caller has waited for acquire fences.
     void* lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size);
 
-    // Assume caller has done waiting for acquire fences
+    // Locks 2-D buffer. Assumes caller has waited for acquire fences.
+    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, const IMapper::Rect& accessRegion);
+
+    // Assumes caller has waited for acquire fences.
     YCbCrLayout lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
                           const IMapper::Rect& accessRegion);
 
@@ -70,6 +74,7 @@
     bool mInitialized;
     sp<IMapper> mMapperV2;
     sp<graphics::mapper::V3_0::IMapper> mMapperV3;
+    sp<graphics::mapper::V4_0::IMapper> mMapperV4;
 };
 
 } // namespace helper
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
index 97d0b5f..da70577 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -14,20 +14,21 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hardware.graphics.common@1.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libcutils",
         "liblog",
+        "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
     ],
     static_libs: [
-        "android.hardware.camera.common@1.0-helper"
+        "android.hardware.camera.common@1.0-helper",
     ],
     header_libs: [
         "media_plugin_headers",
     ],
-    export_include_dirs: ["."]
+    export_include_dirs: ["."],
 }
-
diff --git a/camera/device/3.2/ICameraDeviceCallback.hal b/camera/device/3.2/ICameraDeviceCallback.hal
index dec3bd8..206a649 100644
--- a/camera/device/3.2/ICameraDeviceCallback.hal
+++ b/camera/device/3.2/ICameraDeviceCallback.hal
@@ -87,15 +87,19 @@
      * ERROR_RESULT message.
      *
      * If an output buffer cannot be filled, its status field must be set to
-     * STATUS_ERROR. In addition, notify() must be called with a ERROR_BUFFER
-     * message.
+     * STATUS_ERROR. In this case, notify() isn't required to be called with
+     * an ERROR_BUFFER message. The framework will simply treat the notify()
+     * call with ERROR_BUFFER as a no-op, and derive whether and when to notify
+     * the application of buffer loss based on the buffer status and whether or not
+     * the entire capture has failed.
      *
      * If the entire capture has failed, then this method still needs to be
      * called to return the output buffers to the framework. All the buffer
      * statuses must be STATUS_ERROR, and the result metadata must be an
      * empty buffer. In addition, notify() must be called with a ERROR_REQUEST
      * message. In this case, individual ERROR_RESULT/ERROR_BUFFER messages
-     * must not be sent.
+     * must not be sent. Note that valid partial results are still allowed
+     * as long as the final result metadata fails to be generated.
      *
      * Performance requirements:
      *
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
index e4d9e85..be2de07 100644
--- a/camera/device/3.2/default/Android.bp
+++ b/camera/device/3.2/default/Android.bp
@@ -2,9 +2,11 @@
     name: "camera.device@3.2-impl",
     defaults: ["hidl_defaults"],
     proprietary: true,
-    srcs: ["CameraDevice.cpp",
-           "CameraDeviceSession.cpp",
-           "convert.cpp"],
+    srcs: [
+        "CameraDevice.cpp",
+        "CameraDeviceSession.cpp",
+        "convert.cpp",
+    ],
     shared_libs: [
         "libhidlbase",
         "libutils",
@@ -13,16 +15,18 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
+        "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
-        "libfmq"
+        "libfmq",
     ],
     static_libs: [
-        "android.hardware.camera.common@1.0-helper"
+        "android.hardware.camera.common@1.0-helper",
     ],
     export_include_dirs: ["."],
     export_shared_lib_headers: [
         "libfmq",
-    ]
+    ],
 }
diff --git a/camera/device/3.2/default/convert.cpp b/camera/device/3.2/default/convert.cpp
index d878deb..06ad7e9 100644
--- a/camera/device/3.2/default/convert.cpp
+++ b/camera/device/3.2/default/convert.cpp
@@ -38,7 +38,7 @@
     }
 
     const uint8_t* data = src.data();
-    // sanity check the size of CameraMetadata match underlying camera_metadata_t
+    // check that the size of CameraMetadata match underlying camera_metadata_t
     if (get_camera_metadata_size((camera_metadata_t*)data) != src.size()) {
         ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__);
         return false;
diff --git a/camera/device/3.3/default/Android.bp b/camera/device/3.3/default/Android.bp
index d964f3d..0aa0dd7 100644
--- a/camera/device/3.3/default/Android.bp
+++ b/camera/device/3.3/default/Android.bp
@@ -2,9 +2,11 @@
     name: "camera.device@3.3-impl",
     defaults: ["hidl_defaults"],
     proprietary: true,
-    srcs: ["CameraDevice.cpp",
-           "CameraDeviceSession.cpp",
-           "convert.cpp"],
+    srcs: [
+        "CameraDevice.cpp",
+        "CameraDeviceSession.cpp",
+        "convert.cpp",
+    ],
     shared_libs: [
         "libhidlbase",
         "libutils",
@@ -15,16 +17,18 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
+        "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
-        "libfmq"
+        "libfmq",
     ],
     static_libs: [
-        "android.hardware.camera.common@1.0-helper"
+        "android.hardware.camera.common@1.0-helper",
     ],
     export_include_dirs: ["."],
     export_shared_lib_headers: [
         "libfmq",
-    ]
+    ],
 }
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index 71a9e77..982dce1 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -17,13 +17,13 @@
 cc_library_headers {
     name: "camera.device@3.4-impl_headers",
     vendor: true,
-    export_include_dirs: ["include/device_v3_4_impl"]
+    export_include_dirs: ["include/device_v3_4_impl"],
 }
 
 cc_library_headers {
     name: "camera.device@3.4-external-impl_headers",
     vendor: true,
-    export_include_dirs: ["include/ext_device_v3_4_impl"]
+    export_include_dirs: ["include/ext_device_v3_4_impl"],
 }
 
 cc_library_shared {
@@ -34,7 +34,7 @@
     srcs: [
         "CameraDevice.cpp",
         "CameraDeviceSession.cpp",
-        "convert.cpp"
+        "convert.cpp",
     ],
     shared_libs: [
         "libhidlbase",
@@ -48,7 +48,9 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
+        "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
         "libfmq",
@@ -84,7 +86,9 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
+        "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
         "libfmq",
@@ -92,7 +96,7 @@
         "libyuv",
         "libjpeg",
         "libexif",
-        "libtinyxml2"
+        "libtinyxml2",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index f518a15..677b496 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -20,6 +20,7 @@
 
 #include <algorithm>
 #include <array>
+#include <regex>
 #include <linux/videodev2.h>
 #include "android-base/macros.h"
 #include "CameraMetadata.h"
@@ -46,10 +47,20 @@
 
 } // anonymous namespace
 
+const std::regex kDevicePathRE("/dev/video([0-9]+)");
+
 ExternalCameraDevice::ExternalCameraDevice(
-        const std::string& cameraId, const ExternalCameraConfig& cfg) :
-        mCameraId(cameraId),
-        mCfg(cfg) {}
+        const std::string& devicePath, const ExternalCameraConfig& cfg) :
+        mCameraId("-1"),
+        mDevicePath(devicePath),
+        mCfg(cfg) {
+    std::smatch sm;
+    if (std::regex_match(mDevicePath, sm, kDevicePathRE)) {
+        mCameraId = std::to_string(mCfg.cameraIdOffset + std::stoi(sm[1]));
+    } else {
+        ALOGE("%s: device path match failed for %s", __FUNCTION__, mDevicePath.c_str());
+    }
+}
 
 ExternalCameraDevice::~ExternalCameraDevice() {}
 
@@ -129,20 +140,20 @@
         return Void();
     }
 
-    unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
+    unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
     if (fd.get() < 0) {
         int numAttempt = 0;
         do {
             ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again",
-                    __FUNCTION__, mCameraId.c_str());
+                    __FUNCTION__, mDevicePath.c_str());
             usleep(OPEN_RETRY_SLEEP_US); // sleep and try again
-            fd.reset(::open(mCameraId.c_str(), O_RDWR));
+            fd.reset(::open(mDevicePath.c_str(), O_RDWR));
             numAttempt++;
         } while (fd.get() < 0 && numAttempt <= MAX_RETRY);
 
         if (fd.get() < 0) {
             ALOGE("%s: v4l2 device open %s failed: %s",
-                    __FUNCTION__, mCameraId.c_str(), strerror(errno));
+                    __FUNCTION__, mDevicePath.c_str(), strerror(errno));
             mLock.unlock();
             _hidl_cb(Status::INTERNAL_ERROR, nullptr);
             return Void();
@@ -203,9 +214,9 @@
 status_t ExternalCameraDevice::initCameraCharacteristics() {
     if (mCameraCharacteristics.isEmpty()) {
         // init camera characteristics
-        unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
+        unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
         if (fd.get() < 0) {
-            ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mCameraId.c_str());
+            ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mDevicePath.c_str());
             return DEAD_OBJECT;
         }
 
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 9ff0d74..5f86742 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -81,8 +81,6 @@
     return locked;
 }
 
-buffer_handle_t sEmptyBuffer = nullptr;
-
 } // Anonymous namespace
 
 // Static instances
@@ -119,8 +117,8 @@
     std::string make, model;
     if (ret < 0) {
         ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__);
-        make = "Generic UVC webcam";
-        model = "Generic UVC webcam";
+        mExifMake = "Generic UVC webcam";
+        mExifModel = "Generic UVC webcam";
     } else {
         // capability.card is UTF-8 encoded
         char card[32];
@@ -134,11 +132,11 @@
             }
         }
         if (j == 0 || card[j - 1] != '\0') {
-            make = "Generic UVC webcam";
-            model = "Generic UVC webcam";
+            mExifMake = "Generic UVC webcam";
+            mExifModel = "Generic UVC webcam";
         } else {
-            make = card;
-            model = card;
+            mExifMake = card;
+            mExifModel = card;
         }
     }
 
@@ -147,7 +145,7 @@
         ALOGE("%s: init OutputThread failed!", __FUNCTION__);
         return true;
     }
-    mOutputThread->setExifMakeModel(make, model);
+    mOutputThread->setExifMakeModel(mExifMake, mExifModel);
 
     status_t status = initDefaultRequests();
     if (status != OK) {
@@ -161,7 +159,7 @@
         ALOGE("%s: invalid request fmq", __FUNCTION__);
         return true;
     }
-    mResultMetadataQueue = std::make_shared<RequestMetadataQueue>(
+    mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
             kMetadataMsgQueueSize, false /* non blocking */);
     if (!mResultMetadataQueue->isValid()) {
         ALOGE("%s: invalid result fmq", __FUNCTION__);
@@ -183,7 +181,7 @@
 }
 
 void ExternalCameraDeviceSession::initOutputThread() {
-    mOutputThread = new OutputThread(this, mCroppingType);
+    mOutputThread = new OutputThread(this, mCroppingType, mCameraCharacteristics);
 }
 
 void ExternalCameraDeviceSession::closeOutputThread() {
@@ -518,35 +516,9 @@
         uint64_t bufId, buffer_handle_t buf,
         /*out*/buffer_handle_t** outBufPtr,
         bool allowEmptyBuf) {
-
-    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
-        if (allowEmptyBuf) {
-            *outBufPtr = &sEmptyBuffer;
-            return Status::OK;
-        } else {
-            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
-            return Status::ILLEGAL_ARGUMENT;
-        }
-    }
-
-    CirculatingBuffers& cbs = mCirculatingBuffers[streamId];
-    if (cbs.count(bufId) == 0) {
-        if (buf == nullptr) {
-            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
-            return Status::ILLEGAL_ARGUMENT;
-        }
-        // Register a newly seen buffer
-        buffer_handle_t importedBuf = buf;
-        sHandleImporter.importBuffer(importedBuf);
-        if (importedBuf == nullptr) {
-            ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
-            return Status::INTERNAL_ERROR;
-        } else {
-            cbs[bufId] = importedBuf;
-        }
-    }
-    *outBufPtr = &cbs[bufId];
-    return Status::OK;
+    return importBufferImpl(
+            mCirculatingBuffers, sHandleImporter, streamId,
+            bufId, buf, outBufPtr, allowEmptyBuf);
 }
 
 Status ExternalCameraDeviceSession::importRequestLockedImpl(
@@ -791,15 +763,32 @@
 
 //TODO: refactor with processCaptureResult
 Status ExternalCameraDeviceSession::processCaptureRequestError(
-        const std::shared_ptr<HalRequest>& req) {
+        const std::shared_ptr<HalRequest>& req,
+        /*out*/std::vector<NotifyMsg>* outMsgs,
+        /*out*/std::vector<CaptureResult>* outResults) {
     ATRACE_CALL();
     // Return V4L2 buffer to V4L2 buffer queue
-    enqueueV4l2Frame(req->frameIn);
+    sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+            static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+    enqueueV4l2Frame(v4l2Frame);
 
-    // NotifyShutter
-    notifyShutter(req->frameNumber, req->shutterTs);
+    if (outMsgs == nullptr) {
+        notifyShutter(req->frameNumber, req->shutterTs);
+        notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+    } else {
+        NotifyMsg shutter;
+        shutter.type = MsgType::SHUTTER;
+        shutter.msg.shutter.frameNumber = req->frameNumber;
+        shutter.msg.shutter.timestamp = req->shutterTs;
 
-    notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+        NotifyMsg error;
+        error.type = MsgType::ERROR;
+        error.msg.error.frameNumber = req->frameNumber;
+        error.msg.error.errorStreamId = -1;
+        error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+        outMsgs->push_back(shutter);
+        outMsgs->push_back(error);
+    }
 
     // Fill output buffers
     hidl_vec<CaptureResult> results;
@@ -826,16 +815,22 @@
         mInflightFrames.erase(req->frameNumber);
     }
 
-    // Callback into framework
-    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
-    freeReleaseFences(results);
+    if (outResults == nullptr) {
+        // Callback into framework
+        invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+        freeReleaseFences(results);
+    } else {
+        outResults->push_back(result);
+    }
     return Status::OK;
 }
 
 Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
     ATRACE_CALL();
     // Return V4L2 buffer to V4L2 buffer queue
-    enqueueV4l2Frame(req->frameIn);
+    sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+            static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+    enqueueV4l2Frame(v4l2Frame);
 
     // NotifyShutter
     notifyShutter(req->frameNumber, req->shutterTs);
@@ -923,29 +918,10 @@
     mProcessCaptureResultLock.unlock();
 }
 
-void ExternalCameraDeviceSession::freeReleaseFences(hidl_vec<CaptureResult>& results) {
-    for (auto& result : results) {
-        if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
-            native_handle_t* handle = const_cast<native_handle_t*>(
-                    result.inputBuffer.releaseFence.getNativeHandle());
-            native_handle_close(handle);
-            native_handle_delete(handle);
-        }
-        for (auto& buf : result.outputBuffers) {
-            if (buf.releaseFence.getNativeHandle() != nullptr) {
-                native_handle_t* handle = const_cast<native_handle_t*>(
-                        buf.releaseFence.getNativeHandle());
-                native_handle_close(handle);
-                native_handle_delete(handle);
-            }
-        }
-    }
-    return;
-}
-
 ExternalCameraDeviceSession::OutputThread::OutputThread(
-        wp<ExternalCameraDeviceSession> parent,
-        CroppingType ct) : mParent(parent), mCroppingType(ct) {}
+        wp<OutputThreadInterface> parent, CroppingType ct,
+        const common::V1_0::helper::CameraMetadata& chars) :
+        mParent(parent), mCroppingType(ct), mCameraCharacteristics(chars) {}
 
 ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
 
@@ -955,88 +931,6 @@
     mExifModel = model;
 }
 
-uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout(
-        const YCbCrLayout& layout) {
-    intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
-    intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
-    if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
-        // Interleaved format
-        if (layout.cb > layout.cr) {
-            return V4L2_PIX_FMT_NV21;
-        } else {
-            return V4L2_PIX_FMT_NV12;
-        }
-    } else if (layout.chromaStep == 1) {
-        // Planar format
-        if (layout.cb > layout.cr) {
-            return V4L2_PIX_FMT_YVU420; // YV12
-        } else {
-            return V4L2_PIX_FMT_YUV420; // YU12
-        }
-    } else {
-        return FLEX_YUV_GENERIC;
-    }
-}
-
-int ExternalCameraDeviceSession::OutputThread::getCropRect(
-        CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
-    if (out == nullptr) {
-        ALOGE("%s: out is null", __FUNCTION__);
-        return -1;
-    }
-
-    uint32_t inW = inSize.width;
-    uint32_t inH = inSize.height;
-    uint32_t outW = outSize.width;
-    uint32_t outH = outSize.height;
-
-    // Handle special case where aspect ratio is close to input but scaled
-    // dimension is slightly larger than input
-    float arIn = ASPECT_RATIO(inSize);
-    float arOut = ASPECT_RATIO(outSize);
-    if (isAspectRatioClose(arIn, arOut)) {
-        out->left = 0;
-        out->top = 0;
-        out->width = inW;
-        out->height = inH;
-        return 0;
-    }
-
-    if (ct == VERTICAL) {
-        uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
-        if (scaledOutH > inH) {
-            ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
-                    __FUNCTION__, outW, outH, inW, inH);
-            return -1;
-        }
-        scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
-
-        out->left = 0;
-        out->top = ((inH - scaledOutH) / 2) & ~0x1;
-        out->width = inW;
-        out->height = static_cast<int32_t>(scaledOutH);
-        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
-                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
-    } else {
-        uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
-        if (scaledOutW > inW) {
-            ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
-                    __FUNCTION__, outW, outH, inW, inH);
-            return -1;
-        }
-        scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
-
-        out->left = ((inW - scaledOutW) / 2) & ~0x1;
-        out->top = 0;
-        out->width = static_cast<int32_t>(scaledOutW);
-        out->height = inH;
-        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
-                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
-    }
-
-    return 0;
-}
-
 int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
         sp<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
     Size inSz = {in->mWidth, in->mHeight};
@@ -1274,265 +1168,6 @@
     return 0;
 }
 
-int ExternalCameraDeviceSession::OutputThread::formatConvertLocked(
-        const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
-    int ret = 0;
-    switch (format) {
-        case V4L2_PIX_FMT_NV21:
-            ret = libyuv::I420ToNV21(
-                    static_cast<uint8_t*>(in.y),
-                    in.yStride,
-                    static_cast<uint8_t*>(in.cb),
-                    in.cStride,
-                    static_cast<uint8_t*>(in.cr),
-                    in.cStride,
-                    static_cast<uint8_t*>(out.y),
-                    out.yStride,
-                    static_cast<uint8_t*>(out.cr),
-                    out.cStride,
-                    sz.width,
-                    sz.height);
-            if (ret != 0) {
-                ALOGE("%s: convert to NV21 buffer failed! ret %d",
-                            __FUNCTION__, ret);
-                return ret;
-            }
-            break;
-        case V4L2_PIX_FMT_NV12:
-            ret = libyuv::I420ToNV12(
-                    static_cast<uint8_t*>(in.y),
-                    in.yStride,
-                    static_cast<uint8_t*>(in.cb),
-                    in.cStride,
-                    static_cast<uint8_t*>(in.cr),
-                    in.cStride,
-                    static_cast<uint8_t*>(out.y),
-                    out.yStride,
-                    static_cast<uint8_t*>(out.cb),
-                    out.cStride,
-                    sz.width,
-                    sz.height);
-            if (ret != 0) {
-                ALOGE("%s: convert to NV12 buffer failed! ret %d",
-                            __FUNCTION__, ret);
-                return ret;
-            }
-            break;
-        case V4L2_PIX_FMT_YVU420: // YV12
-        case V4L2_PIX_FMT_YUV420: // YU12
-            // TODO: maybe we can speed up here by somehow save this copy?
-            ret = libyuv::I420Copy(
-                    static_cast<uint8_t*>(in.y),
-                    in.yStride,
-                    static_cast<uint8_t*>(in.cb),
-                    in.cStride,
-                    static_cast<uint8_t*>(in.cr),
-                    in.cStride,
-                    static_cast<uint8_t*>(out.y),
-                    out.yStride,
-                    static_cast<uint8_t*>(out.cb),
-                    out.cStride,
-                    static_cast<uint8_t*>(out.cr),
-                    out.cStride,
-                    sz.width,
-                    sz.height);
-            if (ret != 0) {
-                ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
-                            __FUNCTION__, ret);
-                return ret;
-            }
-            break;
-        case FLEX_YUV_GENERIC:
-            // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
-            ALOGE("%s: unsupported flexible yuv layout"
-                    " y %p cb %p cr %p y_str %d c_str %d c_step %d",
-                    __FUNCTION__, out.y, out.cb, out.cr,
-                    out.yStride, out.cStride, out.chromaStep);
-            return -1;
-        default:
-            ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
-            return -1;
-    }
-    return 0;
-}
-
-int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12(
-        const Size & inSz, const YCbCrLayout& inLayout,
-        int jpegQuality, const void *app1Buffer, size_t app1Size,
-        void *out, const size_t maxOutSize, size_t &actualCodeSize)
-{
-    /* libjpeg is a C library so we use C-style "inheritance" by
-     * putting libjpeg's jpeg_destination_mgr first in our custom
-     * struct. This allows us to cast jpeg_destination_mgr* to
-     * CustomJpegDestMgr* when we get it passed to us in a callback */
-    struct CustomJpegDestMgr {
-        struct jpeg_destination_mgr mgr;
-        JOCTET *mBuffer;
-        size_t mBufferSize;
-        size_t mEncodedSize;
-        bool mSuccess;
-    } dmgr;
-
-    jpeg_compress_struct cinfo = {};
-    jpeg_error_mgr jerr;
-
-    /* Initialize error handling with standard callbacks, but
-     * then override output_message (to print to ALOG) and
-     * error_exit to set a flag and print a message instead
-     * of killing the whole process */
-    cinfo.err = jpeg_std_error(&jerr);
-
-    cinfo.err->output_message = [](j_common_ptr cinfo) {
-        char buffer[JMSG_LENGTH_MAX];
-
-        /* Create the message */
-        (*cinfo->err->format_message)(cinfo, buffer);
-        ALOGE("libjpeg error: %s", buffer);
-    };
-    cinfo.err->error_exit = [](j_common_ptr cinfo) {
-        (*cinfo->err->output_message)(cinfo);
-        if(cinfo->client_data) {
-            auto & dmgr =
-                *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
-            dmgr.mSuccess = false;
-        }
-    };
-    /* Now that we initialized some callbacks, let's create our compressor */
-    jpeg_create_compress(&cinfo);
-
-    /* Initialize our destination manager */
-    dmgr.mBuffer = static_cast<JOCTET*>(out);
-    dmgr.mBufferSize = maxOutSize;
-    dmgr.mEncodedSize = 0;
-    dmgr.mSuccess = true;
-    cinfo.client_data = static_cast<void*>(&dmgr);
-
-    /* These lambdas become C-style function pointers and as per C++11 spec
-     * may not capture anything */
-    dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
-        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
-        dmgr.mgr.next_output_byte = dmgr.mBuffer;
-        dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
-        ALOGV("%s:%d jpeg start: %p [%zu]",
-              __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
-    };
-
-    dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
-        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
-        return 0;
-    };
-
-    dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
-        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
-        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
-        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
-    };
-    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
-
-    /* We are going to be using JPEG in raw data mode, so we are passing
-     * straight subsampled planar YCbCr and it will not touch our pixel
-     * data or do any scaling or anything */
-    cinfo.image_width = inSz.width;
-    cinfo.image_height = inSz.height;
-    cinfo.input_components = 3;
-    cinfo.in_color_space = JCS_YCbCr;
-
-    /* Initialize defaults and then override what we want */
-    jpeg_set_defaults(&cinfo);
-
-    jpeg_set_quality(&cinfo, jpegQuality, 1);
-    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
-    cinfo.raw_data_in = 1;
-    cinfo.dct_method = JDCT_IFAST;
-
-    /* Configure sampling factors. The sampling factor is JPEG subsampling 420
-     * because the source format is YUV420. Note that libjpeg sampling factors
-     * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
-     * 1 V value for each 2 Y values */
-    cinfo.comp_info[0].h_samp_factor = 2;
-    cinfo.comp_info[0].v_samp_factor = 2;
-    cinfo.comp_info[1].h_samp_factor = 1;
-    cinfo.comp_info[1].v_samp_factor = 1;
-    cinfo.comp_info[2].h_samp_factor = 1;
-    cinfo.comp_info[2].v_samp_factor = 1;
-
-    /* Let's not hardcode YUV420 in 6 places... 5 was enough */
-    int maxVSampFactor = std::max( {
-        cinfo.comp_info[0].v_samp_factor,
-        cinfo.comp_info[1].v_samp_factor,
-        cinfo.comp_info[2].v_samp_factor
-    });
-    int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
-                        cinfo.comp_info[1].v_samp_factor;
-
-    /* Start the compressor */
-    jpeg_start_compress(&cinfo, TRUE);
-
-    /* Compute our macroblock height, so we can pad our input to be vertically
-     * macroblock aligned.
-     * TODO: Does it need to be horizontally MCU aligned too? */
-
-    size_t mcuV = DCTSIZE*maxVSampFactor;
-    size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
-
-    /* libjpeg uses arrays of row pointers, which makes it really easy to pad
-     * data vertically (unfortunately doesn't help horizontally) */
-    std::vector<JSAMPROW> yLines (paddedHeight);
-    std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
-    std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
-
-    uint8_t *py = static_cast<uint8_t*>(inLayout.y);
-    uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
-    uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
-
-    for(uint32_t i = 0; i < paddedHeight; i++)
-    {
-        /* Once we are in the padding territory we still point to the last line
-         * effectively replicating it several times ~ CLAMP_TO_EDGE */
-        int li = std::min(i, inSz.height - 1);
-        yLines[i]  = static_cast<JSAMPROW>(py + li * inLayout.yStride);
-        if(i < paddedHeight / cVSubSampling)
-        {
-            crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
-            cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
-        }
-    }
-
-    /* If APP1 data was passed in, use it */
-    if(app1Buffer && app1Size)
-    {
-        jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
-             static_cast<const JOCTET*>(app1Buffer), app1Size);
-    }
-
-    /* While we still have padded height left to go, keep giving it one
-     * macroblock at a time. */
-    while (cinfo.next_scanline < cinfo.image_height) {
-        const uint32_t batchSize = DCTSIZE * maxVSampFactor;
-        const uint32_t nl = cinfo.next_scanline;
-        JSAMPARRAY planes[3]{ &yLines[nl],
-                              &cbLines[nl/cVSubSampling],
-                              &crLines[nl/cVSubSampling] };
-
-        uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
-
-        if (done != batchSize) {
-            ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
-              __FUNCTION__, done, batchSize, cinfo.next_scanline,
-              cinfo.image_height);
-            return -1;
-        }
-    }
-
-    /* This will flush everything */
-    jpeg_finish_compress(&cinfo);
-
-    /* Grab the actual code size and set it */
-    actualCodeSize = dmgr.mEncodedSize;
-
-    return 0;
-}
-
 /*
  * TODO: There needs to be a mechanism to discover allocated buffer size
  * in the HAL.
@@ -1555,25 +1190,9 @@
 }
 
 Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
-    Size thumbSize { 0, 0 };
-    camera_metadata_ro_entry entry =
-        mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
-    for(uint32_t i = 0; i < entry.count; i += 2) {
-        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
-                  static_cast<uint32_t>(entry.data.i32[i+1]) };
-        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
-            thumbSize = sz;
-        }
-    }
-
-    if (thumbSize.width * thumbSize.height == 0) {
-        ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
-    }
-
-    return thumbSize;
+    return getMaxThumbnailResolution(mCameraCharacteristics);
 }
 
-
 ssize_t ExternalCameraDeviceSession::getJpegBufferSize(
         uint32_t width, uint32_t height) const {
     // Constant from camera3.h
@@ -1616,7 +1235,7 @@
 
 int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
         HalStreamBuffer &halBuf,
-        const std::shared_ptr<HalRequest>& req)
+        const common::V1_0::helper::CameraMetadata& setting)
 {
     ATRACE_CALL();
     int ret;
@@ -1645,17 +1264,17 @@
     Size thumbSize;
     bool outputThumbnail = true;
 
-    if (req->setting.exists(ANDROID_JPEG_QUALITY)) {
-        camera_metadata_entry entry =
-            req->setting.find(ANDROID_JPEG_QUALITY);
+    if (setting.exists(ANDROID_JPEG_QUALITY)) {
+        camera_metadata_ro_entry entry =
+            setting.find(ANDROID_JPEG_QUALITY);
         jpegQuality = entry.data.u8[0];
     } else {
         return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__);
     }
 
-    if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
-        camera_metadata_entry entry =
-            req->setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+    if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+        camera_metadata_ro_entry entry =
+            setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
         thumbQuality = entry.data.u8[0];
     } else {
         return lfail(
@@ -1663,9 +1282,9 @@
             __FUNCTION__);
     }
 
-    if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
-        camera_metadata_entry entry =
-            req->setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+    if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+        camera_metadata_ro_entry entry =
+            setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
         thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
                            static_cast<uint32_t>(entry.data.i32[1])
         };
@@ -1732,8 +1351,8 @@
 
     /* Combine camera characteristics with request settings to form EXIF
      * metadata */
-    common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics);
-    meta.append(req->setting);
+    common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics);
+    meta.append(setting);
 
     /* Generate EXIF object */
     std::unique_ptr<ExifUtils> utils(ExifUtils::create());
@@ -1838,7 +1457,7 @@
     // TODO: see if we can save some computation by converting to YV12 here
     uint8_t* inData;
     size_t inDataSize;
-    if (req->frameIn->map(&inData, &inDataSize) != 0) {
+    if (req->frameIn->getData(&inData, &inDataSize) != 0) {
         lk.unlock();
         return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
     }
@@ -1899,7 +1518,7 @@
         // Gralloc lockYCbCr the buffer
         switch (halBuf.format) {
             case PixelFormat::BLOB: {
-                int ret = createJpegLocked(halBuf, req);
+                int ret = createJpegLocked(halBuf, req->setting);
 
                 if(ret != 0) {
                     lk.unlock();
@@ -1949,8 +1568,8 @@
                 }
 
                 Size sz {halBuf.width, halBuf.height};
-                ATRACE_BEGIN("formatConvertLocked");
-                ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc);
+                ATRACE_BEGIN("formatConvert");
+                ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
                 ATRACE_END();
                 if (ret != 0) {
                     lk.unlock();
@@ -2055,6 +1674,14 @@
     return Status::OK;
 }
 
+void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() {
+    std::lock_guard<std::mutex> lk(mBufferLock);
+    mYu12Frame.clear();
+    mYu12ThumbFrame.clear();
+    mIntermediateBuffers.clear();
+    mBlobBufferSize = 0;
+}
+
 Status ExternalCameraDeviceSession::OutputThread::submitRequest(
         const std::shared_ptr<HalRequest>& req) {
     std::unique_lock<std::mutex> lk(mRequestListLock);
@@ -2090,6 +1717,32 @@
     }
 }
 
+std::list<std::shared_ptr<HalRequest>>
+ExternalCameraDeviceSession::OutputThread::switchToOffline() {
+    ATRACE_CALL();
+    std::list<std::shared_ptr<HalRequest>> emptyList;
+    auto parent = mParent.promote();
+    if (parent == nullptr) {
+       ALOGE("%s: session has been disconnected!", __FUNCTION__);
+       return emptyList;
+    }
+
+    std::unique_lock<std::mutex> lk(mRequestListLock);
+    std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
+    mRequestList.clear();
+    if (mProcessingRequest) {
+        std::chrono::seconds timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+        auto st = mRequestDoneCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+        }
+    }
+    lk.unlock();
+    clearIntermediateBuffers();
+    ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size());
+    return reqs;
+}
+
 void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(
         std::shared_ptr<HalRequest>* out) {
     ATRACE_CALL();
@@ -2733,6 +2386,7 @@
         return Status::INTERNAL_ERROR;
     }
 
+    mBlobBufferSize = blobBufferSize;
     status = mOutputThread->allocateIntermediateBuffers(v4lSize,
                 mMaxThumbResolution, config.streams, blobBufferSize);
     if (status != Status::OK) {
@@ -2916,16 +2570,6 @@
 
 status_t ExternalCameraDeviceSession::fillCaptureResult(
         common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
-    // android.control
-    // For USB camera, we don't know the AE state. Set the state to converged to
-    // indicate the frame should be good to use. Then apps don't have to wait the
-    // AE state.
-    const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
-    UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
-
-    const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
-    UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
-
     bool afTrigger = false;
     {
         std::lock_guard<std::mutex> lk(mAfTriggerLock);
@@ -2951,46 +2595,10 @@
     }
     UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
 
-    // Set AWB state to converged to indicate the frame should be good to use.
-    const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
-    UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+    camera_metadata_ro_entry activeArraySize =
+            mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
 
-    const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
-    UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
-
-    camera_metadata_ro_entry active_array_size =
-        mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
-
-    if (active_array_size.count == 0) {
-        ALOGE("%s: cannot find active array size!", __FUNCTION__);
-        return -EINVAL;
-    }
-
-    const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
-    UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
-
-    // This means pipeline latency of X frame intervals. The maximum number is 4.
-    const uint8_t requestPipelineMaxDepth = 4;
-    UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
-
-    // android.scaler
-    const int32_t crop_region[] = {
-          active_array_size.data.i32[0], active_array_size.data.i32[1],
-          active_array_size.data.i32[2], active_array_size.data.i32[3],
-    };
-    UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
-
-    // android.sensor
-    UPDATE(md, ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
-
-    // android.statistics
-    const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
-    UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
-
-    const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
-    UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
-
-    return OK;
+    return fillCaptureResultCommon(md, timestamp, activeArraySize);
 }
 
 #undef ARRAY_SIZE
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index e25deff..8f4626c 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -18,10 +18,23 @@
 #include <log/log.h>
 
 #include <cmath>
+#include <cstring>
 #include <sys/mman.h>
 #include <linux/videodev2.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <jpeglib.h>
+
 #include "ExternalCameraUtils.h"
 
+namespace {
+
+buffer_handle_t sEmptyBuffer = nullptr;
+
+} // Anonymous namespace
+
 namespace android {
 namespace hardware {
 namespace camera {
@@ -29,10 +42,13 @@
 namespace V3_4 {
 namespace implementation {
 
+Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc) :
+        mWidth(width), mHeight(height), mFourcc(fourcc) {}
+
 V4L2Frame::V4L2Frame(
         uint32_t w, uint32_t h, uint32_t fourcc,
         int bufIdx, int fd, uint32_t dataSize, uint64_t offset) :
-        mWidth(w), mHeight(h), mFourcc(fourcc),
+        Frame(w, h, fourcc),
         mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {}
 
 int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
@@ -75,9 +91,13 @@
     unmap();
 }
 
+int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+    return map(outData, dataSize);
+}
+
 AllocatedFrame::AllocatedFrame(
         uint32_t w, uint32_t h) :
-        mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {};
+        Frame(w, h, V4L2_PIX_FMT_YUV420) {};
 
 AllocatedFrame::~AllocatedFrame() {}
 
@@ -106,6 +126,17 @@
     return 0;
 }
 
+int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) {
+    YCbCrLayout layout;
+    int ret = allocate(&layout);
+    if (ret != 0) {
+        return ret;
+    }
+    *outData = mData.data();
+    *dataSize = mData.size();
+    return 0;
+}
+
 int AllocatedFrame::getLayout(YCbCrLayout* out) {
     IMapper::Rect noCrop = {0, 0,
             static_cast<int32_t>(mWidth),
@@ -150,8 +181,521 @@
     return durationDenominator / static_cast<double>(durationNumerator);
 }
 
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+        /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*inout*/HandleImporter& handleImporter,
+        int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf) {
+    using ::android::hardware::camera::common::V1_0::Status;
+    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+        if (allowEmptyBuf) {
+            *outBufPtr = &sEmptyBuffer;
+            return Status::OK;
+        } else {
+            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+            return Status::ILLEGAL_ARGUMENT;
+        }
+    }
+
+    CirculatingBuffers& cbs = circulatingBuffers[streamId];
+    if (cbs.count(bufId) == 0) {
+        if (buf == nullptr) {
+            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+            return Status::ILLEGAL_ARGUMENT;
+        }
+        // Register a newly seen buffer
+        buffer_handle_t importedBuf = buf;
+        handleImporter.importBuffer(importedBuf);
+        if (importedBuf == nullptr) {
+            ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
+            return Status::INTERNAL_ERROR;
+        } else {
+            cbs[bufId] = importedBuf;
+        }
+    }
+    *outBufPtr = &cbs[bufId];
+    return Status::OK;
+}
+
+uint32_t getFourCcFromLayout(const YCbCrLayout& layout) {
+    intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
+    intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
+    if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
+        // Interleaved format
+        if (layout.cb > layout.cr) {
+            return V4L2_PIX_FMT_NV21;
+        } else {
+            return V4L2_PIX_FMT_NV12;
+        }
+    } else if (layout.chromaStep == 1) {
+        // Planar format
+        if (layout.cb > layout.cr) {
+            return V4L2_PIX_FMT_YVU420; // YV12
+        } else {
+            return V4L2_PIX_FMT_YUV420; // YU12
+        }
+    } else {
+        return FLEX_YUV_GENERIC;
+    }
+}
+
+int getCropRect(
+        CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
+    if (out == nullptr) {
+        ALOGE("%s: out is null", __FUNCTION__);
+        return -1;
+    }
+
+    uint32_t inW = inSize.width;
+    uint32_t inH = inSize.height;
+    uint32_t outW = outSize.width;
+    uint32_t outH = outSize.height;
+
+    // Handle special case where aspect ratio is close to input but scaled
+    // dimension is slightly larger than input
+    float arIn = ASPECT_RATIO(inSize);
+    float arOut = ASPECT_RATIO(outSize);
+    if (isAspectRatioClose(arIn, arOut)) {
+        out->left = 0;
+        out->top = 0;
+        out->width = inW;
+        out->height = inH;
+        return 0;
+    }
+
+    if (ct == VERTICAL) {
+        uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
+        if (scaledOutH > inH) {
+            ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
+                    __FUNCTION__, outW, outH, inW, inH);
+            return -1;
+        }
+        scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
+
+        out->left = 0;
+        out->top = ((inH - scaledOutH) / 2) & ~0x1;
+        out->width = inW;
+        out->height = static_cast<int32_t>(scaledOutH);
+        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
+                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
+    } else {
+        uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
+        if (scaledOutW > inW) {
+            ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
+                    __FUNCTION__, outW, outH, inW, inH);
+            return -1;
+        }
+        scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
+
+        out->left = ((inW - scaledOutW) / 2) & ~0x1;
+        out->top = 0;
+        out->width = static_cast<int32_t>(scaledOutW);
+        out->height = inH;
+        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
+                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
+    }
+
+    return 0;
+}
+
+int formatConvert(
+        const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
+    int ret = 0;
+    switch (format) {
+        case V4L2_PIX_FMT_NV21:
+            ret = libyuv::I420ToNV21(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cr),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: convert to NV21 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case V4L2_PIX_FMT_NV12:
+            ret = libyuv::I420ToNV12(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cb),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: convert to NV12 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case V4L2_PIX_FMT_YVU420: // YV12
+        case V4L2_PIX_FMT_YUV420: // YU12
+            // TODO: maybe we can speed up here by somehow save this copy?
+            ret = libyuv::I420Copy(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cb),
+                    out.cStride,
+                    static_cast<uint8_t*>(out.cr),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case FLEX_YUV_GENERIC:
+            // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
+            ALOGE("%s: unsupported flexible yuv layout"
+                    " y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                    __FUNCTION__, out.y, out.cb, out.cr,
+                    out.yStride, out.cStride, out.chromaStep);
+            return -1;
+        default:
+            ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
+            return -1;
+    }
+    return 0;
+}
+
+int encodeJpegYU12(
+        const Size & inSz, const YCbCrLayout& inLayout,
+        int jpegQuality, const void *app1Buffer, size_t app1Size,
+        void *out, const size_t maxOutSize, size_t &actualCodeSize)
+{
+    /* libjpeg is a C library so we use C-style "inheritance" by
+     * putting libjpeg's jpeg_destination_mgr first in our custom
+     * struct. This allows us to cast jpeg_destination_mgr* to
+     * CustomJpegDestMgr* when we get it passed to us in a callback */
+    struct CustomJpegDestMgr {
+        struct jpeg_destination_mgr mgr;
+        JOCTET *mBuffer;
+        size_t mBufferSize;
+        size_t mEncodedSize;
+        bool mSuccess;
+    } dmgr;
+
+    jpeg_compress_struct cinfo = {};
+    jpeg_error_mgr jerr;
+
+    /* Initialize error handling with standard callbacks, but
+     * then override output_message (to print to ALOG) and
+     * error_exit to set a flag and print a message instead
+     * of killing the whole process */
+    cinfo.err = jpeg_std_error(&jerr);
+
+    cinfo.err->output_message = [](j_common_ptr cinfo) {
+        char buffer[JMSG_LENGTH_MAX];
+
+        /* Create the message */
+        (*cinfo->err->format_message)(cinfo, buffer);
+        ALOGE("libjpeg error: %s", buffer);
+    };
+    cinfo.err->error_exit = [](j_common_ptr cinfo) {
+        (*cinfo->err->output_message)(cinfo);
+        if(cinfo->client_data) {
+            auto & dmgr =
+                *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+            dmgr.mSuccess = false;
+        }
+    };
+    /* Now that we initialized some callbacks, let's create our compressor */
+    jpeg_create_compress(&cinfo);
+
+    /* Initialize our destination manager */
+    dmgr.mBuffer = static_cast<JOCTET*>(out);
+    dmgr.mBufferSize = maxOutSize;
+    dmgr.mEncodedSize = 0;
+    dmgr.mSuccess = true;
+    cinfo.client_data = static_cast<void*>(&dmgr);
+
+    /* These lambdas become C-style function pointers and as per C++11 spec
+     * may not capture anything */
+    dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mgr.next_output_byte = dmgr.mBuffer;
+        dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+        ALOGV("%s:%d jpeg start: %p [%zu]",
+              __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+    };
+
+    dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+        return 0;
+    };
+
+    dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+    };
+    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+    /* We are going to be using JPEG in raw data mode, so we are passing
+     * straight subsampled planar YCbCr and it will not touch our pixel
+     * data or do any scaling or anything */
+    cinfo.image_width = inSz.width;
+    cinfo.image_height = inSz.height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_YCbCr;
+
+    /* Initialize defaults and then override what we want */
+    jpeg_set_defaults(&cinfo);
+
+    jpeg_set_quality(&cinfo, jpegQuality, 1);
+    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+    cinfo.raw_data_in = 1;
+    cinfo.dct_method = JDCT_IFAST;
+
+    /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+     * because the source format is YUV420. Note that libjpeg sampling factors
+     * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+     * 1 V value for each 2 Y values */
+    cinfo.comp_info[0].h_samp_factor = 2;
+    cinfo.comp_info[0].v_samp_factor = 2;
+    cinfo.comp_info[1].h_samp_factor = 1;
+    cinfo.comp_info[1].v_samp_factor = 1;
+    cinfo.comp_info[2].h_samp_factor = 1;
+    cinfo.comp_info[2].v_samp_factor = 1;
+
+    /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+    int maxVSampFactor = std::max( {
+        cinfo.comp_info[0].v_samp_factor,
+        cinfo.comp_info[1].v_samp_factor,
+        cinfo.comp_info[2].v_samp_factor
+    });
+    int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
+                        cinfo.comp_info[1].v_samp_factor;
+
+    /* Start the compressor */
+    jpeg_start_compress(&cinfo, TRUE);
+
+    /* Compute our macroblock height, so we can pad our input to be vertically
+     * macroblock aligned.
+     * TODO: Does it need to be horizontally MCU aligned too? */
+
+    size_t mcuV = DCTSIZE*maxVSampFactor;
+    size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+    /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+     * data vertically (unfortunately doesn't help horizontally) */
+    std::vector<JSAMPROW> yLines (paddedHeight);
+    std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
+    std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
+
+    uint8_t *py = static_cast<uint8_t*>(inLayout.y);
+    uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
+    uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
+
+    for(uint32_t i = 0; i < paddedHeight; i++)
+    {
+        /* Once we are in the padding territory we still point to the last line
+         * effectively replicating it several times ~ CLAMP_TO_EDGE */
+        int li = std::min(i, inSz.height - 1);
+        yLines[i]  = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+        if(i < paddedHeight / cVSubSampling)
+        {
+            li = std::min(i, (inSz.height - 1) / cVSubSampling);
+            crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+            cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+        }
+    }
+
+    /* If APP1 data was passed in, use it */
+    if(app1Buffer && app1Size)
+    {
+        jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
+             static_cast<const JOCTET*>(app1Buffer), app1Size);
+    }
+
+    /* While we still have padded height left to go, keep giving it one
+     * macroblock at a time. */
+    while (cinfo.next_scanline < cinfo.image_height) {
+        const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+        const uint32_t nl = cinfo.next_scanline;
+        JSAMPARRAY planes[3]{ &yLines[nl],
+                              &cbLines[nl/cVSubSampling],
+                              &crLines[nl/cVSubSampling] };
+
+        uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+        if (done != batchSize) {
+            ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
+              __FUNCTION__, done, batchSize, cinfo.next_scanline,
+              cinfo.image_height);
+            return -1;
+        }
+    }
+
+    /* This will flush everything */
+    jpeg_finish_compress(&cinfo);
+
+    /* Grab the actual code size and set it */
+    actualCodeSize = dmgr.mEncodedSize;
+
+    return 0;
+}
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) {
+    Size thumbSize { 0, 0 };
+    camera_metadata_ro_entry entry =
+        chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for(uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+                  static_cast<uint32_t>(entry.data.i32[i+1]) };
+        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+    }
+
+    return thumbSize;
+}
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>& results) {
+    for (auto& result : results) {
+        if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+            native_handle_t* handle = const_cast<native_handle_t*>(
+                    result.inputBuffer.releaseFence.getNativeHandle());
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+        for (auto& buf : result.outputBuffers) {
+            if (buf.releaseFence.getNativeHandle() != nullptr) {
+                native_handle_t* handle = const_cast<native_handle_t*>(
+                        buf.releaseFence.getNativeHandle());
+                native_handle_close(handle);
+                native_handle_delete(handle);
+            }
+        }
+    }
+    return;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define UPDATE(md, tag, data, size)               \
+do {                                              \
+    if ((md).update((tag), (data), (size))) {     \
+        ALOGE("Update " #tag " failed!");         \
+        return BAD_VALUE;                         \
+    }                                             \
+} while (0)
+
+status_t fillCaptureResultCommon(
+        common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp,
+        camera_metadata_ro_entry& activeArraySize) {
+    if (activeArraySize.count < 4) {
+        ALOGE("%s: cannot find active array size!", __FUNCTION__);
+        return -EINVAL;
+    }
+    // android.control
+    // For USB camera, we don't know the AE state. Set the state to converged to
+    // indicate the frame should be good to use. Then apps don't have to wait the
+    // AE state.
+    const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
+    UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
+
+    const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+    UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
+
+    // Set AWB state to converged to indicate the frame should be good to use.
+    const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
+    UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+
+    const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+    UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
+
+    const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+    UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
+    // This means pipeline latency of X frame intervals. The maximum number is 4.
+    const uint8_t requestPipelineMaxDepth = 4;
+    UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
+
+    // android.scaler
+    const int32_t crop_region[] = {
+          activeArraySize.data.i32[0], activeArraySize.data.i32[1],
+          activeArraySize.data.i32[2], activeArraySize.data.i32[3],
+    };
+    UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
+
+    // android.sensor
+    UPDATE(md, ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
+
+    // android.statistics
+    const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+    UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
+
+    const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
+    UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
+
+    return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
 }  // namespace implementation
 }  // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+AllocatedV4L2Frame::AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn) :
+        Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) {
+    uint8_t* dataIn;
+    size_t dataSize;
+    if (frameIn->getData(&dataIn, &dataSize) != 0) {
+        ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__);
+        return;
+    }
+
+    mData.resize(dataSize);
+    std::memcpy(mData.data(), dataIn, dataSize);
+}
+
+int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+    if (outData == nullptr || dataSize == nullptr) {
+        ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize);
+        return -1;
+    }
+
+    *outData = mData.data();
+    *dataSize = mData.size();
+    return 0;
+}
+
+AllocatedV4L2Frame::~AllocatedV4L2Frame() {}
+
+}  // namespace implementation
+}  // namespace V3_6
 }  // namespace device
 
 
@@ -159,6 +703,7 @@
 namespace common {
 
 namespace {
+    const int kDefaultCameraIdOffset = 100;
     const int kDefaultJpegBufSize = 5 << 20; // 5MB
     const int kDefaultNumVideoBuffer = 4;
     const int kDefaultNumStillBuffer = 2;
@@ -194,6 +739,11 @@
         return ret;
     }
 
+    XMLElement *cameraIdOffset = providerCfg->FirstChildElement("CameraIdOffset");
+    if (cameraIdOffset != nullptr) {
+        ret.cameraIdOffset = std::atoi(cameraIdOffset->GetText());
+    }
+
     XMLElement *ignore = providerCfg->FirstChildElement("ignore");
     if (ignore == nullptr) {
         ALOGI("%s: no internal ignored device specified", __FUNCTION__);
@@ -330,6 +880,7 @@
 }
 
 ExternalCameraConfig::ExternalCameraConfig() :
+        cameraIdOffset(kDefaultCameraIdOffset),
         maxJpegBufSize(kDefaultJpegBufSize),
         numVideoBuffers(kDefaultNumVideoBuffer),
         numStillBuffers(kDefaultNumStillBuffer),
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index 71b7c17..180f0c1 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
@@ -84,7 +84,8 @@
 using ::android::Mutex;
 using ::android::base::unique_fd;
 
-struct ExternalCameraDeviceSession : public virtual RefBase {
+struct ExternalCameraDeviceSession : public virtual RefBase,
+        public virtual OutputThreadInterface {
 
     ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
             const ExternalCameraConfig& cfg,
@@ -110,6 +111,82 @@
     static const int kMaxStallStream = 1;
     static const uint32_t kMaxBytesPerPixel = 2;
 
+    class OutputThread : public android::Thread {
+    public:
+        OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+                const common::V1_0::helper::CameraMetadata&);
+        virtual ~OutputThread();
+
+        Status allocateIntermediateBuffers(
+                const Size& v4lSize, const Size& thumbSize,
+                const hidl_vec<Stream>& streams,
+                uint32_t blobBufferSize);
+        Status submitRequest(const std::shared_ptr<HalRequest>&);
+        void flush();
+        void dump(int fd);
+        virtual bool threadLoop() override;
+
+        void setExifMakeModel(const std::string& make, const std::string& model);
+
+        // The remaining request list is returned for offline processing
+        std::list<std::shared_ptr<HalRequest>> switchToOffline();
+
+    protected:
+        // Methods to request output buffer in parallel
+        // No-op for device@3.4. Implemented in device@3.5
+        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
+        virtual int waitForBufferRequestDone(
+                /*out*/std::vector<HalStreamBuffer>*) { return 0; }
+
+        static const int kFlushWaitTimeoutSec = 3; // 3 sec
+        static const int kReqWaitTimeoutMs = 33;   // 33ms
+        static const int kReqWaitTimesMax = 90;    // 33ms * 90 ~= 3 sec
+
+        void waitForNextRequest(std::shared_ptr<HalRequest>* out);
+        void signalRequestDone();
+
+        int cropAndScaleLocked(
+                sp<AllocatedFrame>& in, const Size& outSize,
+                YCbCrLayout* out);
+
+        int cropAndScaleThumbLocked(
+                sp<AllocatedFrame>& in, const Size& outSize,
+                YCbCrLayout* out);
+
+        int createJpegLocked(HalStreamBuffer &halBuf,
+                const common::V1_0::helper::CameraMetadata& settings);
+
+        void clearIntermediateBuffers();
+
+        const wp<OutputThreadInterface> mParent;
+        const CroppingType mCroppingType;
+        const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+        mutable std::mutex mRequestListLock;      // Protect acccess to mRequestList,
+                                                  // mProcessingRequest and mProcessingFrameNumer
+        std::condition_variable mRequestCond;     // signaled when a new request is submitted
+        std::condition_variable mRequestDoneCond; // signaled when a request is done processing
+        std::list<std::shared_ptr<HalRequest>> mRequestList;
+        bool mProcessingRequest = false;
+        uint32_t mProcessingFrameNumer = 0;
+
+        // V4L2 frameIn
+        // (MJPG decode)-> mYu12Frame
+        // (Scale)-> mScaledYu12Frames
+        // (Format convert) -> output gralloc frames
+        mutable std::mutex mBufferLock; // Protect access to intermediate buffers
+        sp<AllocatedFrame> mYu12Frame;
+        sp<AllocatedFrame> mYu12ThumbFrame;
+        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
+        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
+        YCbCrLayout mYu12FrameLayout;
+        YCbCrLayout mYu12ThumbFrameLayout;
+        uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
+
+        std::string mExifMake;
+        std::string mExifModel;
+    };
+
 protected:
 
     // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow
@@ -150,27 +227,22 @@
             ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb);
 
 protected:
-    struct HalStreamBuffer {
-        int32_t streamId;
-        uint64_t bufferId;
-        uint32_t width;
-        uint32_t height;
-        PixelFormat format;
-        V3_2::BufferUsageFlags usage;
-        buffer_handle_t* bufPtr;
-        int acquireFence;
-        bool fenceTimeout;
-    };
+    // Methods from OutputThreadInterface
+    virtual Status importBuffer(int32_t streamId,
+            uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr,
+            bool allowEmptyBuf) override;
 
-    struct HalRequest {
-        uint32_t frameNumber;
-        common::V1_0::helper::CameraMetadata setting;
-        sp<V4L2Frame> frameIn;
-        nsecs_t shutterTs;
-        std::vector<HalStreamBuffer> buffers;
-    };
+    virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
 
-    static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+    virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+        /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+        /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+    virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+    // End of OutputThreadInterface methods
 
     Status constructDefaultRequestSettingsRaw(RequestTemplate type,
             V3_2::CameraMetadata *outMetadata);
@@ -219,11 +291,6 @@
             // Optional argument for ICameraDeviceSession@3.5 impl
             bool allowEmptyBuf = false);
 
-    Status importBuffer(int32_t streamId,
-            uint64_t bufId, buffer_handle_t buf,
-            /*out*/buffer_handle_t** outBufPtr,
-            bool allowEmptyBuf);
-
     Status importBufferLocked(int32_t streamId,
             uint64_t bufId, buffer_handle_t buf,
             /*out*/buffer_handle_t** outBufPtr,
@@ -236,106 +303,15 @@
 
     Status processOneCaptureRequest(const CaptureRequest& request);
 
-    Status processCaptureResult(std::shared_ptr<HalRequest>&);
-    Status processCaptureRequestError(const std::shared_ptr<HalRequest>&);
     void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs);
-    void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec);
     void invokeProcessCaptureResultCallback(
             hidl_vec<CaptureResult> &results, bool tryWriteFmq);
-    static void freeReleaseFences(hidl_vec<CaptureResult>&);
 
     Size getMaxJpegResolution() const;
     Size getMaxThumbResolution() const;
 
-    ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
-
     int waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk);
 
-    class OutputThread : public android::Thread {
-    public:
-        OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
-        virtual ~OutputThread();
-
-        Status allocateIntermediateBuffers(
-                const Size& v4lSize, const Size& thumbSize,
-                const hidl_vec<Stream>& streams,
-                uint32_t blobBufferSize);
-        Status submitRequest(const std::shared_ptr<HalRequest>&);
-        void flush();
-        void dump(int fd);
-        virtual bool threadLoop() override;
-
-        void setExifMakeModel(const std::string& make, const std::string& model);
-
-    protected:
-        // Methods to request output buffer in parallel
-        // No-op for device@3.4. Implemented in device@3.5
-        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
-        virtual int waitForBufferRequestDone(
-                /*out*/std::vector<HalStreamBuffer>*) { return 0; }
-
-        static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
-                static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
-                static_cast<uint32_t>('X') << 24;
-        // returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
-        static uint32_t getFourCcFromLayout(const YCbCrLayout&);
-        static int getCropRect(
-                CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
-
-        static const int kFlushWaitTimeoutSec = 3; // 3 sec
-        static const int kReqWaitTimeoutMs = 33;   // 33ms
-        static const int kReqWaitTimesMax = 90;    // 33ms * 90 ~= 3 sec
-
-        void waitForNextRequest(std::shared_ptr<HalRequest>* out);
-        void signalRequestDone();
-
-        int cropAndScaleLocked(
-                sp<AllocatedFrame>& in, const Size& outSize,
-                YCbCrLayout* out);
-
-        int cropAndScaleThumbLocked(
-                sp<AllocatedFrame>& in, const Size& outSize,
-                YCbCrLayout* out);
-
-        int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out,
-                Size sz, uint32_t format);
-
-        static int encodeJpegYU12(const Size &inSz,
-                const YCbCrLayout& inLayout, int jpegQuality,
-                const void *app1Buffer, size_t app1Size,
-                void *out, size_t maxOutSize,
-                size_t &actualCodeSize);
-
-        int createJpegLocked(HalStreamBuffer &halBuf, const std::shared_ptr<HalRequest>& req);
-
-        const wp<ExternalCameraDeviceSession> mParent;
-        const CroppingType mCroppingType;
-
-        mutable std::mutex mRequestListLock;      // Protect acccess to mRequestList,
-                                                  // mProcessingRequest and mProcessingFrameNumer
-        std::condition_variable mRequestCond;     // signaled when a new request is submitted
-        std::condition_variable mRequestDoneCond; // signaled when a request is done processing
-        std::list<std::shared_ptr<HalRequest>> mRequestList;
-        bool mProcessingRequest = false;
-        uint32_t mProcessingFrameNumer = 0;
-
-        // V4L2 frameIn
-        // (MJPG decode)-> mYu12Frame
-        // (Scale)-> mScaledYu12Frames
-        // (Format convert) -> output gralloc frames
-        mutable std::mutex mBufferLock; // Protect access to intermediate buffers
-        sp<AllocatedFrame> mYu12Frame;
-        sp<AllocatedFrame> mYu12ThumbFrame;
-        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
-        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
-        YCbCrLayout mYu12FrameLayout;
-        YCbCrLayout mYu12ThumbFrameLayout;
-        uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
-
-        std::string mExifMake;
-        std::string mExifModel;
-    };
-
     // Protect (most of) HIDL interface methods from synchronized-entering
     mutable Mutex mInterfaceLock;
 
@@ -345,7 +321,7 @@
     const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
     const std::vector<SupportedV4L2Format> mSupportedFormats;
     const CroppingType mCroppingType;
-    const std::string& mCameraId;
+    const std::string mCameraId;
 
     // Not protected by mLock, this is almost a const.
     // Setup in constructor, reset in close() after OutputThread is joined
@@ -381,12 +357,6 @@
     std::mutex mInflightFramesLock; // protect mInflightFrames
     std::unordered_set<uint32_t>  mInflightFrames;
 
-    // buffers currently circulating between HAL and camera service
-    // key: bufferId sent via HIDL interface
-    // value: imported buffer_handle_t
-    // Buffer will be imported during processCaptureRequest and will be freed
-    // when the its stream is deleted or camera device session is closed
-    typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
     // Stream ID -> circulating buffers map
     std::map<int, CirculatingBuffers> mCirculatingBuffers;
     // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
@@ -395,6 +365,8 @@
     std::mutex mAfTriggerLock; // protect mAfTrigger
     bool mAfTrigger = false;
 
+    uint32_t mBlobBufferSize = 0;
+
     static HandleImporter sHandleImporter;
 
     /* Beginning of members not changed after initialize() */
@@ -410,6 +382,9 @@
 
     const Size mMaxThumbResolution;
     const Size mMaxJpegResolution;
+
+    std::string mExifMake;
+    std::string mExifModel;
     /* End of members not changed after initialize() */
 
 private:
@@ -484,4 +459,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index bd79807..88726f4 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -105,7 +105,7 @@
     // Calls into virtual member function. Do not use it in constructor
     status_t initCameraCharacteristics();
     // Init available capabilities keys
-    status_t initAvailableCapabilities(
+    virtual status_t initAvailableCapabilities(
             ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
     // Init non-device dependent keys
     virtual status_t initDefaultCharsKeys(
@@ -149,6 +149,7 @@
     bool mInitialized = false;
     bool mInitFailed = false;
     std::string mCameraId;
+    std::string mDevicePath;
     const ExternalCameraConfig& mCfg;
     std::vector<SupportedV4L2Format> mSupportedFormats;
     CroppingType mCroppingType;
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 341c622..b354406 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -17,16 +17,27 @@
 #ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
 #define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
 
+#include <android/hardware/camera/common/1.0/types.h>
+#include <android/hardware/camera/device/3.2/types.h>
+#include <android/hardware/graphics/common/1.0/types.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <inttypes.h>
 #include <mutex>
+#include <unordered_map>
 #include <unordered_set>
 #include <vector>
 #include "tinyxml2.h"  // XML parsing
 #include "utils/LightRefBase.h"
+#include "utils/Timers.h"
+#include <CameraMetadata.h>
+#include <HandleImporter.h>
 
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
 
 namespace android {
 namespace hardware {
@@ -57,6 +68,9 @@
     static const char* kDefaultCfgPath;
     static ExternalCameraConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
 
+    // CameraId base offset for numerical representation
+    uint32_t cameraIdOffset;
+
     // List of internal V4L2 video nodes external camera HAL must ignore.
     std::unordered_set<std::string> mInternalDevices;
 
@@ -113,16 +127,28 @@
     std::vector<FrameRate> frameRates;
 };
 
+// A Base class with basic information about a frame
+struct Frame : public VirtualLightRefBase {
+public:
+    Frame(uint32_t width, uint32_t height, uint32_t fourcc);
+    const uint32_t mWidth;
+    const uint32_t mHeight;
+    const uint32_t mFourcc;
+
+    // getData might involve map/allocation
+    virtual int getData(uint8_t** outData, size_t* dataSize) = 0;
+};
+
 // A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
 // Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
-class V4L2Frame : public virtual VirtualLightRefBase {
+class V4L2Frame : public Frame {
 public:
     V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd,
               uint32_t dataSize, uint64_t offset);
     ~V4L2Frame() override;
-    const uint32_t mWidth;
-    const uint32_t mHeight;
-    const uint32_t mFourcc;
+
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
     const int mBufferIndex; // for later enqueue
     int map(uint8_t** data, size_t* dataSize);
     int unmap();
@@ -137,13 +163,13 @@
 
 // A RAII class representing a CPU allocated YUV frame used as intermeidate buffers
 // when generating output images.
-class AllocatedFrame : public virtual VirtualLightRefBase {
+class AllocatedFrame : public Frame {
 public:
-    AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size?
+    AllocatedFrame(uint32_t w, uint32_t h); // only support V4L2_PIX_FMT_YUV420 for now
     ~AllocatedFrame() override;
-    const uint32_t mWidth;
-    const uint32_t mHeight;
-    const uint32_t mFourcc; // Only support YU12 format for now
+
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
     int allocate(YCbCrLayout* out = nullptr);
     int getLayout(YCbCrLayout* out);
     int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
@@ -165,8 +191,110 @@
 
 bool isAspectRatioClose(float ar1, float ar2);
 
+struct HalStreamBuffer {
+    int32_t streamId;
+    uint64_t bufferId;
+    uint32_t width;
+    uint32_t height;
+    ::android::hardware::graphics::common::V1_0::PixelFormat format;
+    ::android::hardware::camera::device::V3_2::BufferUsageFlags usage;
+    buffer_handle_t* bufPtr;
+    int acquireFence;
+    bool fenceTimeout;
+};
+
+struct HalRequest {
+    uint32_t frameNumber;
+    common::V1_0::helper::CameraMetadata setting;
+    sp<Frame> frameIn;
+    nsecs_t shutterTs;
+    std::vector<HalStreamBuffer> buffers;
+};
+
+static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
+// buffers currently circulating between HAL and camera service
+// key: bufferId sent via HIDL interface
+// value: imported buffer_handle_t
+// Buffer will be imported during processCaptureRequest (or requestStreamBuffer
+// in the case of HAL buffer manager is enabled) and will be freed
+// when the stream is deleted or camera device session is closed
+typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
+
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+        /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*inout*/HandleImporter& handleImporter,
+        int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf);
+
+static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
+        static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
+        static_cast<uint32_t>('X') << 24;
+
+// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
+uint32_t getFourCcFromLayout(const YCbCrLayout&);
+
+using ::android::hardware::camera::external::common::Size;
+int getCropRect(CroppingType ct, const Size& inSize,
+        const Size& outSize, IMapper::Rect* out);
+
+int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format);
+
+int encodeJpegYU12(const Size &inSz,
+        const YCbCrLayout& inLayout, int jpegQuality,
+        const void *app1Buffer, size_t app1Size,
+        void *out, size_t maxOutSize,
+        size_t &actualCodeSize);
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&);
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>&);
+
+status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp,
+        camera_metadata_ro_entry& activeArraySize);
+
+// Interface for OutputThread calling back to parent
+struct OutputThreadInterface : public virtual RefBase {
+    virtual ::android::hardware::camera::common::V1_0::Status importBuffer(
+            int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) = 0;
+
+    virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) = 0;
+
+    // Callbacks are fired within the method if msgs/results are nullptr.
+    // Otherwise the callbacks will be returned and caller is responsible to
+    // fire the callback later
+    virtual ::android::hardware::camera::common::V1_0::Status processCaptureRequestError(
+            const std::shared_ptr<HalRequest>&,
+            /*out*/std::vector<V3_2::NotifyMsg>* msgs = nullptr,
+            /*out*/std::vector<V3_2::CaptureResult>* results = nullptr) = 0;
+
+    virtual ::android::hardware::camera::common::V1_0::Status processCaptureResult(
+            std::shared_ptr<HalRequest>&) = 0;
+
+    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0;
+};
+
 }  // namespace implementation
 }  // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame.
+class AllocatedV4L2Frame : public V3_4::implementation::Frame {
+public:
+    AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn);
+    ~AllocatedV4L2Frame() override;
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+private:
+    std::vector<uint8_t> mData;
+};
+
+} // namespace implementation
+} // namespace V3_6
 }  // namespace device
 }  // namespace camera
 }  // namespace hardware
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
index 43362fd..d106b4b 100644
--- a/camera/device/3.5/default/Android.bp
+++ b/camera/device/3.5/default/Android.bp
@@ -17,13 +17,13 @@
 cc_library_headers {
     name: "camera.device@3.5-impl_headers",
     vendor: true,
-    export_include_dirs: ["include/device_v3_5_impl"]
+    export_include_dirs: ["include/device_v3_5_impl"],
 }
 
 cc_library_headers {
     name: "camera.device@3.5-external-impl_headers",
     vendor: true,
-    export_include_dirs: ["include/ext_device_v3_5_impl"]
+    export_include_dirs: ["include/ext_device_v3_5_impl"],
 }
 
 cc_library_shared {
@@ -49,7 +49,9 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
+        "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
     ],
@@ -81,8 +83,10 @@
         "android.hardware.camera.device@3.5",
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
-	"android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
+        "libgralloctypes",
         "libhardware",
         "libcamera_metadata",
         "libfmq",
@@ -90,7 +94,7 @@
         "libyuv",
         "libjpeg",
         "libexif",
-        "libtinyxml2"
+        "libtinyxml2",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
index 00c1d0d..287ac32 100644
--- a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
@@ -80,7 +80,7 @@
 
 
 ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread(
-        wp<ExternalCameraDeviceSession> parent,
+        wp<OutputThreadInterface> parent,
         sp<V3_5::ICameraDeviceCallback> callbacks) :
         mParent(parent),
         mCallbacks(callbacks) {}
@@ -254,7 +254,8 @@
         mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5);
         mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
     }
-    mOutputThread = new OutputThread(this, mCroppingType, mBufferRequestThread);
+    mOutputThread = new OutputThread(
+            this, mCroppingType, mCameraCharacteristics, mBufferRequestThread);
 }
 
 void ExternalCameraDeviceSession::closeOutputThreadImpl() {
@@ -271,10 +272,11 @@
 }
 
 ExternalCameraDeviceSession::OutputThread::OutputThread(
-        wp<ExternalCameraDeviceSession> parent,
+        wp<OutputThreadInterface> parent,
         CroppingType ct,
+        const common::V1_0::helper::CameraMetadata& chars,
         sp<BufferRequestThread> bufReqThread) :
-        V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct),
+        V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct, chars),
         mBufferRequestThread(bufReqThread) {}
 
 ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
index 281f93a..e89ef45 100644
--- a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
 
 #include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
 #include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
@@ -72,6 +72,7 @@
 
 using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
 using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::HalStreamBuffer;
 
 struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCameraDeviceSession {
 
@@ -97,6 +98,62 @@
                 config, supportedFormats, devCfg);
     }
 
+    class BufferRequestThread : public android::Thread {
+    public:
+        BufferRequestThread(
+                wp<OutputThreadInterface> parent,
+                sp<V3_5::ICameraDeviceCallback> callbacks);
+
+        int requestBufferStart(const std::vector<HalStreamBuffer>&);
+        int waitForBufferRequestDone(
+                /*out*/std::vector<HalStreamBuffer>*);
+
+        virtual bool threadLoop() override;
+
+    private:
+        void waitForNextRequest();
+
+        const wp<OutputThreadInterface> mParent;
+        const sp<V3_5::ICameraDeviceCallback> mCallbacks;
+
+        std::mutex mLock;
+        bool mRequestingBuffer = false;
+
+        std::vector<HalStreamBuffer> mBufferReqs;
+        std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
+        // mHalBufferReqs is not under mLock protection during the HIDL transaction
+        hidl_vec<BufferRequest>      mHalBufferReqs;
+
+        // request buffers takes much less time in steady state, but can take much longer
+        // when requesting 1st buffer from a stream.
+        // TODO: consider a separate timeout for new vs. steady state?
+        // TODO: or make sure framework is warming up the pipeline during configure new stream?
+        static const int kReqProcTimeoutMs = 66;
+
+        static const int kReqWaitTimeoutMs = 33;
+        static const int kReqWaitTimesWarn = 90;  // 33ms * 90 ~= 3 sec
+        std::condition_variable mRequestCond;     // signaled when a new buffer request incoming
+        std::condition_variable mRequestDoneCond; // signaled when a request is done
+    };
+
+    class OutputThread :
+            public V3_4::implementation::ExternalCameraDeviceSession::OutputThread {
+    public:
+        // TODO: pass buffer request thread to OutputThread ctor
+        OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+                const common::V1_0::helper::CameraMetadata&,
+                sp<BufferRequestThread> bufReqThread);
+        virtual ~OutputThread();
+
+    protected:
+        // Methods to request output buffer in parallel
+        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) override;
+        virtual int waitForBufferRequestDone(
+                /*out*/std::vector<HalStreamBuffer>*) override;
+
+        const sp<BufferRequestThread> mBufferRequestThread;
+    };
+
 protected:
     // Methods from v3.4 and earlier will trampoline to inherited implementation
     Return<void> configureStreams_3_5(
@@ -120,63 +177,8 @@
             hidl_vec<buffer_handle_t*>& allBufPtrs,
             hidl_vec<int>& allFences) override;
 
-    class BufferRequestThread : public android::Thread {
-    public:
-        BufferRequestThread(
-                wp<ExternalCameraDeviceSession> parent,
-                sp<V3_5::ICameraDeviceCallback> callbacks);
-
-        int requestBufferStart(const std::vector<HalStreamBuffer>&);
-        int waitForBufferRequestDone(
-                /*out*/std::vector<HalStreamBuffer>*);
-
-        virtual bool threadLoop() override;
-
-    private:
-        void waitForNextRequest();
-
-        const wp<ExternalCameraDeviceSession> mParent;
-        const sp<V3_5::ICameraDeviceCallback> mCallbacks;
-
-        std::mutex mLock;
-        bool mRequestingBuffer = false;
-
-        std::vector<HalStreamBuffer> mBufferReqs;
-        std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
-        // mHalBufferReqs is not under mLock protection during the HIDL transaction
-        hidl_vec<BufferRequest>      mHalBufferReqs;
-
-        // request buffers takes much less time in steady state, but can take much longer
-        // when requesting 1st buffer from a stream.
-        // TODO: consider a separate timeout for new vs. steady state?
-        // TODO: or make sure framework is warming up the pipeline during configure new stream?
-        static const int kReqProcTimeoutMs = 66;
-
-        static const int kReqWaitTimeoutMs = 33;
-        static const int kReqWaitTimesWarn = 90;  // 33ms * 90 ~= 3 sec
-        std::condition_variable mRequestCond;     // signaled when a new buffer request incoming
-        std::condition_variable mRequestDoneCond; // signaled when a request is done
-    };
-
     sp<BufferRequestThread> mBufferRequestThread;
 
-    class OutputThread :
-            public V3_4::implementation::ExternalCameraDeviceSession::OutputThread {
-    public:
-        // TODO: pass buffer request thread to OutputThread ctor
-        OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType,
-                sp<BufferRequestThread> bufReqThread);
-        virtual ~OutputThread();
-
-    protected:
-        // Methods to request output buffer in parallel
-        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) override;
-        virtual int waitForBufferRequestDone(
-                /*out*/std::vector<HalStreamBuffer>*) override;
-
-        const sp<BufferRequestThread> mBufferRequestThread;
-    };
-
     sp<V3_5::ICameraDeviceCallback> mCallback_3_5;
     bool mSupportBufMgr;
 
@@ -270,4 +272,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.5/types.hal b/camera/device/3.5/types.hal
index 6d861e2..38493b4 100644
--- a/camera/device/3.5/types.hal
+++ b/camera/device/3.5/types.hal
@@ -23,7 +23,8 @@
 /**
  * If the result metadata cannot be produced for a physical camera device part of a logical
  * multi-camera, then HAL must invoke the notification callback and pass a message with ERROR_RESULT
- * code and errorStreamId that contains the stream id associated with that physical device.
+ * code and errorStreamId that contains the stream id associated with that physical device. Such
+ * callback must be made before the final processCaptureResult() call for the corresponding request.
  * The behavior during absent result metadata remains unchanged for a logical or a non-logical
  * camera device and the errorStreamId must be set to -1.
  */
diff --git a/camera/device/3.6/Android.bp b/camera/device/3.6/Android.bp
new file mode 100644
index 0000000..e6f458c
--- /dev/null
+++ b/camera/device/3.6/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.device@3.6",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "ICameraDevice.hal",
+        "ICameraDeviceSession.hal",
+        "ICameraOfflineSession.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.common@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.device@3.5",
+        "android.hardware.graphics.common@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/camera/device/3.6/ICameraDevice.hal b/camera/device/3.6/ICameraDevice.hal
new file mode 100644
index 0000000..e859606
--- /dev/null
+++ b/camera/device/3.6/ICameraDevice.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.6;
+
+import @3.5::ICameraDevice;
+
+/**
+ * Camera device interface
+ *
+ * Supports the android.hardware.Camera API, and the android.hardware.camera2
+ * API at LIMITED or better hardware level.
+ *
+ * ICameraDevice.open() must return @3.2::ICameraDeviceSession or
+ * @3.5::ICameraDeviceSession or @3.6::ICameraDeviceSession.
+ */
+interface ICameraDevice extends @3.5::ICameraDevice {
+};
diff --git a/camera/device/3.6/ICameraDeviceSession.hal b/camera/device/3.6/ICameraDeviceSession.hal
new file mode 100644
index 0000000..00ebcc3
--- /dev/null
+++ b/camera/device/3.6/ICameraDeviceSession.hal
@@ -0,0 +1,132 @@
+/*
+ * 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.camera.device@3.6;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.5::ICameraDeviceSession;
+import @3.5::StreamConfiguration;
+import ICameraOfflineSession;
+
+/**
+ * Camera device active session interface.
+ *
+ * Obtained via ICameraDevice::open(), this interface contains the methods to
+ * configure and request captures from an active camera device.
+ */
+interface ICameraDeviceSession extends @3.5::ICameraDeviceSession {
+    /**
+     * configureStreams_3_6:
+     *
+     * Identical to @3.5::ICameraDeviceSession.configureStreams, except that:
+     *
+     * - a boolean supportOffline is added to HalStreamConfiguration to indicate
+     *   if this stream can be switched to offline mode later.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On successful stream configuration.
+     *     INTERNAL_ERROR:
+     *         If there has been a fatal error and the device is no longer
+     *         operational. Only close() can be called successfully by the
+     *         framework after this error is returned.
+     *     ILLEGAL_ARGUMENT:
+     *         If the requested stream configuration is invalid. Some examples
+     *         of invalid stream configurations include:
+     *           - Including more than 1 INPUT stream
+     *           - Not including any OUTPUT streams
+     *           - Including streams with unsupported formats, or an unsupported
+     *             size for that format.
+     *           - Including too many output streams of a certain format.
+     *           - Unsupported rotation configuration
+     *           - Stream sizes/formats don't satisfy the
+     *             StreamConfigurationMode requirements
+     *             for non-NORMAL mode, or the requested operation_mode is not
+     *             supported by the HAL.
+     *           - Unsupported usage flag
+     *         The camera service cannot filter out all possible illegal stream
+     *         configurations, since some devices may support more simultaneous
+     *         streams or larger stream resolutions than the minimum required
+     *         for a given camera device hardware level. The HAL must return an
+     *         ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+     *         ready to accept a future valid stream configuration in a later
+     *         configureStreams call.
+     * @return halConfiguration The stream parameters desired by the HAL for
+     *     each stream, including maximum buffers, the usage flags, and the
+     *     override format.
+     */
+    configureStreams_3_6(@3.5::StreamConfiguration requestedConfiguration)
+        generates (Status status, HalStreamConfiguration halConfiguration);
+
+    /**
+     * switchToOffline:
+     *
+     * Switch the current running session from actively streaming mode to the
+     * offline mode. See ICameraOfflineSession for more details.
+     *
+     * The streamsToKeep argument contains list of streams IDs where application
+     * still needs its output. For all streams application does not need anymore,
+     * camera HAL can send ERROR_BUFFER to speed up the transition, or even send
+     * ERROR_REQUEST if all output targets of a request is not needed. By the
+     * time this call returns, camera HAL must have returned all buffers coming
+     * from streams no longer needed and have erased buffer caches of such streams.
+     *
+     * For all requests that are going to be transferred to offline session,
+     * the ICameraDeviceSession is responsible to capture all input buffers from
+     * the image sensor before the switchToOffline call returns. Before
+     * switchToOffline returns, camera HAL must have completed all requests not
+     * switching to offline mode, and collected information on what streams and
+     * requests are going to continue in the offline session, in the
+     * offlineSessionInfo output argument.
+     *
+     * If there are no requests qualified to be transferred to offline session,
+     * the camera HAL must return a null ICameraOfflineSession object with OK
+     * status. In this scenario, the camera HAL still must flush all inflight
+     * requests and unconfigure all streams before returning this call.
+     *
+     * After switchToOffline returns, the ICameraDeviceSession must be back to
+     * unconfigured state as if it is just created and no streams are configured.
+     * Also, camera HAL must not call any methods in ICameraDeviceCallback since
+     * all unfinished requests are now transferred to the offline session.
+     * After the call returns, camera service may then call close to close
+     * the camera device, or call configureStream* again to reconfigure the
+     * camera and then send new capture requests with processCaptureRequest. In
+     * the latter case, it is legitimate for camera HAL to call methods in
+     * ICameraDeviceCallback again in response to the newly submitted capture
+     * requests.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On switching to offline session and unconfiguring streams
+     *         successfully.
+     *     ILLEGAL_ARGUMENT:
+     *         If camera does not support offline mode in any one of streams
+     *         in streamsToKeep argument. Note that the camera HAL must report
+     *         if a stream supports offline mode in HalStreamConfiguration
+     *         output of configureStreams_3_6 method. If all streams in
+     *         streamsToKeep argument support offline mode, then the camera HAL
+     *         must not return this error.
+     *
+     *
+     * @return offlineSessionInfo Information on what streams and requests will
+     *     be transferred to offline session to continue processing.
+     *
+     * @return offlineSession The offline session object camera service will use
+     *     to interact with.
+     */
+    switchToOffline(vec<int32_t> streamsToKeep) generates (Status status,
+        CameraOfflineSessionInfo offlineSessionInfo, ICameraOfflineSession offlineSession);
+};
diff --git a/camera/device/3.6/ICameraOfflineSession.hal b/camera/device/3.6/ICameraOfflineSession.hal
new file mode 100644
index 0000000..03cea64
--- /dev/null
+++ b/camera/device/3.6/ICameraOfflineSession.hal
@@ -0,0 +1,80 @@
+/*
+ * 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.camera.device@3.6;
+
+import @3.5::ICameraDeviceCallback;
+
+/**
+ * Camera device offline session interface.
+ *
+ * Obtained via ICameraDeviceSession::switchToOffline(), this interface contains
+ * the methods and callback interfaces that define how camera service interacts
+ * with an offline session.
+ *
+ * An offline session contains some unfinished capture requests that were submitted
+ * to the parent ICameraDeviceSession before calling switchToOffline, and is
+ * responsible for delivering these capture results back to camera service regardless
+ * of whether the parent camera device is still opened or not. An offline session must
+ * not have access to the camera device's image sensor. During switchToOffline
+ * call, camera HAL must capture all necessary frames from the image sensor that
+ * is needed for completing the requests offline later.
+ */
+interface ICameraOfflineSession {
+    /**
+     * Set the callbacks for offline session to communicate with camera service.
+     *
+     * Offline session is responsible to store all callbacks the camera HAL
+     * generated after the return of ICameraDeviceSession::switchToOffline, and
+     * send them to camera service once this method is called.
+     *
+     * Camera service must not call this method more than once, so these
+     * callbacks can be assumed to be constant after the first setCallback call.
+     */
+    setCallback(ICameraDeviceCallback cb);
+
+    /**
+     * getCaptureResultMetadataQueue:
+     *
+     * Retrieves the queue used along with
+     * ICameraDeviceCallback#processCaptureResult.
+     *
+     * Clients to ICameraOfflineSession must:
+     * - Call getCaptureRequestMetadataQueue to retrieve the fast message queue;
+     * - In implementation of ICameraDeviceCallback, test whether
+     *   .fmqResultSize field is zero.
+     *     - If .fmqResultSize != 0, read result metadata from the fast message
+     *       queue;
+     *     - otherwise, read result metadata in CaptureResult.result.
+     *
+     * @return queue the queue that implementation writes result metadata to.
+     */
+    getCaptureResultMetadataQueue() generates (fmq_sync<uint8_t> queue);
+
+    /**
+     * Close the offline session and release all resources.
+     *
+     * Camera service may call this method before or after the offline session
+     * has finished all requests it needs to handle. If there are still unfinished
+     * requests when close is called, camera HAL must send ERROR_REQUEST for
+     * all unfinished requests and return all buffers via
+     * ICameraDeviceCallback#processCaptureResult or
+     * ICameraDeviceCallback#returnStreamBuffers.
+     * Also, all buffer caches maintained by the offline session must be erased
+     * before the close call returns.
+     */
+    close();
+};
diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp
new file mode 100644
index 0000000..2871e2a
--- /dev/null
+++ b/camera/device/3.6/default/Android.bp
@@ -0,0 +1,68 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+    name: "camera.device@3.6-external-impl_headers",
+    vendor: true,
+    export_include_dirs: ["include/ext_device_v3_6_impl"],
+}
+
+cc_library_shared {
+    name: "camera.device@3.6-external-impl",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    vendor: true,
+    srcs: [
+        "ExternalCameraDevice.cpp",
+        "ExternalCameraDeviceSession.cpp",
+        "ExternalCameraOfflineSession.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libutils",
+        "libcutils",
+        "camera.device@3.2-impl",
+        "camera.device@3.3-impl",
+        "camera.device@3.4-external-impl",
+        "camera.device@3.5-external-impl",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.device@3.5",
+        "android.hardware.camera.device@3.6",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "liblog",
+        "libgralloctypes",
+        "libhardware",
+        "libcamera_metadata",
+        "libfmq",
+        "libsync",
+        "libyuv",
+        "libjpeg",
+        "libexif",
+        "libtinyxml2",
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    local_include_dirs: ["include/ext_device_v3_6_impl"],
+    export_shared_lib_headers: [
+        "libfmq",
+    ],
+}
diff --git a/camera/device/3.6/default/ExternalCameraDevice.cpp b/camera/device/3.6/default/ExternalCameraDevice.cpp
new file mode 100644
index 0000000..244c7dd
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDevice.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ExtCamDev@3.6"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include "ExternalCameraDevice_3_6.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDevice::ExternalCameraDevice(
+        const std::string& cameraId, const ExternalCameraConfig& cfg) :
+        V3_5::implementation::ExternalCameraDevice(cameraId, cfg) {}
+
+ExternalCameraDevice::~ExternalCameraDevice() {}
+
+sp<V3_4::implementation::ExternalCameraDeviceSession> ExternalCameraDevice::createSession(
+        const sp<V3_2::ICameraDeviceCallback>& cb,
+        const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats,
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        unique_fd v4l2Fd) {
+    return new ExternalCameraDeviceSession(
+            cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd));
+}
+
+#define UPDATE(tag, data, size)                    \
+do {                                               \
+  if (metadata->update((tag), (data), (size))) {   \
+    ALOGE("Update " #tag " failed!");              \
+    return -EINVAL;                                \
+  }                                                \
+} while (0)
+
+status_t ExternalCameraDevice::initAvailableCapabilities(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    status_t res =
+            V3_4::implementation::ExternalCameraDevice::initAvailableCapabilities(metadata);
+
+    if (res != OK) {
+        return res;
+    }
+
+    camera_metadata_entry caps = metadata->find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    std::vector<uint8_t> availableCapabilities;
+
+    for (size_t i = 0; i < caps.count; i++) {
+        uint8_t capability = caps.data.u8[i];
+        availableCapabilities.push_back(capability);
+    }
+
+    // Add OFFLINE_PROCESSING capability to device 3.6
+    availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING);
+
+    UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+           availableCapabilities.data(),
+           availableCapabilities.size());
+
+    return OK;
+}
+
+#undef UPDATE
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
new file mode 100644
index 0000000..8fd8e58
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ExtCamDevSsn@3.6"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDeviceSession::ExternalCameraDeviceSession(
+        const sp<V3_2::ICameraDeviceCallback>& callback,
+        const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats,
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        unique_fd v4l2Fd) :
+        V3_5::implementation::ExternalCameraDeviceSession(
+                callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) {
+}
+
+ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {}
+
+
+Return<void> ExternalCameraDeviceSession::configureStreams_3_6(
+        const StreamConfiguration& requestedConfiguration,
+        ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb)  {
+    V3_2::StreamConfiguration config_v32;
+    V3_3::HalStreamConfiguration outStreams_v33;
+    V3_6::HalStreamConfiguration outStreams;
+    const V3_4::StreamConfiguration& requestedConfiguration_3_4 = requestedConfiguration.v3_4;
+    Mutex::Autolock _il(mInterfaceLock);
+
+    config_v32.operationMode = requestedConfiguration_3_4.operationMode;
+    config_v32.streams.resize(requestedConfiguration_3_4.streams.size());
+    uint32_t blobBufferSize = 0;
+    int numStallStream = 0;
+    for (size_t i = 0; i < config_v32.streams.size(); i++) {
+        config_v32.streams[i] = requestedConfiguration_3_4.streams[i].v3_2;
+        if (config_v32.streams[i].format == PixelFormat::BLOB) {
+            blobBufferSize = requestedConfiguration_3_4.streams[i].bufferSize;
+            numStallStream++;
+        }
+    }
+
+    // Fail early if there are multiple BLOB streams
+    if (numStallStream > kMaxStallStream) {
+        ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__,
+                kMaxStallStream, numStallStream);
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, outStreams);
+        return Void();
+    }
+
+    Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize);
+
+    fillOutputStream3_6(outStreams_v33, &outStreams);
+
+    _hidl_cb(status, outStreams);
+    return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::switchToOffline(
+        const hidl_vec<int32_t>& streamsToKeep,
+        ICameraDeviceSession::switchToOffline_cb _hidl_cb) {
+    std::vector<NotifyMsg> msgs;
+    std::vector<CaptureResult> results;
+    CameraOfflineSessionInfo info;
+    sp<ICameraOfflineSession> session;
+
+    Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session);
+
+    mCallback->notify(msgs);
+    hidl_vec<CaptureResult> hidlResults(std::move(results));
+    invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true);
+    V3_4::implementation::freeReleaseFences(hidlResults);
+
+    _hidl_cb(st, info, session);
+    return Void();
+}
+
+void ExternalCameraDeviceSession::fillOutputStream3_6(
+        const V3_3::HalStreamConfiguration& outStreams_v33,
+        /*out*/V3_6::HalStreamConfiguration* outStreams_v36) {
+    if (outStreams_v36 == nullptr) {
+        ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__);
+        return;
+    }
+    Mutex::Autolock _l(mLock);
+    outStreams_v36->streams.resize(outStreams_v33.streams.size());
+    for (size_t i = 0; i < outStreams_v36->streams.size(); i++) {
+        outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i];
+        outStreams_v36->streams[i].supportOffline =
+                supportOfflineLocked(outStreams_v33.streams[i].v3_2.id);
+    }
+}
+
+bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) {
+    const Stream& stream = mStreamMap[streamId];
+    if (stream.format == PixelFormat::BLOB &&
+            stream.dataSpace == static_cast<int32_t>(Dataspace::V0_JFIF)) {
+        return true;
+    }
+    // TODO: support YUV output stream?
+    return false;
+}
+
+bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+        std::shared_ptr<V3_4::implementation::HalRequest> halReq) {
+    for (const auto& buffer : halReq->buffers) {
+        for (auto offlineStreamId : offlineStreams) {
+            if (buffer.streamId == offlineStreamId) {
+                return false;
+            }
+        }
+    }
+    // Only drop a request completely if it has no offline output
+    return true;
+}
+
+void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+        std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+        const std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*out*/CameraOfflineSessionInfo* info) {
+    if (info == nullptr) {
+        ALOGE("%s: output info must not be null!", __FUNCTION__);
+        return;
+    }
+
+    info->offlineStreams.resize(offlineStreams.size());
+    info->offlineRequests.resize(offlineReqs.size());
+
+    // Fill in offline reqs and count outstanding buffers
+    for (size_t i = 0; i < offlineReqs.size(); i++) {
+        info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
+        info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
+        for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
+            int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
+            info->offlineRequests[i].pendingStreams[bIdx] = streamId;
+        }
+    }
+
+    for (size_t i = 0; i < offlineStreams.size(); i++) {
+        int32_t streamId = offlineStreams[i];
+        info->offlineStreams[i].id = streamId;
+        // outstanding buffers are 0 since we are doing hal buffer management and
+        // offline session will ask for those buffers later
+        info->offlineStreams[i].numOutstandingBuffers = 0;
+        const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
+        info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
+        size_t bIdx = 0;
+        for (const auto& pair : bufIdMap) {
+            // Fill in bufferId
+            info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
+        }
+
+    }
+}
+
+Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+        /*out*/std::vector<NotifyMsg>* msgs,
+        /*out*/std::vector<CaptureResult>* results,
+        /*out*/CameraOfflineSessionInfo* info,
+        /*out*/sp<ICameraOfflineSession>* session) {
+    ATRACE_CALL();
+    if (offlineStreams.size() > 1) {
+        ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
+        ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__,
+                msgs, results, info, session);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    msgs->clear();
+    results->clear();
+
+    Mutex::Autolock _il(mInterfaceLock);
+    Status status = initStatus();
+    if (status != Status::OK) {
+        return status;
+    }
+
+    Mutex::Autolock _l(mLock);
+    for (auto streamId : offlineStreams) {
+        if (!supportOfflineLocked(streamId)) {
+            return Status::ILLEGAL_ARGUMENT;
+        }
+    }
+
+    // pause output thread and get all remaining inflight requests
+    auto remainingReqs = mOutputThread->switchToOffline();
+    std::vector<std::shared_ptr<V3_4::implementation::HalRequest>> halReqs;
+
+    // Send out buffer/request error for remaining requests and filter requests
+    // to be handled in offline mode
+    for (auto& halReq : remainingReqs) {
+        bool dropReq = canDropRequest(offlineStreams, halReq);
+        if (dropReq) {
+            // Request is dropped completely. Just send request error and
+            // there is no need to send the request to offline session
+            processCaptureRequestError(halReq, msgs, results);
+            continue;
+        }
+
+        // All requests reach here must have at least one offline stream output
+        NotifyMsg shutter;
+        shutter.type = MsgType::SHUTTER;
+        shutter.msg.shutter.frameNumber = halReq->frameNumber;
+        shutter.msg.shutter.timestamp = halReq->shutterTs;
+        msgs->push_back(shutter);
+
+        std::vector<V3_4::implementation::HalStreamBuffer> offlineBuffers;
+        for (const auto& buffer : halReq->buffers) {
+            bool dropBuffer = true;
+            for (auto offlineStreamId : offlineStreams) {
+                if (buffer.streamId == offlineStreamId) {
+                    dropBuffer = false;
+                    break;
+                }
+            }
+            if (dropBuffer) {
+                NotifyMsg error;
+                error.type = MsgType::ERROR;
+                error.msg.error.frameNumber = halReq->frameNumber;
+                error.msg.error.errorStreamId = buffer.streamId;
+                error.msg.error.errorCode = ErrorCode::ERROR_BUFFER;
+                msgs->push_back(error);
+
+                CaptureResult result;
+                result.frameNumber = halReq->frameNumber;
+                result.partialResult = 0; // buffer only result
+                result.inputBuffer.streamId = -1;
+                result.outputBuffers.resize(1);
+                result.outputBuffers[0].streamId = buffer.streamId;
+                result.outputBuffers[0].bufferId = buffer.bufferId;
+                result.outputBuffers[0].status = BufferStatus::ERROR;
+                if (buffer.acquireFence >= 0) {
+                    native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                    handle->data[0] = buffer.acquireFence;
+                    result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false);
+                }
+                results->push_back(result);
+            } else {
+                offlineBuffers.push_back(buffer);
+            }
+        }
+        halReq->buffers = offlineBuffers;
+        halReqs.push_back(halReq);
+    }
+
+    // convert hal requests to offline request
+    std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+    size_t i = 0;
+    for (auto& v4lReq : halReqs) {
+        offlineReqs[i] = std::make_shared<HalRequest>();
+        offlineReqs[i]->frameNumber = v4lReq->frameNumber;
+        offlineReqs[i]->setting = v4lReq->setting;
+        offlineReqs[i]->shutterTs = v4lReq->shutterTs;
+        offlineReqs[i]->buffers = v4lReq->buffers;
+        sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+                static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
+        offlineReqs[i]->frameIn = new AllocatedV4L2Frame(v4l2Frame);
+        i++;
+        // enqueue V4L2 frame
+        enqueueV4l2Frame(v4l2Frame);
+    }
+
+    // Collect buffer caches/streams
+    hidl_vec<Stream> streamInfos;
+    streamInfos.resize(offlineStreams.size());
+    std::map<int, CirculatingBuffers> circulatingBuffers;
+    {
+        Mutex::Autolock _l(mCbsLock);
+        size_t idx = 0;
+        for(auto streamId : offlineStreams) {
+            circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
+            mCirculatingBuffers.erase(streamId);
+            streamInfos[idx++] = mStreamMap.at(streamId);
+            mStreamMap.erase(streamId);
+        }
+    }
+
+    fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
+
+    // create the offline session object
+    bool afTrigger;
+    {
+        std::lock_guard<std::mutex> lk(mAfTriggerLock);
+        afTrigger = mAfTrigger;
+    }
+    sp<ExternalCameraOfflineSession> sessionImpl = new ExternalCameraOfflineSession(
+            mCroppingType, mCameraCharacteristics, mCameraId,
+            mExifMake, mExifModel, mBlobBufferSize, afTrigger,
+            streamInfos, offlineReqs, circulatingBuffers);
+
+    bool initFailed = sessionImpl->initialize();
+    if (initFailed) {
+        ALOGE("%s: offline session initialize failed!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    // cleanup stream and buffer caches
+    {
+        Mutex::Autolock _l(mCbsLock);
+        for(auto pair : mStreamMap) {
+            cleanupBuffersLocked(/*Stream ID*/pair.first);
+        }
+        mCirculatingBuffers.clear();
+    }
+    mStreamMap.clear();
+
+    // update inflight records
+    {
+        std::lock_guard<std::mutex> lk(mInflightFramesLock);
+        mInflightFrames.clear();
+    }
+
+    // stop v4l2 streaming
+    if (v4l2StreamOffLocked() !=0) {
+        ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    // No need to return session if there is no offline requests left
+    if (offlineReqs.size() != 0) {
+        *session = sessionImpl->getInterface();
+    } else {
+        *session = nullptr;
+    }
+    return Status::OK;
+}
+
+} // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
new file mode 100644
index 0000000..e606fda
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ExtCamOfflnSsn@3.6"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+#include <android/log.h>
+
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace {
+
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+} // anonymous namespace
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+// static instance
+HandleImporter ExternalCameraOfflineSession::sHandleImporter;
+
+using V3_5::implementation::ExternalCameraDeviceSession;
+
+ExternalCameraOfflineSession::ExternalCameraOfflineSession(
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        const std::string& exifMake,
+        const std::string& exifModel,
+        const uint32_t blobBufferSize,
+        const bool afTrigger,
+        const hidl_vec<Stream>& offlineStreams,
+        std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+        const std::map<int, CirculatingBuffers>& circulatingBuffers) :
+        mCroppingType(croppingType), mChars(chars), mCameraId(cameraId),
+        mExifMake(exifMake), mExifModel(exifModel), mBlobBufferSize(blobBufferSize),
+        mAfTrigger(afTrigger), mOfflineStreams(offlineStreams), mOfflineReqs(offlineReqs),
+        mCirculatingBuffers(circulatingBuffers) {}
+
+ExternalCameraOfflineSession::~ExternalCameraOfflineSession() {
+    close();
+}
+
+bool ExternalCameraOfflineSession::initialize() {
+    mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
+            kMetadataMsgQueueSize, false /* non blocking */);
+    if (!mResultMetadataQueue->isValid()) {
+        ALOGE("%s: invalid result fmq", __FUNCTION__);
+        return true;
+    }
+    return false;
+}
+
+void ExternalCameraOfflineSession::initOutputThread() {
+    if (mOutputThread != nullptr) {
+        ALOGE("%s: OutputThread already exist!", __FUNCTION__);
+        return;
+    }
+
+    mBufferRequestThread = new ExternalCameraDeviceSession::BufferRequestThread(
+            this, mCallback);
+    mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
+
+    mOutputThread = new OutputThread(this, mCroppingType, mChars,
+            mBufferRequestThread, mOfflineReqs);
+
+    mOutputThread->setExifMakeModel(mExifMake, mExifModel);
+
+    Size inputSize = { mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight};
+    Size maxThumbSize = V3_4::implementation::getMaxThumbnailResolution(mChars);
+    mOutputThread->allocateIntermediateBuffers(
+            inputSize, maxThumbSize, mOfflineStreams, mBlobBufferSize);
+
+    mOutputThread->run("ExtCamOfflnOut", PRIORITY_DISPLAY);
+}
+
+bool ExternalCameraOfflineSession::OutputThread::threadLoop() {
+    auto parent = mParent.promote();
+    if (parent == nullptr) {
+       ALOGE("%s: session has been disconnected!", __FUNCTION__);
+       return false;
+    }
+
+    if (mOfflineReqs.empty()) {
+        ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__);
+        return false;
+    }
+
+    std::shared_ptr<HalRequest> req = mOfflineReqs.front();
+    mOfflineReqs.pop_front();
+
+    auto onDeviceError = [&](auto... args) {
+        ALOGE(args...);
+        parent->notifyError(
+                req->frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+        signalRequestDone();
+        return false;
+    };
+
+    if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
+        return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+                req->frameIn->mFourcc & 0xFF,
+                (req->frameIn->mFourcc >> 8) & 0xFF,
+                (req->frameIn->mFourcc >> 16) & 0xFF,
+                (req->frameIn->mFourcc >> 24) & 0xFF);
+    }
+
+    int res = requestBufferStart(req->buffers);
+    if (res != 0) {
+        ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+        return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+    }
+
+    std::unique_lock<std::mutex> lk(mBufferLock);
+    // Convert input V4L2 frame to YU12 of the same size
+    // TODO: see if we can save some computation by converting to YV12 here
+    uint8_t* inData;
+    size_t inDataSize;
+    if (req->frameIn->getData(&inData, &inDataSize) != 0) {
+        lk.unlock();
+        return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+    }
+
+    // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+    if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+        ATRACE_BEGIN("MJPGtoI420");
+        int res = libyuv::MJPGToI420(
+            inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y), mYu12FrameLayout.yStride,
+            static_cast<uint8_t*>(mYu12FrameLayout.cb), mYu12FrameLayout.cStride,
+            static_cast<uint8_t*>(mYu12FrameLayout.cr), mYu12FrameLayout.cStride,
+            mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth, mYu12Frame->mHeight);
+        ATRACE_END();
+
+        if (res != 0) {
+            // For some webcam, the first few V4L2 frames might be malformed...
+            ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
+            lk.unlock();
+            Status st = parent->processCaptureRequestError(req);
+            if (st != Status::OK) {
+                return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+            }
+            signalRequestDone();
+            return true;
+        }
+    }
+
+    ATRACE_BEGIN("Wait for BufferRequest done");
+    res = waitForBufferRequestDone(&req->buffers);
+    ATRACE_END();
+
+    if (res != 0) {
+        ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+        lk.unlock();
+        return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+    }
+
+    ALOGV("%s processing new request", __FUNCTION__);
+    const int kSyncWaitTimeoutMs = 500;
+    for (auto& halBuf : req->buffers) {
+        if (*(halBuf.bufPtr) == nullptr) {
+            ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+            halBuf.fenceTimeout = true;
+        } else if (halBuf.acquireFence >= 0) {
+            int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+            if (ret) {
+                halBuf.fenceTimeout = true;
+            } else {
+                ::close(halBuf.acquireFence);
+                halBuf.acquireFence = -1;
+            }
+        }
+
+        if (halBuf.fenceTimeout) {
+            continue;
+        }
+
+        // Gralloc lockYCbCr the buffer
+        switch (halBuf.format) {
+            case PixelFormat::BLOB: {
+                int ret = createJpegLocked(halBuf, req->setting);
+
+                if(ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: createJpegLocked failed with %d",
+                          __FUNCTION__, ret);
+                }
+            } break;
+            case PixelFormat::Y16: {
+                void* outLayout = sHandleImporter.lock(*(halBuf.bufPtr), halBuf.usage, inDataSize);
+
+                std::memcpy(outLayout, inData, inDataSize);
+
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            case PixelFormat::YCBCR_420_888:
+            case PixelFormat::YV12: {
+                IMapper::Rect outRect {0, 0,
+                        static_cast<int32_t>(halBuf.width),
+                        static_cast<int32_t>(halBuf.height)};
+                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+                        *(halBuf.bufPtr), halBuf.usage, outRect);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                        __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
+                        outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
+
+                // Convert to output buffer size/format
+                uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout);
+                ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__,
+                        outputFourcc & 0xFF,
+                        (outputFourcc >> 8) & 0xFF,
+                        (outputFourcc >> 16) & 0xFF,
+                        (outputFourcc >> 24) & 0xFF);
+
+                YCbCrLayout cropAndScaled;
+                ATRACE_BEGIN("cropAndScaleLocked");
+                int ret = cropAndScaleLocked(
+                        mYu12Frame,
+                        Size { halBuf.width, halBuf.height },
+                        &cropAndScaled);
+                ATRACE_END();
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
+                }
+
+                Size sz {halBuf.width, halBuf.height};
+                ATRACE_BEGIN("formatConvert");
+                ret = V3_4::implementation::formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
+                ATRACE_END();
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: format coversion failed!", __FUNCTION__);
+                }
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            default:
+                lk.unlock();
+                return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+        }
+    } // for each buffer
+    mScaledYu12Frames.clear();
+
+    // Don't hold the lock while calling back to parent
+    lk.unlock();
+    Status st = parent->processCaptureResult(req);
+    if (st != Status::OK) {
+        return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
+    }
+    signalRequestDone();
+    return true;
+}
+
+Status ExternalCameraOfflineSession::importBuffer(int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf) {
+    Mutex::Autolock _l(mCbsLock);
+    return V3_4::implementation::importBufferImpl(
+            mCirculatingBuffers, sHandleImporter, streamId,
+            bufId, buf, outBufPtr, allowEmptyBuf);
+    return Status::OK;
+};
+
+#define UPDATE(md, tag, data, size)               \
+do {                                              \
+    if ((md).update((tag), (data), (size))) {     \
+        ALOGE("Update " #tag " failed!");         \
+        return BAD_VALUE;                         \
+    }                                             \
+} while (0)
+
+status_t ExternalCameraOfflineSession::fillCaptureResult(
+        common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
+    bool afTrigger = false;
+    {
+        std::lock_guard<std::mutex> lk(mAfTriggerLock);
+        afTrigger = mAfTrigger;
+        if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+            camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+            if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+                mAfTrigger = afTrigger = true;
+            } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+                mAfTrigger = afTrigger = false;
+            }
+        }
+    }
+
+    // For USB camera, the USB camera handles everything and we don't have control
+    // over AF. We only simply fake the AF metadata based on the request
+    // received here.
+    uint8_t afState;
+    if (afTrigger) {
+        afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+    } else {
+        afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+    }
+    UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+    camera_metadata_ro_entry activeArraySize =
+            mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+    return V3_4::implementation::fillCaptureResultCommon(md, timestamp, activeArraySize);
+}
+
+#undef UPDATE
+
+Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
+    ATRACE_CALL();
+    // Fill output buffers
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    CaptureResult& result = results[0];
+    result.frameNumber = req->frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req->buffers.size());
+    for (size_t i = 0; i < req->buffers.size(); i++) {
+        result.outputBuffers[i].streamId = req->buffers[i].streamId;
+        result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+        if (req->buffers[i].fenceTimeout) {
+            result.outputBuffers[i].status = BufferStatus::ERROR;
+            if (req->buffers[i].acquireFence >= 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+            }
+            notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+        } else {
+            result.outputBuffers[i].status = BufferStatus::OK;
+            // TODO: refactor
+            if (req->buffers[i].acquireFence >= 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+            }
+        }
+    }
+
+    // Fill capture result metadata
+    fillCaptureResult(req->setting, req->shutterTs);
+    const camera_metadata_t *rawResult = req->setting.getAndLock();
+    V3_2::implementation::convertToHidl(rawResult, &result.result);
+    req->setting.unlock(rawResult);
+
+    // Callback into framework
+    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+    V3_4::implementation::freeReleaseFences(results);
+    return Status::OK;
+};
+
+void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback(
+        hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        const nsecs_t NS_TO_SECOND = 1000000000;
+        ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(/* 1s */NS_TO_SECOND) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+                    __FUNCTION__);
+            return;
+        }
+    }
+    if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+        for (CaptureResult &result : results) {
+            if (result.result.size() > 0) {
+                if (mResultMetadataQueue->write(result.result.data(), result.result.size())) {
+                    result.fmqResultSize = result.result.size();
+                    result.result.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    result.fmqResultSize = 0;
+                }
+            } else {
+                result.fmqResultSize = 0;
+            }
+        }
+    }
+    auto status = mCallback->processCaptureResult(results);
+    if (!status.isOk()) {
+        ALOGE("%s: processCaptureResult ERROR : %s", __FUNCTION__,
+              status.description().c_str());
+    }
+
+    mProcessCaptureResultLock.unlock();
+}
+
+Status ExternalCameraOfflineSession::processCaptureRequestError(
+        const std::shared_ptr<HalRequest>& req,
+        /*out*/std::vector<NotifyMsg>* outMsgs,
+        /*out*/std::vector<CaptureResult>* outResults) {
+    ATRACE_CALL();
+
+    if (outMsgs == nullptr) {
+        notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+    } else {
+        NotifyMsg shutter;
+        shutter.type = MsgType::SHUTTER;
+        shutter.msg.shutter.frameNumber = req->frameNumber;
+        shutter.msg.shutter.timestamp = req->shutterTs;
+
+        NotifyMsg error;
+        error.type = MsgType::ERROR;
+        error.msg.error.frameNumber = req->frameNumber;
+        error.msg.error.errorStreamId = -1;
+        error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+        outMsgs->push_back(shutter);
+        outMsgs->push_back(error);
+    }
+
+    // Fill output buffers
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    CaptureResult& result = results[0];
+    result.frameNumber = req->frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req->buffers.size());
+    for (size_t i = 0; i < req->buffers.size(); i++) {
+        result.outputBuffers[i].streamId = req->buffers[i].streamId;
+        result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+        result.outputBuffers[i].status = BufferStatus::ERROR;
+        if (req->buffers[i].acquireFence >= 0) {
+            native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+            handle->data[0] = req->buffers[i].acquireFence;
+            result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+        }
+    }
+
+    if (outResults == nullptr) {
+        // Callback into framework
+        invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+        V3_4::implementation::freeReleaseFences(results);
+    } else {
+        outResults->push_back(result);
+    }
+    return Status::OK;
+};
+
+ssize_t ExternalCameraOfflineSession::getJpegBufferSize(
+        uint32_t /*width*/, uint32_t /*height*/) const {
+    // Empty implementation here as the jpeg buffer size is passed in by ctor
+    return 0;
+};
+
+void ExternalCameraOfflineSession::notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) {
+    NotifyMsg msg;
+    msg.type = MsgType::ERROR;
+    msg.msg.error.frameNumber = frameNumber;
+    msg.msg.error.errorStreamId = streamId;
+    msg.msg.error.errorCode = ec;
+    mCallback->notify({msg});
+};
+
+Return<void> ExternalCameraOfflineSession::setCallback(const sp<ICameraDeviceCallback>& cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    if (mCallback != nullptr && cb != nullptr) {
+        ALOGE("%s: callback must not be set twice!", __FUNCTION__);
+        return Void();
+    }
+    mCallback = cb;
+
+    initOutputThread();
+
+    if (mOutputThread == nullptr) {
+        ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+    }
+    return Void();
+}
+
+Return<void> ExternalCameraOfflineSession::getCaptureResultMetadataQueue(
+        V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    _hidl_cb(*mResultMetadataQueue->getDesc());
+    return Void();
+}
+
+void ExternalCameraOfflineSession::cleanupBuffersLocked(int id) {
+    for (auto& pair : mCirculatingBuffers.at(id)) {
+        sHandleImporter.freeBuffer(pair.second);
+    }
+    mCirculatingBuffers[id].clear();
+    mCirculatingBuffers.erase(id);
+}
+
+Return<void> ExternalCameraOfflineSession::close() {
+    Mutex::Autolock _il(mInterfaceLock);
+    {
+        Mutex::Autolock _l(mLock);
+        if (mClosed) {
+            ALOGW("%s: offline session already closed!", __FUNCTION__);
+            return Void();
+        }
+    }
+    if (mBufferRequestThread) {
+        mBufferRequestThread->requestExit();
+        mBufferRequestThread->join();
+        mBufferRequestThread.clear();
+    }
+    if (mOutputThread) {
+        mOutputThread->flush();
+        mOutputThread->requestExit();
+        mOutputThread->join();
+        mOutputThread.clear();
+    }
+
+    Mutex::Autolock _l(mLock);
+    // free all buffers
+    {
+        Mutex::Autolock _cbl(mCbsLock);
+        for(auto stream : mOfflineStreams) {
+            cleanupBuffersLocked(stream.id);
+        }
+    }
+    mCallback.clear();
+    mClosed = true;
+    return Void();
+}
+
+} // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.6/default/OWNERS b/camera/device/3.6/default/OWNERS
new file mode 100644
index 0000000..f48a95c
--- /dev/null
+++ b/camera/device/3.6/default/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
new file mode 100644
index 0000000..db0d9a5
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+
+struct ExternalCameraDeviceSession : public V3_5::implementation::ExternalCameraDeviceSession {
+
+    ExternalCameraDeviceSession(const sp<V3_2::ICameraDeviceCallback>&,
+            const ExternalCameraConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats,
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            unique_fd v4l2Fd);
+    virtual ~ExternalCameraDeviceSession();
+
+    // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+    // dealing with minor version revs and simultaneous implementation and interface inheritance
+    virtual sp<V3_4::ICameraDeviceSession> getInterface() override {
+        return new TrampolineSessionInterface_3_6(this);
+    }
+
+protected:
+    // Methods from v3.5 and earlier will trampoline to inherited implementation
+    Return<void> configureStreams_3_6(
+            const StreamConfiguration& requestedConfiguration,
+            ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb);
+
+    Return<void> switchToOffline(
+            const hidl_vec<int32_t>& streamsToKeep,
+            ICameraDeviceSession::switchToOffline_cb _hidl_cb);
+
+    void fillOutputStream3_6(const V3_3::HalStreamConfiguration& outStreams_v33,
+            /*out*/V3_6::HalStreamConfiguration* outStreams_v36);
+    bool supportOfflineLocked(int32_t streamId);
+
+    // Main body of switchToOffline. This method does not invoke any callbacks
+    // but instead returns the necessary callbacks in output arguments so callers
+    // can callback later without holding any locks
+    Status switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+            /*out*/std::vector<NotifyMsg>* msgs,
+            /*out*/std::vector<CaptureResult>* results,
+            /*out*/CameraOfflineSessionInfo* info,
+            /*out*/sp<ICameraOfflineSession>* session);
+
+    // Whether a request can be completely dropped when switching to offline
+    bool canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+            std::shared_ptr<V3_4::implementation::HalRequest> halReq);
+
+    void fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+            std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+            const std::map<int, CirculatingBuffers>& circulatingBuffers,
+            /*out*/CameraOfflineSessionInfo* info);
+
+private:
+
+    struct TrampolineSessionInterface_3_6 : public ICameraDeviceSession {
+        TrampolineSessionInterface_3_6(sp<ExternalCameraDeviceSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> constructDefaultRequestSettings(
+                RequestTemplate type,
+                V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+            return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+            return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+            return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> getCaptureRequestMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<Status> flush() override {
+            return mParent->flush();
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+        virtual Return<void> configureStreams_3_3(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_3_cb _hidl_cb) override {
+            return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_4(
+                const V3_4::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_4_cb _hidl_cb) override {
+            return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
+            return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_5(
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_5_cb _hidl_cb) override {
+            return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> signalStreamFlush(
+                const hidl_vec<int32_t>& requests,
+                uint32_t streamConfigCounter) override {
+            return mParent->signalStreamFlush(requests, streamConfigCounter);
+        }
+
+        virtual Return<void> isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams,
+                const V3_2::CameraMetadata& newSessionParams,
+                ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) override {
+            return mParent->isReconfigurationRequired(oldSessionParams, newSessionParams, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_6(
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_6_cb _hidl_cb) override {
+            return mParent->configureStreams_3_6(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> switchToOffline(
+                const hidl_vec<int32_t>& streamsToKeep,
+                switchToOffline_cb _hidl_cb) override {
+            return mParent->switchToOffline(streamsToKeep, _hidl_cb);
+        }
+
+    private:
+        sp<ExternalCameraDeviceSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h
new file mode 100644
index 0000000..020bec4
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
+
+#include <android/hardware/camera/device/3.6/ICameraDevice.h>
+
+#include "ExternalCameraDeviceSession.h"
+#include <../../../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_6::ICameraDevice;
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct ExternalCameraDevice : public V3_5::implementation::ExternalCameraDevice {
+
+    // Called by external camera provider HAL.
+    // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+    // be multiple CameraDevice trying to access the same physical camera.  Also, provider will have
+    // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+    // camera is detached.
+    ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg);
+    virtual ~ExternalCameraDevice();
+
+    virtual sp<V3_2::ICameraDevice> getInterface() override {
+        return new TrampolineDeviceInterface_3_6(this);
+    }
+
+protected:
+    virtual sp<V3_4::implementation::ExternalCameraDeviceSession> createSession(
+            const sp<V3_2::ICameraDeviceCallback>&,
+            const ExternalCameraConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats,
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            unique_fd v4l2Fd) override;
+
+    virtual status_t initAvailableCapabilities(
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*) override;
+
+private:
+    struct TrampolineDeviceInterface_3_6 : public ICameraDevice {
+        TrampolineDeviceInterface_3_6(sp<ExternalCameraDevice> parent) :
+            mParent(parent) {}
+
+        virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb)
+                override {
+            return mParent->getResourceCost(_hidl_cb);
+        }
+
+        virtual Return<void> getCameraCharacteristics(
+                V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getCameraCharacteristics(_hidl_cb);
+        }
+
+        virtual Return<Status> setTorchMode(TorchMode mode) override {
+            return mParent->setTorchMode(mode);
+        }
+
+        virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback,
+                V3_2::ICameraDevice::open_cb _hidl_cb) override {
+            return mParent->open(callback, _hidl_cb);
+        }
+
+        virtual Return<void> dumpState(const hidl_handle& fd) override {
+            return mParent->dumpState(fd);
+        }
+
+        virtual Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+                V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb);
+        }
+
+        virtual Return<void> isStreamCombinationSupported(
+                const V3_4::StreamConfiguration& streams,
+                V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) override {
+            return mParent->isStreamCombinationSupported(streams, _hidl_cb);
+        }
+
+    private:
+        sp<ExternalCameraDevice> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
new file mode 100644
index 0000000..230b67c
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+#include <android/hardware/camera/common/1.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <deque>
+#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include <HandleImporter.h>
+#include <Exif.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_5::BufferRequest;
+using ::android::hardware::camera::device::V3_5::BufferRequestStatus;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_2::DataspaceFlags;
+using ::android::hardware::camera::device::V3_2::CameraBlob;
+using ::android::hardware::camera::device::V3_2::CameraBlobId;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::camera::external::common::SizeHasher;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::CirculatingBuffers;
+using ::android::hardware::camera::device::V3_4::implementation::HalRequest;
+using ::android::hardware::camera::device::V3_4::implementation::OutputThreadInterface;
+
+struct ExternalCameraOfflineSession : public virtual RefBase,
+        public virtual OutputThreadInterface {
+
+    ExternalCameraOfflineSession(
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            const std::string& exifMake,
+            const std::string& exifModel,
+            uint32_t blobBufferSize,
+            bool afTrigger,
+            const hidl_vec<Stream>& offlineStreams,
+            std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+            const std::map<int, CirculatingBuffers>& circulatingBuffers);
+
+    bool initialize();
+
+    virtual ~ExternalCameraOfflineSession();
+
+    // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+    // dealing with minor version revs and simultaneous implementation and interface inheritance
+    virtual sp<V3_6::ICameraOfflineSession> getInterface() {
+        return new TrampolineSessionInterface_3_6(this);
+    }
+
+protected:
+
+    // Methods from OutputThreadInterface
+    virtual Status importBuffer(int32_t streamId,
+            uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr,
+            bool allowEmptyBuf) override;
+
+    virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
+
+    virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+            /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+            /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+    virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+    // End of OutputThreadInterface methods
+
+    class OutputThread : public V3_5::implementation::ExternalCameraDeviceSession::OutputThread {
+    public:
+        OutputThread(
+                wp<OutputThreadInterface> parent, CroppingType ct,
+                const common::V1_0::helper::CameraMetadata& chars,
+                sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> bufReqThread,
+                std::deque<std::shared_ptr<HalRequest>>& offlineReqs) :
+                V3_5::implementation::ExternalCameraDeviceSession::OutputThread(
+                        parent, ct, chars, bufReqThread),
+                mOfflineReqs(offlineReqs) {}
+
+        virtual bool threadLoop() override;
+
+    protected:
+        std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+    }; // OutputThread
+
+
+    Return<void> setCallback(const sp<ICameraDeviceCallback>& cb);
+
+    Return<void> getCaptureResultMetadataQueue(
+            V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb);
+
+    Return<void> close();
+
+    void initOutputThread();
+
+    void invokeProcessCaptureResultCallback(
+            hidl_vec<CaptureResult> &results, bool tryWriteFmq);
+
+    status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
+
+    void cleanupBuffersLocked(int id);
+
+    // Protect (most of) HIDL interface methods from synchronized-entering
+    mutable Mutex mInterfaceLock;
+
+    mutable Mutex mLock; // Protect all data members except otherwise noted
+
+    bool mClosed = false;
+    const CroppingType mCroppingType;
+    const common::V1_0::helper::CameraMetadata mChars;
+    const std::string mCameraId;
+    const std::string mExifMake;
+    const std::string mExifModel;
+    const uint32_t mBlobBufferSize;
+
+    std::mutex mAfTriggerLock; // protect mAfTrigger
+    bool mAfTrigger;
+
+    const hidl_vec<Stream> mOfflineStreams;
+    std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+
+    // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+    mutable Mutex mCbsLock;
+    std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+    static HandleImporter sHandleImporter;
+
+    using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+    std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+    // Protect against invokeProcessCaptureResultCallback()
+    Mutex mProcessCaptureResultLock;
+
+    sp<ICameraDeviceCallback> mCallback;
+
+    sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> mBufferRequestThread;
+    sp<OutputThread> mOutputThread;
+private:
+
+    struct TrampolineSessionInterface_3_6 : public ICameraOfflineSession {
+        TrampolineSessionInterface_3_6(sp<ExternalCameraOfflineSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> setCallback(const sp<ICameraDeviceCallback>& cb) override {
+            return mParent->setCallback(cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+    private:
+        sp<ExternalCameraOfflineSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
diff --git a/camera/device/3.6/types.hal b/camera/device/3.6/types.hal
new file mode 100644
index 0000000..f4c50ed
--- /dev/null
+++ b/camera/device/3.6/types.hal
@@ -0,0 +1,149 @@
+/*
+ * 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.camera.device@3.6;
+
+import @3.2::BufferCache;
+import @3.4::HalStream;
+
+/**
+ * OfflineRequest:
+ *
+ * Information about a capture request being switched to offline mode via the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct OfflineRequest {
+    /**
+     * Must match a inflight CaptureRequest sent by camera service
+     */
+    uint32_t frameNumber;
+
+    /**
+     * Stream IDs for outputs that will be returned via ICameraDeviceCallback.
+     * The stream ID must be within one of offline stream listed in
+     * CameraOfflineSessionInfo.
+     * Camera service will validate these pending buffers are matching camera
+     * service's record to make sure no buffers are leaked during the
+     * switchToOffline call.
+     */
+    vec<int32_t> pendingStreams;
+};
+
+/**
+ * OfflineStream:
+ *
+ * Information about a stream being switched to offline mode via the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct OfflineStream {
+    /**
+     * IDs of a stream to be transferred to offline session.
+     *
+     * For devices that do not support HAL buffer management, this must be
+     * one of stream ID listed in streamsToKeep argument of the
+     * switchToOffline call.
+     * For devices that support HAL buffer management, this could be any stream
+     * that was configured right before calling switchToOffline.
+     */
+    int32_t id;
+
+    /**
+     * Number of outstanding buffers that will be returned via offline session
+     */
+    uint32_t numOutstandingBuffers;
+
+    /**
+     * Buffer ID of buffers currently cached between camera service and this
+     * stream, which may or may not be owned by the camera HAL right now.
+     * See StreamBuffer#bufferId for more details.
+     */
+    vec<uint64_t> circulatingBufferIds;
+};
+
+/**
+ * CameraOfflineSessionInfo:
+ *
+ * Information about pending outputs that's being transferred to an offline
+ * session from an active session using the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct CameraOfflineSessionInfo {
+    /**
+     * Information on what streams will be preserved in offline session.
+     * Streams not listed here will be removed by camera service after
+     * switchToOffline call returns.
+     */
+    vec<OfflineStream> offlineStreams;
+
+    /**
+     * Information for requests that will be handled by offline session
+     * Camera service will validate this matches what camera service has on
+     * record.
+     */
+    vec<OfflineRequest> offlineRequests;
+};
+
+/**
+ * HalStream:
+ *
+ * The camera HAL's response to each requested stream configuration.
+ *
+ * This version extends the @3.4 HalStream with the physicalCameraId
+ * field
+ */
+struct HalStream {
+    /**
+     * The definition of HalStream from the prior version.
+     */
+    @3.4::HalStream v3_4;
+
+    /**
+     * Whether this stream can be switch to offline mode.
+     *
+     * For devices that does not support the OFFLINE_PROCESSING capability, this
+     * fields will always be false.
+     *
+     * 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;
+};
+
+/**
+ * HalStreamConfiguration:
+ *
+ * Identical to @3.4::HalStreamConfiguration, except that it contains @3.6::HalStream entries.
+ *
+ */
+struct HalStreamConfiguration {
+    vec<HalStream> streams;
+};
diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal
index cef0397..ad671d9 100644
--- a/camera/metadata/3.2/types.hal
+++ b/camera/metadata/3.2/types.hal
@@ -410,7 +410,7 @@
      *
      * <p>List of the maximum number of regions that can be used for metering in
      * auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
-     * this corresponds to the the maximum number of elements in
+     * this corresponds to the maximum number of elements in
      * ANDROID_CONTROL_AE_REGIONS, ANDROID_CONTROL_AWB_REGIONS,
      * and ANDROID_CONTROL_AF_REGIONS.</p>
      *
@@ -1343,8 +1343,8 @@
 
     /** android.sensor.rollingShutterSkew [dynamic, int64, public]
      *
-     * <p>Duration between the start of first row exposure
-     * and the start of last row exposure.</p>
+     * <p>Duration between the start of exposure for the first row of the image sensor,
+     * and the start of exposure for one past the last row of the image sensor.</p>
      */
     ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
 
diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal
index ca0c9d6..0d89681 100644
--- a/camera/metadata/3.3/types.hal
+++ b/camera/metadata/3.3/types.hal
@@ -71,8 +71,10 @@
 
     /** android.lens.poseReference [static, enum, public]
      *
-     * <p>The origin for ANDROID_LENS_POSE_TRANSLATION.</p>
+     * <p>The origin for ANDROID_LENS_POSE_TRANSLATION, and the accuracy of
+     * ANDROID_LENS_POSE_TRANSLATION and ANDROID_LENS_POSE_ROTATION.</p>
      *
+     * @see ANDROID_LENS_POSE_ROTATION
      * @see ANDROID_LENS_POSE_TRANSLATION
      */
     ANDROID_LENS_POSE_REFERENCE = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_LENS_END,
diff --git a/camera/metadata/3.5/Android.bp b/camera/metadata/3.5/Android.bp
new file mode 100644
index 0000000..a28ba43
--- /dev/null
+++ b/camera/metadata/3.5/Android.bp
@@ -0,0 +1,15 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.metadata@3.5",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.metadata@3.2",
+        "android.hardware.camera.metadata@3.3",
+        "android.hardware.camera.metadata@3.4",
+    ],
+    gen_java: true,
+}
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
new file mode 100644
index 0000000..99d6115
--- /dev/null
+++ b/camera/metadata/3.5/types.hal
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.5;
+
+import android.hardware.camera.metadata@3.2;
+import android.hardware.camera.metadata@3.3;
+import android.hardware.camera.metadata@3.4;
+
+// No new metadata sections added in this revision
+
+/**
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
+ */
+enum CameraMetadataTag : @3.4::CameraMetadataTag {
+    /** android.control.availableExtendedSceneModeMaxSizes [static, int32[], ndk_public]
+     *
+     * <p>The list of extended scene modes for ANDROID_CONTROL_EXTENDED_SCENE_MODE that are supported
+     * by this camera device, and each extended scene mode's maximum streaming (non-stall) size
+     * with  effect.</p>
+     *
+     * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE
+     */
+    ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+
+    /** android.control.availableExtendedSceneModeZoomRatioRanges [static, float[], ndk_public]
+     *
+     * <p>The ranges of supported zoom ratio for non-DISABLED ANDROID_CONTROL_EXTENDED_SCENE_MODE.</p>
+     *
+     * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE
+     */
+    ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES,
+
+    /** android.control.extendedSceneMode [dynamic, enum, public]
+     *
+     * <p>Whether extended scene mode is enabled for a particular capture request.</p>
+     */
+    ANDROID_CONTROL_EXTENDED_SCENE_MODE,
+
+    /** android.control.zoomRatioRange [static, float[], public]
+     *
+     * <p>Minimum and maximum zoom ratios supported by this camera device.</p>
+     */
+    ANDROID_CONTROL_ZOOM_RATIO_RANGE,
+
+    /** android.control.zoomRatio [dynamic, float, public]
+     *
+     * <p>The desired zoom ratio</p>
+     */
+    ANDROID_CONTROL_ZOOM_RATIO,
+
+    ANDROID_CONTROL_END_3_5,
+
+    /** android.scaler.availableRotateAndCropModes [static, byte[], hidden]
+     *
+     * <p>List of rotate-and-crop modes for ANDROID_SCALER_ROTATE_AND_CROP that are supported by this camera device.</p>
+     *
+     * @see ANDROID_SCALER_ROTATE_AND_CROP
+     */
+    ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_SCALER_END_3_4,
+
+    /** android.scaler.rotateAndCrop [dynamic, enum, hidden]
+     *
+     * <p>Whether a rotation-and-crop operation is applied to processed
+     * outputs from the camera.</p>
+     */
+    ANDROID_SCALER_ROTATE_AND_CROP,
+
+    ANDROID_SCALER_END_3_5,
+
+};
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
+
+/** android.control.mode enumeration values added since v3.2
+ * @see ANDROID_CONTROL_MODE
+ */
+enum CameraMetadataEnumAndroidControlMode :
+        @3.2::CameraMetadataEnumAndroidControlMode {
+    ANDROID_CONTROL_MODE_USE_EXTENDED_SCENE_MODE,
+};
+
+/** android.control.extendedSceneMode enumeration values
+ * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE
+ */
+enum CameraMetadataEnumAndroidControlExtendedSceneMode : uint32_t {
+    ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED                = 0,
+    ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE,
+    ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS,
+    ANDROID_CONTROL_EXTENDED_SCENE_MODE_VENDOR_START            = 0x40,
+};
+
+/** android.lens.poseReference enumeration values added since v3.3
+ * @see ANDROID_LENS_POSE_REFERENCE
+ */
+enum CameraMetadataEnumAndroidLensPoseReference :
+        @3.3::CameraMetadataEnumAndroidLensPoseReference {
+    ANDROID_LENS_POSE_REFERENCE_UNDEFINED,
+};
+
+/** android.request.availableCapabilities enumeration values added since v3.4
+ * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
+ */
+enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
+        @3.4::CameraMetadataEnumAndroidRequestAvailableCapabilities {
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING,
+};
+
+/** android.scaler.rotateAndCrop enumeration values
+ * @see ANDROID_SCALER_ROTATE_AND_CROP
+ */
+enum CameraMetadataEnumAndroidScalerRotateAndCrop : uint32_t {
+    ANDROID_SCALER_ROTATE_AND_CROP_NONE,
+    ANDROID_SCALER_ROTATE_AND_CROP_90,
+    ANDROID_SCALER_ROTATE_AND_CROP_180,
+    ANDROID_SCALER_ROTATE_AND_CROP_270,
+    ANDROID_SCALER_ROTATE_AND_CROP_AUTO,
+};
diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal
index 74c3ff1..105629d 100644
--- a/camera/provider/2.4/ICameraProvider.hal
+++ b/camera/provider/2.4/ICameraProvider.hal
@@ -115,7 +115,7 @@
      *     INTERNAL_ERROR:
      *         A camera ID list cannot be created. This may be due to
      *         a failure to initialize the camera subsystem, for example.
-     * @return cameraDeviceServiceNames The vector of internal camera device
+     * @return cameraDeviceNames The vector of internal camera device
      *     names known to this provider.
      */
     getCameraIdList()
diff --git a/camera/provider/2.4/ICameraProviderCallback.hal b/camera/provider/2.4/ICameraProviderCallback.hal
index 63dd3c5..8822305 100644
--- a/camera/provider/2.4/ICameraProviderCallback.hal
+++ b/camera/provider/2.4/ICameraProviderCallback.hal
@@ -39,7 +39,7 @@
      * are already present, as soon as the callbacks are available through
      * setCallback.
      *
-     * @param cameraDeviceServiceName The name of the camera device that has a
+     * @param cameraDeviceName The name of the camera device that has a
      *     new status.
      * @param newStatus The new status that device is in.
      *
@@ -57,7 +57,7 @@
      * android.flash.info.available is reported as true via the
      * ICameraDevice::getCameraCharacteristics call.
      *
-     * @param cameraDeviceServiceName The name of the camera device that has a
+     * @param cameraDeviceName The name of the camera device that has a
      *     new status.
      * @param newStatus The new status that device is in.
      *
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index 95e27fd..627ddf4 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -13,6 +13,7 @@
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "camera.device@1.0-impl",
@@ -48,9 +49,11 @@
         "android.hardware.camera.device@3.3",
         "android.hardware.camera.device@3.4",
         "android.hardware.camera.device@3.5",
+        "android.hardware.camera.device@3.6",
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "camera.device@3.3-impl",
@@ -58,6 +61,7 @@
         "camera.device@3.4-impl",
         "camera.device@3.5-external-impl",
         "camera.device@3.5-impl",
+        "camera.device@3.6-external-impl",
         "libcamera_metadata",
         "libcutils",
         "libhardware",
@@ -71,7 +75,8 @@
     ],
     header_libs: [
         "camera.device@3.4-external-impl_headers",
-        "camera.device@3.5-external-impl_headers"
+        "camera.device@3.5-external-impl_headers",
+        "camera.device@3.6-external-impl_headers"
     ],
     export_include_dirs: ["."],
 }
@@ -93,6 +98,8 @@
         "android.hardware.camera.provider@2.4-external",
         "android.hardware.camera.provider@2.4-legacy",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "camera.device@1.0-impl",
@@ -137,6 +144,8 @@
         "android.hardware.camera.device@3.5",
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libbinder",
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index a6fd288..64a51f6 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -26,6 +26,7 @@
 #include "ExternalCameraProviderImpl_2_4.h"
 #include "ExternalCameraDevice_3_4.h"
 #include "ExternalCameraDevice_3_5.h"
+#include "ExternalCameraDevice_3_6.h"
 
 namespace android {
 namespace hardware {
@@ -43,17 +44,19 @@
 const char* kDevicePath = "/dev/";
 constexpr char kPrefix[] = "video";
 constexpr int kPrefixLen = sizeof(kPrefix) - 1;
+constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
 
-bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
-                     std::string* cameraId) {
+bool matchDeviceName(int cameraIdOffset,
+                     const hidl_string& deviceName, std::string* deviceVersion,
+                     std::string* cameraDevicePath) {
     std::string deviceNameStd(deviceName.c_str());
     std::smatch sm;
     if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) {
         if (deviceVersion != nullptr) {
             *deviceVersion = sm[1];
         }
-        if (cameraId != nullptr) {
-            *cameraId = sm[2];
+        if (cameraDevicePath != nullptr) {
+            *cameraDevicePath = "/dev/video" + std::to_string(std::stoi(sm[2]) - cameraIdOffset);
         }
         return true;
     }
@@ -73,6 +76,7 @@
     switch(mPreferredHal3MinorVersion) {
         case 4:
         case 5:
+        case 6:
             // OK
             break;
         default:
@@ -144,8 +148,9 @@
         const hidl_string& cameraDeviceName,
         ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb) {
 
-    std::string cameraId, deviceVersion;
-    bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId);
+    std::string cameraDevicePath, deviceVersion;
+    bool match = matchDeviceName(mCfg.cameraIdOffset, cameraDeviceName,
+                                 &deviceVersion, &cameraDevicePath);
     if (!match) {
         _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
         return Void();
@@ -162,13 +167,19 @@
         case 4: {
             ALOGV("Constructing v3.4 external camera device");
             deviceImpl = new device::V3_4::implementation::ExternalCameraDevice(
-                    cameraId, mCfg);
+                    cameraDevicePath, mCfg);
             break;
         }
         case 5: {
             ALOGV("Constructing v3.5 external camera device");
             deviceImpl = new device::V3_5::implementation::ExternalCameraDevice(
-                    cameraId, mCfg);
+                    cameraDevicePath, mCfg);
+            break;
+        }
+        case 6: {
+            ALOGV("Constructing v3.6 external camera device");
+            deviceImpl = new device::V3_6::implementation::ExternalCameraDevice(
+                    cameraDevicePath, mCfg);
             break;
         }
         default:
@@ -178,7 +189,7 @@
     }
 
     if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
-        ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+        ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraDevicePath.c_str());
         _hidl_cb(Status::INTERNAL_ERROR, nullptr);
         return Void();
     }
@@ -202,10 +213,14 @@
     ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
     Mutex::Autolock _l(mLock);
     std::string deviceName;
-    if (mPreferredHal3MinorVersion == 5) {
-        deviceName = std::string("device@3.5/external/") + devName;
+    std::string cameraId = std::to_string(mCfg.cameraIdOffset +
+                                          std::atoi(devName + kDevicePrefixLen));
+    if (mPreferredHal3MinorVersion == 6) {
+        deviceName = std::string("device@3.6/external/") + cameraId;
+    } else if (mPreferredHal3MinorVersion == 5) {
+        deviceName = std::string("device@3.5/external/") + cameraId;
     } else {
-        deviceName = std::string("device@3.4/external/") + devName;
+        deviceName = std::string("device@3.4/external/") + cameraId;
     }
     mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
     if (mCallbacks != nullptr) {
@@ -249,10 +264,14 @@
 void ExternalCameraProviderImpl_2_4::deviceRemoved(const char* devName) {
     Mutex::Autolock _l(mLock);
     std::string deviceName;
-    if (mPreferredHal3MinorVersion == 5) {
-        deviceName = std::string("device@3.5/external/") + devName;
+    std::string cameraId = std::to_string(mCfg.cameraIdOffset +
+                                          std::atoi(devName + kDevicePrefixLen));
+    if (mPreferredHal3MinorVersion == 6) {
+        deviceName = std::string("device@3.6/external/") + cameraId;
+    } else if (mPreferredHal3MinorVersion == 5) {
+        deviceName = std::string("device@3.5/external/") + cameraId;
     } else {
-        deviceName = std::string("device@3.4/external/") + devName;
+        deviceName = std::string("device@3.4/external/") + cameraId;
     }
     if (mCameraStatusMap.find(deviceName) != mCameraStatusMap.end()) {
         mCameraStatusMap.erase(deviceName);
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 2c3ed37..4b9d6f1 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -38,17 +38,16 @@
         "android.hardware.camera.device@3.3",
         "android.hardware.camera.device@3.4",
         "android.hardware.camera.device@3.5",
-	"android.hardware.camera.metadata@3.4",
+        "android.hardware.camera.device@3.6",
+        "android.hardware.camera.metadata@3.4",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.provider@2.5",
-        "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.camera.provider@2.6",
         "android.hardware.graphics.common@1.0",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
         "android.hidl.allocator@1.0",
         "libgrallocusage",
         "libhidlmemory",
+        "libgralloctypes",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/camera/provider/2.4/vts/functional/AndroidTest.xml b/camera/provider/2.4/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..3000c0e
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalCameraProviderV2_4TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalCameraProviderV2_4TargetTest->/data/local/tmp/VtsHalCameraProviderV2_4TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalCameraProviderV2_4TargetTest" />
+        <option name="native-test-timeout" value="1800000"/> <!-- 30 min -->
+    </test>
+</configuration>
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index a5369e7..f235235 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -18,113 +18,119 @@
 
 #include <algorithm>
 #include <chrono>
+#include <condition_variable>
+#include <list>
 #include <mutex>
 #include <regex>
+#include <string>
 #include <unordered_map>
 #include <unordered_set>
-#include <condition_variable>
 
 #include <inttypes.h>
 
-#include <android/hardware/camera/device/1.0/ICameraDevice.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android/hardware/camera/device/3.5/ICameraDevice.h>
-#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
-#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
-#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
-#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
-#include <android/hardware/camera/metadata/3.4/types.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
-#include <binder/MemoryHeapBase.h>
 #include <CameraMetadata.h>
 #include <CameraParameters.h>
+#include <android/hardware/camera/device/1.0/ICameraDevice.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.5/ICameraDevice.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraDevice.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <android/hardware/camera/metadata/3.4/types.h>
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.6/ICameraProvider.h>
+#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
 #include <cutils/properties.h>
 #include <fmq/MessageQueue.h>
 #include <grallocusage/GrallocUsageConversion.h>
+#include <gtest/gtest.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/BufferQueue.h>
 #include <gui/Surface.h>
 #include <hardware/gralloc.h>
 #include <hardware/gralloc1.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
 #include <system/camera.h>
 #include <system/camera_metadata.h>
 #include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
 
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/2.0/types.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMapper.h>
 #include <android/hidl/memory/1.0/IMemory.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 using namespace ::android::hardware::camera::device;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
+using ::android::BufferItemConsumer;
+using ::android::BufferQueue;
+using ::android::GraphicBuffer;
+using ::android::IGraphicBufferConsumer;
+using ::android::IGraphicBufferProducer;
+using ::android::sp;
+using ::android::Surface;
+using ::android::wp;
 using ::android::hardware::hidl_bitfield;
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
-using ::android::sp;
-using ::android::wp;
-using ::android::GraphicBuffer;
-using ::android::IGraphicBufferProducer;
-using ::android::IGraphicBufferConsumer;
-using ::android::BufferQueue;
-using ::android::BufferItemConsumer;
-using ::android::Surface;
-using ::android::hardware::graphics::common::V1_0::BufferUsage;
-using ::android::hardware::graphics::common::V1_0::Dataspace;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
 using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::Status;
 using ::android::hardware::camera::common::V1_0::TorchMode;
 using ::android::hardware::camera::common::V1_0::TorchModeStatus;
 using ::android::hardware::camera::common::V1_0::helper::CameraParameters;
 using ::android::hardware::camera::common::V1_0::helper::Size;
-using ::android::hardware::camera::provider::V2_4::ICameraProvider;
-using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
-using ::android::hardware::camera::device::V3_2::ICameraDevice;
-using ::android::hardware::camera::device::V3_2::BufferCache;
-using ::android::hardware::camera::device::V3_2::CaptureRequest;
-using ::android::hardware::camera::device::V3_2::CaptureResult;
-using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
-using ::android::hardware::camera::device::V3_2::NotifyMsg;
-using ::android::hardware::camera::device::V3_2::RequestTemplate;
-using ::android::hardware::camera::device::V3_2::StreamType;
-using ::android::hardware::camera::device::V3_2::StreamRotation;
-using ::android::hardware::camera::device::V3_2::StreamConfiguration;
-using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
-using ::android::hardware::camera::device::V3_2::CameraMetadata;
-using ::android::hardware::camera::device::V3_2::HalStreamConfiguration;
-using ::android::hardware::camera::device::V3_2::BufferStatus;
-using ::android::hardware::camera::device::V3_2::StreamBuffer;
-using ::android::hardware::camera::device::V3_2::MsgType;
-using ::android::hardware::camera::device::V3_2::ErrorMsg;
-using ::android::hardware::camera::device::V3_2::ErrorCode;
 using ::android::hardware::camera::device::V1_0::CameraFacing;
-using ::android::hardware::camera::device::V1_0::NotifyCallbackMsg;
+using ::android::hardware::camera::device::V1_0::CameraFrameMetadata;
 using ::android::hardware::camera::device::V1_0::CommandType;
 using ::android::hardware::camera::device::V1_0::DataCallbackMsg;
-using ::android::hardware::camera::device::V1_0::CameraFrameMetadata;
-using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback;
 using ::android::hardware::camera::device::V1_0::FrameCallbackFlag;
 using ::android::hardware::camera::device::V1_0::HandleTimestampMessage;
-using ::android::hardware::camera::metadata::V3_4::CameraMetadataEnumAndroidSensorInfoColorFilterArrangement;
-using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag;
+using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback;
+using ::android::hardware::camera::device::V1_0::NotifyCallbackMsg;
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V3_2::ErrorMsg;
+using ::android::hardware::camera::device::V3_2::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_2::ICameraDevice;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::StreamBuffer;
+using ::android::hardware::camera::device::V3_2::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::android::hardware::camera::device::V3_2::StreamType;
 using ::android::hardware::camera::device::V3_4::PhysicalCameraMetadata;
-using ::android::hardware::MessageQueue;
-using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::camera::metadata::V3_4::
+        CameraMetadataEnumAndroidSensorInfoColorFilterArrangement;
+using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag;
+using ::android::hardware::camera::provider::V2_4::ICameraProvider;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
 using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
 using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hidl::memory::V1_0::IMemory;
 using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
 using ::android::hidl::manager::V1_0::IServiceManager;
 
@@ -132,6 +138,8 @@
 
 const uint32_t kMaxPreviewWidth = 1920;
 const uint32_t kMaxPreviewHeight = 1080;
+const uint32_t kMaxStillWidth = 2048;
+const uint32_t kMaxStillHeight = 1536;
 const uint32_t kMaxVideoWidth = 4096;
 const uint32_t kMaxVideoHeight = 2160;
 const int64_t kStreamBufferTimeoutSec = 3;
@@ -158,14 +166,36 @@
     YUV_REPROCESS,
 };
 
+enum SystemCameraKind {
+    /**
+     * These camera devices are visible to all apps and system components alike
+     */
+    PUBLIC = 0,
+
+    /**
+     * These camera devices are visible only to processes having the
+     * android.permission.SYSTEM_CAMERA permission. They are not exposed to 3P
+     * apps.
+     */
+    SYSTEM_ONLY_CAMERA,
+
+    /**
+     * These camera devices are visible only to HAL clients (that try to connect
+     * on a hwbinder thread).
+     */
+    HIDDEN_SECURE_CAMERA
+};
+
 namespace {
     // "device@<version>/legacy/<id>"
     const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
+    const int CAMERA_DEVICE_API_VERSION_3_6 = 0x306;
     const int CAMERA_DEVICE_API_VERSION_3_5 = 0x305;
     const int CAMERA_DEVICE_API_VERSION_3_4 = 0x304;
     const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303;
     const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
     const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
+    const char *kHAL3_6 = "3.6";
     const char *kHAL3_5 = "3.5";
     const char *kHAL3_4 = "3.4";
     const char *kHAL3_3 = "3.3";
@@ -201,7 +231,9 @@
             return -1;
         }
 
-        if (version.compare(kHAL3_5) == 0) {
+        if (version.compare(kHAL3_6) == 0) {
+            return CAMERA_DEVICE_API_VERSION_3_6;
+        } else if (version.compare(kHAL3_5) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_5;
         } else if (version.compare(kHAL3_4) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_4;
@@ -286,27 +318,6 @@
     }
 }
 
-// Test environment for camera
-class CameraHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static CameraHidlEnvironment* Instance() {
-        static CameraHidlEnvironment* instance = new CameraHidlEnvironment;
-        return instance;
-    }
-
-    virtual void HidlSetUp() override { ALOGI("SetUp CameraHidlEnvironment"); }
-
-    virtual void HidlTearDown() override { ALOGI("TearDown CameraHidlEnvironment"); }
-
-    virtual void registerTestServices() override { registerTestService<ICameraProvider>(); }
-
-   private:
-    CameraHidlEnvironment() {}
-
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(CameraHidlEnvironment);
-};
-
 struct BufferItemHander: public BufferItemConsumer::FrameAvailableListener {
     BufferItemHander(wp<BufferItemConsumer> consumer) : mConsumer(consumer) {}
 
@@ -547,25 +558,34 @@
 }
 
 // The main test class for camera HIDL HAL.
-class CameraHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class CameraHidlTest : public ::testing::TestWithParam<std::string> {
 public:
  virtual void SetUp() override {
-     string service_name = CameraHidlEnvironment::Instance()->getServiceName<ICameraProvider>();
+     std::string service_name = GetParam();
      ALOGI("get service with name: %s", service_name.c_str());
-     mProvider = ::testing::VtsHalHidlTargetTestBase::getService<ICameraProvider>(service_name);
+     mProvider = ICameraProvider::getService(service_name);
+
      ASSERT_NE(mProvider, nullptr);
 
      uint32_t id;
      ASSERT_TRUE(parseProviderName(service_name, &mProviderType, &id));
 
-     castProvider(mProvider, &mProvider2_5);
+     castProvider(mProvider, &mProvider2_5, &mProvider2_6);
      notifyDeviceState(provider::V2_5::DeviceState::NORMAL);
  }
  virtual void TearDown() override {}
 
- hidl_vec<hidl_string> getCameraDeviceNames(sp<ICameraProvider> provider);
+ hidl_vec<hidl_string> getCameraDeviceNames(sp<ICameraProvider> provider,
+                                            bool addSecureOnly = false);
 
-    struct EmptyDeviceCb : public V3_5::ICameraDeviceCallback {
+ bool isSecureOnly(sp<ICameraProvider> provider, const hidl_string& name);
+
+ std::map<hidl_string, hidl_string> getCameraDeviceIdToNameMap(sp<ICameraProvider> provider);
+
+ hidl_vec<hidl_vec<hidl_string>> getConcurrentDeviceCombinations(
+         sp<::android::hardware::camera::provider::V2_6::ICameraProvider>&);
+
+ struct EmptyDeviceCb : public V3_5::ICameraDeviceCallback {
      virtual Return<void> processCaptureResult(
          const hidl_vec<CaptureResult>& /*results*/) override {
          ALOGI("processCaptureResult callback");
@@ -602,8 +622,7 @@
          ADD_FAILURE();  // Empty callback should not reach here
          return Void();
      }
-
-    };
+ };
 
     struct DeviceCb : public V3_5::ICameraDeviceCallback {
         DeviceCb(CameraHidlTest *parent, int deviceVersion, const camera_metadata_t *staticMeta) :
@@ -622,7 +641,7 @@
 
         Return<void> returnStreamBuffers(const hidl_vec<StreamBuffer>& buffers) override;
 
-        void setCurrentStreamConfig(const hidl_vec<V3_2::Stream>& streams,
+        void setCurrentStreamConfig(const hidl_vec<V3_4::Stream>& streams,
                 const hidl_vec<V3_2::HalStream>& halStreams);
 
         void waitForBuffersReturned();
@@ -639,7 +658,7 @@
         /* members for requestStreamBuffers() and returnStreamBuffers()*/
         std::mutex mLock; // protecting members below
         bool                      mUseHalBufManager = false;
-        hidl_vec<V3_2::Stream>    mStreams;
+        hidl_vec<V3_4::Stream>    mStreams;
         hidl_vec<V3_2::HalStream> mHalStreams;
         uint64_t mNextBufferId = 1;
         using OutstandingBuffers = std::unordered_map<uint64_t, hidl_handle>;
@@ -730,12 +749,14 @@
             sp<ICameraDeviceSession> *session /*out*/,
             camera_metadata_t **staticMeta /*out*/,
             ::android::sp<ICameraDevice> *device = nullptr/*out*/);
-    void castProvider(const sp<provider::V2_4::ICameraProvider> &provider,
-            sp<provider::V2_5::ICameraProvider> *provider2_5 /*out*/);
+    void castProvider(const sp<provider::V2_4::ICameraProvider>& provider,
+                      sp<provider::V2_5::ICameraProvider>* provider2_5 /*out*/,
+                      sp<provider::V2_6::ICameraProvider>* provider2_6 /*out*/);
     void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
             sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
             sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
-            sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/);
+            sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
+            sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/);
     void castDevice(const sp<device::V3_2::ICameraDevice> &device, int32_t deviceVersion,
             sp<device::V3_5::ICameraDevice> *device3_5/*out*/);
     void createStreamConfiguration(const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
@@ -745,6 +766,17 @@
             ::android::hardware::camera::device::V3_5::StreamConfiguration *config3_5,
             uint32_t jpegBufferSize = 0);
 
+    void configureOfflineStillStream(const std::string &name, int32_t deviceVersion,
+            sp<ICameraProvider> provider,
+            const AvailableStream *threshold,
+            sp<device::V3_6::ICameraDeviceSession> *session/*out*/,
+            V3_2::Stream *stream /*out*/,
+            device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/,
+            bool *supportsPartialResults /*out*/,
+            uint32_t *partialResultCount /*out*/,
+            sp<DeviceCb> *outCb /*out*/,
+            uint32_t *jpegBufferSize /*out*/,
+            bool *useHalBufManager /*out*/);
     void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
             const AvailableStream *previewThreshold,
@@ -770,12 +802,24 @@
             bool *useHalBufManager /*out*/,
             sp<DeviceCb> *cb /*out*/,
             uint32_t streamConfigCounter = 0);
+    void configureSingleStream(const std::string& name, int32_t deviceVersion,
+            sp<ICameraProvider> provider,
+            const AvailableStream* previewThreshold, uint64_t bufferUsage,
+            RequestTemplate reqTemplate,
+            sp<ICameraDeviceSession>* session /*out*/,
+            V3_2::Stream* previewStream /*out*/,
+            HalStreamConfiguration* halStreamConfig /*out*/,
+            bool* supportsPartialResults /*out*/,
+            uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
+            sp<DeviceCb>* cb /*out*/, uint32_t streamConfigCounter = 0);
 
     void verifyLogicalCameraMetadata(const std::string& cameraName,
             const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device,
             const CameraMetadata& chars, int deviceVersion,
             const hidl_vec<hidl_string>& deviceNames);
     void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
+    void verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata);
+    void verifyZoomCharacteristics(const camera_metadata_t* metadata);
     void verifyRecommendedConfigs(const CameraMetadata& metadata);
     void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
     void verifyMonochromeCameraResult(
@@ -797,15 +841,25 @@
     void verifySessionReconfigurationQuery(sp<device::V3_5::ICameraDeviceSession> session3_5,
             camera_metadata* oldSessionParams, camera_metadata* newSessionParams);
 
-    bool isDepthOnly(camera_metadata_t* staticMeta);
+    void verifyRequestTemplate(const camera_metadata_t* metadata, RequestTemplate requestTemplate);
 
-    static Status getAvailableOutputStreams(camera_metadata_t *staticMeta,
+    static bool isDepthOnly(const camera_metadata_t* staticMeta);
+
+    static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta,
             std::vector<AvailableStream> &outputStreams,
             const AvailableStream *threshold = nullptr);
+
+    static Status getMaxOutputSizeForFormat(const camera_metadata_t* staticMeta, PixelFormat format,
+                                            Size* size);
+
+    static Status getMandatoryConcurrentStreams(const camera_metadata_t* staticMeta,
+                                                std::vector<AvailableStream>* outputStreams);
+
     static Status getJpegBufferSize(camera_metadata_t *staticMeta,
             uint32_t* outBufSize);
     static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
     static Status isLogicalMultiCamera(const camera_metadata_t *staticMeta);
+    static Status isOfflineSessionSupported(const camera_metadata_t *staticMeta);
     static Status getPhysicalCameraIds(const camera_metadata_t *staticMeta,
             std::unordered_set<std::string> *physicalIds/*out*/);
     static Status getSupportedKeys(camera_metadata_t *staticMeta,
@@ -831,6 +885,14 @@
     static Status isAutoFocusModeAvailable(
             CameraParameters &cameraParams, const char *mode) ;
     static Status isMonochromeCamera(const camera_metadata_t *staticMeta);
+    static Status getSystemCameraKind(const camera_metadata_t* staticMeta,
+                                      SystemCameraKind* systemCameraKind);
+
+    void processCaptureRequestInternal(uint64_t bufferusage, RequestTemplate reqTemplate,
+                                       bool useSecureOnlyCameras);
+
+    // Used by switchToOffline where a new result queue is created for offline reqs
+    void updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue);
 
 protected:
 
@@ -865,6 +927,8 @@
         int32_t partialResultCount;
 
         // For buffer drop errors, the stream ID for the stream that lost a buffer.
+        // For physical sub-camera result errors, the Id of the physical stream
+        // for the physical sub-camera.
         // Otherwise -1.
         int32_t errorStreamId;
 
@@ -878,6 +942,8 @@
         // return from HAL but framework.
         ::android::Vector<StreamBuffer> resultOutputBuffers;
 
+        std::unordered_set<std::string> expectedPhysicalResults;
+
         InFlightRequest() :
                 shutterTimestamp(0),
                 errorCodeValid(false),
@@ -907,6 +973,24 @@
                 partialResultCount(0),
                 errorStreamId(-1),
                 hasInputBuffer(hasInput) {}
+
+        InFlightRequest(ssize_t numBuffers, bool hasInput,
+                bool partialResults, uint32_t partialCount,
+                const std::unordered_set<std::string>& extraPhysicalResult,
+                std::shared_ptr<ResultMetadataQueue> queue = nullptr) :
+                shutterTimestamp(0),
+                errorCodeValid(false),
+                errorCode(ErrorCode::ERROR_BUFFER),
+                usePartialResult(partialResults),
+                numPartialResults(partialCount),
+                resultQueue(queue),
+                haveResultMetadata(false),
+                numBuffersLeft(numBuffers),
+                frameNumber(0),
+                partialResultCount(0),
+                errorStreamId(-1),
+                hasInputBuffer(hasInput),
+                expectedPhysicalResults(extraPhysicalResult) {}
     };
 
     // Map from frame number to the in-flight request state
@@ -932,6 +1016,7 @@
     // Camera provider service
     sp<ICameraProvider> mProvider;
     sp<::android::hardware::camera::provider::V2_5::ICameraProvider> mProvider2_5;
+    sp<::android::hardware::camera::provider::V2_6::ICameraProvider> mProvider2_6;
 
     // Camera provider type.
     std::string mProviderType;
@@ -1124,6 +1209,13 @@
             return notify;
         }
 
+        if (physicalCameraMetadata.size() != request->expectedPhysicalResults.size()) {
+            ALOGE("%s: Frame %d: Returned physical metadata count %zu "
+                    "must be equal to expected count %zu", __func__, frameNumber,
+                    physicalCameraMetadata.size(), request->expectedPhysicalResults.size());
+            ADD_FAILURE();
+            return notify;
+        }
         std::vector<::android::hardware::camera::device::V3_2::CameraMetadata> physResultMetadata;
         physResultMetadata.resize(physicalCameraMetadata.size());
         for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
@@ -1251,11 +1343,11 @@
 }
 
 void CameraHidlTest::DeviceCb::setCurrentStreamConfig(
-        const hidl_vec<V3_2::Stream>& streams, const hidl_vec<V3_2::HalStream>& halStreams) {
+        const hidl_vec<V3_4::Stream>& streams, const hidl_vec<V3_2::HalStream>& halStreams) {
     ASSERT_EQ(streams.size(), halStreams.size());
     ASSERT_NE(streams.size(), 0);
     for (size_t i = 0; i < streams.size(); i++) {
-        ASSERT_EQ(streams[i].id, halStreams[i].id);
+        ASSERT_EQ(streams[i].v3_2.id, halStreams[i].id);
     }
     std::lock_guard<std::mutex> l(mLock);
     mUseHalBufManager = true;
@@ -1293,16 +1385,6 @@
     std::lock_guard<std::mutex> l(mParent->mLock);
 
     for (size_t i = 0; i < messages.size(); i++) {
-        ssize_t idx = mParent->mInflightMap.indexOfKey(
-                messages[i].msg.shutter.frameNumber);
-        if (::android::NAME_NOT_FOUND == idx) {
-            ALOGE("%s: Unexpected frame number! received: %u",
-                  __func__, messages[i].msg.shutter.frameNumber);
-            ADD_FAILURE();
-            break;
-        }
-        InFlightRequest *r = mParent->mInflightMap.editValueAt(idx);
-
         switch(messages[i].type) {
             case MsgType::ERROR:
                 if (ErrorCode::ERROR_DEVICE == messages[i].msg.error.errorCode) {
@@ -1310,13 +1392,59 @@
                           __func__);
                     ADD_FAILURE();
                 } else {
-                    r->errorCodeValid = true;
-                    r->errorCode = messages[i].msg.error.errorCode;
-                    r->errorStreamId = messages[i].msg.error.errorStreamId;
+                    ssize_t idx = mParent->mInflightMap.indexOfKey(
+                            messages[i].msg.error.frameNumber);
+                    if (::android::NAME_NOT_FOUND == idx) {
+                        ALOGE("%s: Unexpected error frame number! received: %u",
+                              __func__, messages[i].msg.error.frameNumber);
+                        ADD_FAILURE();
+                        break;
+                    }
+                    InFlightRequest *r = mParent->mInflightMap.editValueAt(idx);
+
+                    if (ErrorCode::ERROR_RESULT == messages[i].msg.error.errorCode &&
+                            messages[i].msg.error.errorStreamId != -1) {
+                        if (r->haveResultMetadata) {
+                            ALOGE("%s: Camera must report physical camera result error before "
+                                    "the final capture result!", __func__);
+                            ADD_FAILURE();
+                        } else {
+                            for (size_t j = 0; j < mStreams.size(); j++) {
+                                if (mStreams[j].v3_2.id == messages[i].msg.error.errorStreamId) {
+                                    hidl_string physicalCameraId = mStreams[j].physicalCameraId;
+                                    bool idExpected = r->expectedPhysicalResults.find(
+                                            physicalCameraId) != r->expectedPhysicalResults.end();
+                                    if (!idExpected) {
+                                        ALOGE("%s: ERROR_RESULT's error stream's physicalCameraId "
+                                                "%s must be expected", __func__,
+                                                physicalCameraId.c_str());
+                                        ADD_FAILURE();
+                                    } else {
+                                        r->expectedPhysicalResults.erase(physicalCameraId);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                    } else {
+                        r->errorCodeValid = true;
+                        r->errorCode = messages[i].msg.error.errorCode;
+                        r->errorStreamId = messages[i].msg.error.errorStreamId;
+                  }
                 }
                 break;
             case MsgType::SHUTTER:
+            {
+                ssize_t idx = mParent->mInflightMap.indexOfKey(messages[i].msg.shutter.frameNumber);
+                if (::android::NAME_NOT_FOUND == idx) {
+                    ALOGE("%s: Unexpected shutter frame number! received: %u",
+                          __func__, messages[i].msg.shutter.frameNumber);
+                    ADD_FAILURE();
+                    break;
+                }
+                InFlightRequest *r = mParent->mInflightMap.editValueAt(idx);
                 r->shutterTimestamp = messages[i].msg.shutter.timestamp;
+            }
                 break;
             default:
                 ALOGE("%s: Unsupported notify message %d", __func__,
@@ -1357,7 +1485,7 @@
     for (size_t i = 0; i < bufReqs.size(); i++) {
         bool found = false;
         for (size_t idx = 0; idx < mStreams.size(); idx++) {
-            if (bufReqs[i].streamId == mStreams[idx].id) {
+            if (bufReqs[i].streamId == mStreams[idx].v3_2.id) {
                 found = true;
                 indexes[i] = idx;
                 break;
@@ -1381,7 +1509,7 @@
         const auto& halStream = mHalStreams[idx];
         const V3_5::BufferRequest& bufReq = bufReqs[i];
         if (mOutstandingBufferIds[idx].size() + bufReq.numBuffersRequested > halStream.maxBuffers) {
-            bufRets[i].streamId = stream.id;
+            bufRets[i].streamId = stream.v3_2.id;
             bufRets[i].val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
             allStreamOk = false;
             continue;
@@ -1390,17 +1518,23 @@
         hidl_vec<StreamBuffer> tmpRetBuffers(bufReq.numBuffersRequested);
         for (size_t j = 0; j < bufReq.numBuffersRequested; j++) {
             hidl_handle buffer_handle;
-            mParent->allocateGraphicBuffer(stream.width, stream.height,
+            uint32_t w = stream.v3_2.width;
+            uint32_t h = stream.v3_2.height;
+            if (stream.v3_2.format == PixelFormat::BLOB) {
+                w = stream.bufferSize;
+                h = 1;
+            }
+            mParent->allocateGraphicBuffer(w, h,
                     android_convertGralloc1To0Usage(
                             halStream.producerUsage, halStream.consumerUsage),
                     halStream.overrideFormat, &buffer_handle);
 
-            tmpRetBuffers[j] = {stream.id, mNextBufferId, buffer_handle, BufferStatus::OK,
+            tmpRetBuffers[j] = {stream.v3_2.id, mNextBufferId, buffer_handle, BufferStatus::OK,
                                 nullptr, nullptr};
             mOutstandingBufferIds[idx].insert(std::make_pair(mNextBufferId++, buffer_handle));
         }
         atLeastOneStreamOk = true;
-        bufRets[i].streamId = stream.id;
+        bufRets[i].streamId = stream.v3_2.id;
         bufRets[i].val.buffers(std::move(tmpRetBuffers));
     }
 
@@ -1426,11 +1560,11 @@
         ADD_FAILURE();
     }
 
-    std::lock_guard<std::mutex> l(mLock);
+    std::unique_lock<std::mutex> l(mLock);
     for (const auto& buf : buffers) {
         bool found = false;
         for (size_t idx = 0; idx < mOutstandingBufferIds.size(); idx++) {
-            if (mStreams[idx].id == buf.streamId &&
+            if (mStreams[idx].v3_2.id == buf.streamId &&
                     mOutstandingBufferIds[idx].count(buf.bufferId) == 1) {
                 mOutstandingBufferIds[idx].erase(buf.bufferId);
                 // TODO: check do we need to close/delete native handle or assume we have enough
@@ -1446,10 +1580,29 @@
         ALOGE("%s: unknown buffer ID %" PRIu64, __FUNCTION__, buf.bufferId);
         ADD_FAILURE();
     }
+    if (!hasOutstandingBuffersLocked()) {
+        l.unlock();
+        mFlushedCondition.notify_one();
+    }
     return Void();
 }
 
-hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames(sp<ICameraProvider> provider) {
+std::map<hidl_string, hidl_string> CameraHidlTest::getCameraDeviceIdToNameMap(
+        sp<ICameraProvider> provider) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(provider);
+    std::map<hidl_string, hidl_string> idToNameMap;
+    for (auto& name : cameraDeviceNames) {
+        std::string version, cameraId;
+        if (!matchDeviceName(name, mProviderType, &version, &cameraId)) {
+            ADD_FAILURE();
+        }
+        idToNameMap.insert(std::make_pair(hidl_string(cameraId), name));
+    }
+    return idToNameMap;
+}
+
+hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames(sp<ICameraProvider> provider,
+                                                           bool addSecureOnly) {
     std::vector<std::string> cameraDeviceNames;
     Return<void> ret;
     ret = provider->getCameraIdList(
@@ -1498,15 +1651,70 @@
         }
     }
 
-    hidl_vec<hidl_string> retList(cameraDeviceNames.size());
+    std::vector<hidl_string> retList;
     for (size_t i = 0; i < cameraDeviceNames.size(); i++) {
-        retList[i] = cameraDeviceNames[i];
+        bool isSecureOnlyCamera = isSecureOnly(mProvider, cameraDeviceNames[i]);
+        if (addSecureOnly) {
+            if (isSecureOnlyCamera) {
+                retList.emplace_back(cameraDeviceNames[i]);
+            }
+        } else if (!isSecureOnlyCamera) {
+            retList.emplace_back(cameraDeviceNames[i]);
+        }
     }
-    return retList;
+    hidl_vec<hidl_string> finalRetList = std::move(retList);
+    return finalRetList;
+}
+
+bool CameraHidlTest::isSecureOnly(sp<ICameraProvider> provider, const hidl_string& name) {
+    Return<void> ret;
+    ::android::sp<ICameraDevice> device3_x;
+    bool retVal = false;
+    if (getCameraDeviceVersion(mProviderType, name) == CAMERA_DEVICE_API_VERSION_1_0) {
+        return false;
+    }
+    ret = provider->getCameraDeviceInterface_V3_x(name, [&](auto status, const auto& device) {
+        ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_NE(device, nullptr);
+        device3_x = device;
+    });
+    if (!ret.isOk()) {
+        ADD_FAILURE() << "Failed to get camera device interface for " << name;
+    }
+    ret = device3_x->getCameraCharacteristics([&](Status s, CameraMetadata metadata) {
+        ASSERT_EQ(Status::OK, s);
+        camera_metadata_t* chars = (camera_metadata_t*)metadata.data();
+        SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+        Status status = getSystemCameraKind(chars, &systemCameraKind);
+        ASSERT_EQ(status, Status::OK);
+        if (systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA) {
+            retVal = true;
+        }
+    });
+    if (!ret.isOk()) {
+        ADD_FAILURE() << "Failed to get camera characteristics for device " << name;
+    }
+    return retVal;
+}
+
+hidl_vec<hidl_vec<hidl_string>> CameraHidlTest::getConcurrentDeviceCombinations(
+        sp<::android::hardware::camera::provider::V2_6::ICameraProvider>& provider2_6) {
+    hidl_vec<hidl_vec<hidl_string>> combinations;
+    Return<void> ret = provider2_6->getConcurrentStreamingCameraIds(
+            [&combinations](Status concurrentIdStatus,
+                            const hidl_vec<hidl_vec<hidl_string>>& cameraDeviceIdCombinations) {
+                ASSERT_EQ(concurrentIdStatus, Status::OK);
+                combinations = cameraDeviceIdCombinations;
+            });
+    if (!ret.isOk()) {
+        ADD_FAILURE();
+    }
+    return combinations;
 }
 
 // Test devices with first_api_level >= P does not advertise device@1.0
-TEST_F(CameraHidlTest, noHal1AfterP) {
+TEST_P(CameraHidlTest, noHal1AfterP) {
     constexpr int32_t HAL1_PHASE_OUT_API_LEVEL = 28;
     int32_t firstApiLevel = 0;
     getFirstApiLevel(&firstApiLevel);
@@ -1531,7 +1739,7 @@
 
 // Test if ICameraProvider::isTorchModeSupported returns Status::OK
 // Also if first_api_level >= Q torch API must be supported.
-TEST_F(CameraHidlTest, isTorchModeSupported) {
+TEST_P(CameraHidlTest, isTorchModeSupported) {
     constexpr int32_t API_LEVEL_Q = 29;
     int32_t firstApiLevel = 0;
     getFirstApiLevel(&firstApiLevel);
@@ -1548,7 +1756,7 @@
 }
 
 // TODO: consider removing this test if getCameraDeviceNames() has the same coverage
-TEST_F(CameraHidlTest, getCameraIdList) {
+TEST_P(CameraHidlTest, getCameraIdList) {
     Return<void> ret;
     ret = mProvider->getCameraIdList([&](auto status, const auto& idList) {
         ALOGI("getCameraIdList returns status:%d", (int)status);
@@ -1561,7 +1769,7 @@
 }
 
 // Test if ICameraProvider::getVendorTags returns Status::OK
-TEST_F(CameraHidlTest, getVendorTags) {
+TEST_P(CameraHidlTest, getVendorTags) {
     Return<void> ret;
     ret = mProvider->getVendorTags([&](auto status, const auto& vendorTagSecs) {
         ALOGI("getVendorTags returns status:%d numSections %zu", (int)status, vendorTagSecs.size());
@@ -1579,7 +1787,7 @@
 }
 
 // Test if ICameraProvider::setCallback returns Status::OK
-TEST_F(CameraHidlTest, setCallback) {
+TEST_P(CameraHidlTest, setCallback) {
     struct ProviderCb : public ICameraProviderCallback {
         virtual Return<void> cameraDeviceStatusChange(
                 const hidl_string& cameraDeviceName,
@@ -1597,6 +1805,33 @@
             return Void();
         }
     };
+
+    struct ProviderCb2_6
+        : public ::android::hardware::camera::provider::V2_6::ICameraProviderCallback {
+        virtual Return<void> cameraDeviceStatusChange(const hidl_string& cameraDeviceName,
+                                                      CameraDeviceStatus newStatus) override {
+            ALOGI("camera device status callback name %s, status %d", cameraDeviceName.c_str(),
+                  (int)newStatus);
+            return Void();
+        }
+
+        virtual Return<void> torchModeStatusChange(const hidl_string& cameraDeviceName,
+                                                   TorchModeStatus newStatus) override {
+            ALOGI("Torch mode status callback name %s, status %d", cameraDeviceName.c_str(),
+                  (int)newStatus);
+            return Void();
+        }
+
+        virtual Return<void> physicalCameraDeviceStatusChange(
+                const hidl_string& cameraDeviceName, const hidl_string& physicalCameraDeviceName,
+                CameraDeviceStatus newStatus) override {
+            ALOGI("physical camera device status callback name %s, physical camera name %s,"
+                  " status %d",
+                  cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(), (int)newStatus);
+            return Void();
+        }
+    };
+
     sp<ProviderCb> cb = new ProviderCb;
     auto status = mProvider->setCallback(cb);
     ASSERT_TRUE(status.isOk());
@@ -1604,15 +1839,26 @@
     status = mProvider->setCallback(nullptr);
     ASSERT_TRUE(status.isOk());
     ASSERT_EQ(Status::OK, status);
+
+    if (mProvider2_6.get() != nullptr) {
+        sp<ProviderCb2_6> cb = new ProviderCb2_6;
+        auto status = mProvider2_6->setCallback(cb);
+        ASSERT_TRUE(status.isOk());
+        ASSERT_EQ(Status::OK, status);
+        status = mProvider2_6->setCallback(nullptr);
+        ASSERT_TRUE(status.isOk());
+        ASSERT_EQ(Status::OK, status);
+    }
 }
 
 // Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
-TEST_F(CameraHidlTest, getCameraDeviceInterface) {
+TEST_P(CameraHidlTest, getCameraDeviceInterface) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -1648,13 +1894,14 @@
 }
 
 // Verify that the device resource cost can be retrieved and the values are
-// sane.
-TEST_F(CameraHidlTest, getResourceCost) {
+// correct.
+TEST_P(CameraHidlTest, getResourceCost) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -1719,7 +1966,7 @@
 
 // Verify that the static camera info can be retrieved
 // successfully.
-TEST_F(CameraHidlTest, getCameraInfo) {
+TEST_P(CameraHidlTest, getCameraInfo) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -1767,7 +2014,7 @@
 }
 
 // Check whether preview window can be configured
-TEST_F(CameraHidlTest, setPreviewWindow) {
+TEST_P(CameraHidlTest, setPreviewWindow) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -1787,7 +2034,7 @@
 }
 
 // Verify that setting preview window fails in case device is not open
-TEST_F(CameraHidlTest, setPreviewWindowInvalid) {
+TEST_P(CameraHidlTest, setPreviewWindowInvalid) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -1812,7 +2059,7 @@
 }
 
 // Start and stop preview checking whether it gets enabled in between.
-TEST_F(CameraHidlTest, startStopPreview) {
+TEST_P(CameraHidlTest, startStopPreview) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -1837,7 +2084,7 @@
 
 // Start preview without active preview window. Preview should start as soon
 // as a valid active window gets configured.
-TEST_F(CameraHidlTest, startStopPreviewDelayed) {
+TEST_P(CameraHidlTest, startStopPreviewDelayed) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -1867,7 +2114,7 @@
 }
 
 // Verify that image capture behaves as expected along with preview callbacks.
-TEST_F(CameraHidlTest, takePicture) {
+TEST_P(CameraHidlTest, takePicture) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -1916,7 +2163,7 @@
 }
 
 // Image capture should fail in case preview didn't get enabled first.
-TEST_F(CameraHidlTest, takePictureFail) {
+TEST_P(CameraHidlTest, takePictureFail) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -1936,7 +2183,7 @@
 }
 
 // Verify that image capture can be cancelled.
-TEST_F(CameraHidlTest, cancelPicture) {
+TEST_P(CameraHidlTest, cancelPicture) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -1963,7 +2210,7 @@
 }
 
 // Image capture cancel is a no-op when image capture is not running.
-TEST_F(CameraHidlTest, cancelPictureNOP) {
+TEST_P(CameraHidlTest, cancelPictureNOP) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -1986,7 +2233,7 @@
 }
 
 // Test basic video recording.
-TEST_F(CameraHidlTest, startStopRecording) {
+TEST_P(CameraHidlTest, startStopRecording) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -2064,7 +2311,7 @@
 }
 
 // It shouldn't be possible to start recording without enabling preview first.
-TEST_F(CameraHidlTest, startRecordingFail) {
+TEST_P(CameraHidlTest, startRecordingFail) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -2088,7 +2335,7 @@
 }
 
 // Check autofocus support if available.
-TEST_F(CameraHidlTest, autoFocus) {
+TEST_P(CameraHidlTest, autoFocus) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<const char*> focusModes = {CameraParameters::FOCUS_MODE_AUTO,
                                            CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE,
@@ -2149,7 +2396,7 @@
 }
 
 // In case autofocus is supported verify that it can be cancelled.
-TEST_F(CameraHidlTest, cancelAutoFocus) {
+TEST_P(CameraHidlTest, cancelAutoFocus) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -2195,7 +2442,7 @@
 }
 
 // Check whether face detection is available and try to enable&disable.
-TEST_F(CameraHidlTest, sendCommandFaceDetection) {
+TEST_P(CameraHidlTest, sendCommandFaceDetection) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -2250,7 +2497,7 @@
 }
 
 // Check whether smooth zoom is available and try to enable&disable.
-TEST_F(CameraHidlTest, sendCommandSmoothZoom) {
+TEST_P(CameraHidlTest, sendCommandSmoothZoom) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -2297,8 +2544,8 @@
     }
 }
 
-// Basic sanity tests related to camera parameters.
-TEST_F(CameraHidlTest, getSetParameters) {
+// Basic correctness tests related to camera parameters.
+TEST_P(CameraHidlTest, getSetParameters) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -2388,14 +2635,99 @@
     }
 }
 
+TEST_P(CameraHidlTest, systemCameraTest) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::map<std::string, std::list<SystemCameraKind>> hiddenPhysicalIdToLogicalMap;
+    for (const auto& name : cameraDeviceNames) {
+        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+        switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
+            case CAMERA_DEVICE_API_VERSION_3_5:
+            case CAMERA_DEVICE_API_VERSION_3_4:
+            case CAMERA_DEVICE_API_VERSION_3_3:
+            case CAMERA_DEVICE_API_VERSION_3_2: {
+                ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
+                ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
+                Return<void> ret;
+                ret = mProvider->getCameraDeviceInterface_V3_x(
+                        name, [&](auto status, const auto& device) {
+                            ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+                            ASSERT_EQ(Status::OK, status);
+                            ASSERT_NE(device, nullptr);
+                            device3_x = device;
+                        });
+                ASSERT_TRUE(ret.isOk());
+
+                ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) {
+                    ASSERT_EQ(status, Status::OK);
+                    const camera_metadata_t* staticMeta =
+                            reinterpret_cast<const camera_metadata_t*>(chars.data());
+                    ASSERT_NE(staticMeta, nullptr);
+                    Status rc = isLogicalMultiCamera(staticMeta);
+                    ASSERT_TRUE(Status::OK == rc || Status::METHOD_NOT_SUPPORTED == rc);
+                    if (Status::METHOD_NOT_SUPPORTED == rc) {
+                        return;
+                    }
+                    std::unordered_set<std::string> physicalIds;
+                    ASSERT_EQ(Status::OK, getPhysicalCameraIds(staticMeta, &physicalIds));
+                    SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+                    rc = getSystemCameraKind(staticMeta, &systemCameraKind);
+                    ASSERT_EQ(rc, Status::OK);
+                    for (auto physicalId : physicalIds) {
+                        bool isPublicId = false;
+                        for (auto& deviceName : cameraDeviceNames) {
+                            std::string publicVersion, publicId;
+                            ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion,
+                                                          &publicId));
+                            if (physicalId == publicId) {
+                                isPublicId = true;
+                                break;
+                            }
+                        }
+                        // For hidden physical cameras, collect their associated logical cameras
+                        // and store the system camera kind.
+                        if (!isPublicId) {
+                            auto it = hiddenPhysicalIdToLogicalMap.find(physicalId);
+                            if (it == hiddenPhysicalIdToLogicalMap.end()) {
+                                hiddenPhysicalIdToLogicalMap.insert(std::make_pair(
+                                        physicalId, std::list<SystemCameraKind>(systemCameraKind)));
+                            } else {
+                                it->second.push_back(systemCameraKind);
+                            }
+                        }
+                    }
+                });
+                ASSERT_TRUE(ret.isOk());
+            } break;
+            case CAMERA_DEVICE_API_VERSION_1_0: {
+                // Not applicable
+            } break;
+            default: {
+                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+                ADD_FAILURE();
+            } break;
+        }
+    }
+
+    // Check that the system camera kind of the logical cameras associated with
+    // each hidden physical camera is the same.
+    for (const auto& it : hiddenPhysicalIdToLogicalMap) {
+        SystemCameraKind neededSystemCameraKind = it.second.front();
+        for (auto foundSystemCamera : it.second) {
+            ASSERT_EQ(neededSystemCameraKind, foundSystemCamera);
+        }
+    }
+}
+
 // Verify that the static camera characteristics can be retrieved
 // successfully.
-TEST_F(CameraHidlTest, getCameraCharacteristics) {
+TEST_P(CameraHidlTest, getCameraCharacteristics) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2456,7 +2788,7 @@
 
 //In case it is supported verify that torch can be enabled.
 //Check for corresponding toch callbacks as well.
-TEST_F(CameraHidlTest, setTorchMode) {
+TEST_P(CameraHidlTest, setTorchMode) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     bool torchControlSupported = false;
     Return<void> ret;
@@ -2475,6 +2807,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2594,13 +2927,14 @@
 }
 
 // Check dump functionality.
-TEST_F(CameraHidlTest, dumpState) {
+TEST_P(CameraHidlTest, dumpState) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     Return<void> ret;
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2659,13 +2993,14 @@
 }
 
 // Open, dumpStates, then close
-TEST_F(CameraHidlTest, openClose) {
+TEST_P(CameraHidlTest, openClose) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     Return<void> ret;
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2695,8 +3030,12 @@
                 sp<device::V3_3::ICameraDeviceSession> sessionV3_3;
                 sp<device::V3_4::ICameraDeviceSession> sessionV3_4;
                 sp<device::V3_5::ICameraDeviceSession> sessionV3_5;
-                castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4, &sessionV3_5);
-                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
+                sp<device::V3_6::ICameraDeviceSession> sessionV3_6;
+                castSession(session, deviceVersion, &sessionV3_3,
+                        &sessionV3_4, &sessionV3_5, &sessionV3_6);
+                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) {
+                    ASSERT_TRUE(sessionV3_6.get() != nullptr);
+                } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
                     ASSERT_TRUE(sessionV3_5.get() != nullptr);
                 } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
                     ASSERT_TRUE(sessionV3_4.get() != nullptr);
@@ -2752,12 +3091,13 @@
 
 // Check whether all common default request settings can be sucessfully
 // constructed.
-TEST_F(CameraHidlTest, constructDefaultRequestSettings) {
+TEST_P(CameraHidlTest, constructDefaultRequestSettings) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2809,13 +3149,7 @@
                                             metadata, &expectedSize);
                                     ASSERT_TRUE((result == 0) ||
                                             (result == CAMERA_METADATA_VALIDATION_SHIFTED));
-                                    size_t entryCount =
-                                            get_camera_metadata_entry_count(metadata);
-                                    // TODO: we can do better than 0 here. Need to check how many required
-                                    // request keys we've defined for each template
-                                    ASSERT_GT(entryCount, 0u);
-                                    ALOGI("template %u metadata entry count is %zu",
-                                          t, entryCount);
+                                    verifyRequestTemplate(metadata, reqTemplate);
                                 } else {
                                     ASSERT_EQ(0u, req.size());
                                 }
@@ -2842,7 +3176,7 @@
 
 // Verify that all supported stream formats and sizes can be configured
 // successfully.
-TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) {
+TEST_P(CameraHidlTest, configureStreamsAvailableOutputs) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<AvailableStream> outputStreams;
 
@@ -2862,11 +3196,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
+        sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider,
                 &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         outputStreams.clear();
@@ -2949,8 +3284,159 @@
     }
 }
 
+// Verify that mandatory concurrent streams and outputs are supported.
+TEST_P(CameraHidlTest, configureConcurrentStreamsAvailableOutputs) {
+    struct CameraTestInfo {
+        camera_metadata_t* staticMeta = nullptr;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        sp<device::V3_5::ICameraDeviceSession> session3_5;
+        sp<device::V3_6::ICameraDeviceSession> session3_6;
+        sp<device::V3_2::ICameraDevice> cameraDevice;
+        sp<device::V3_5::ICameraDevice> cameraDevice3_5;
+        ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
+        ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+        ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+    };
+    if (mProvider2_6 == nullptr) {
+        // This test is provider@2.6 specific
+        ALOGW("%s provider not 2_6, skipping", __func__);
+        return;
+    }
+
+    std::map<hidl_string, hidl_string> idToNameMap = getCameraDeviceIdToNameMap(mProvider2_6);
+    hidl_vec<hidl_vec<hidl_string>> concurrentDeviceCombinations =
+            getConcurrentDeviceCombinations(mProvider2_6);
+    std::vector<AvailableStream> outputStreams;
+    for (const auto& cameraDeviceIds : concurrentDeviceCombinations) {
+        std::vector<CameraIdAndStreamCombination> cameraIdsAndStreamCombinations;
+        std::vector<CameraTestInfo> cameraTestInfos;
+        size_t i = 0;
+        for (const auto& id : cameraDeviceIds) {
+            CameraTestInfo cti;
+            Return<void> ret;
+            auto it = idToNameMap.find(id);
+            ASSERT_TRUE(idToNameMap.end() != it);
+            hidl_string name = it->second;
+            int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+            if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+                continue;
+            } else if (deviceVersion <= 0) {
+                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+                ADD_FAILURE();
+                return;
+            }
+            openEmptyDeviceSession(name, mProvider2_6, &cti.session /*out*/,
+                                   &cti.staticMeta /*out*/, &cti.cameraDevice /*out*/);
+            castSession(cti.session, deviceVersion, &cti.session3_3, &cti.session3_4,
+                        &cti.session3_5, &cti.session3_6);
+            castDevice(cti.cameraDevice, deviceVersion, &cti.cameraDevice3_5);
+
+            outputStreams.clear();
+            ASSERT_EQ(Status::OK, getMandatoryConcurrentStreams(cti.staticMeta, &outputStreams));
+            ASSERT_NE(0u, outputStreams.size());
+
+            uint32_t jpegBufferSize = 0;
+            ASSERT_EQ(Status::OK, getJpegBufferSize(cti.staticMeta, &jpegBufferSize));
+            ASSERT_NE(0u, jpegBufferSize);
+
+            int32_t streamId = 0;
+            ::android::hardware::hidl_vec<V3_2::Stream> streams3_2(outputStreams.size());
+            size_t j = 0;
+            for (const auto& it : outputStreams) {
+                V3_2::Stream stream3_2;
+                V3_2::DataspaceFlags dataspaceFlag = 0;
+                switch (static_cast<PixelFormat>(it.format)) {
+                    case PixelFormat::BLOB:
+                        dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::V0_JFIF);
+                        break;
+                    case PixelFormat::Y16:
+                        dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::DEPTH);
+                        break;
+                    default:
+                        dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::UNKNOWN);
+                }
+                stream3_2 = {streamId++,
+                             StreamType::OUTPUT,
+                             static_cast<uint32_t>(it.width),
+                             static_cast<uint32_t>(it.height),
+                             static_cast<PixelFormat>(it.format),
+                             GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                             dataspaceFlag,
+                             StreamRotation::ROTATION_0};
+                streams3_2[j] = stream3_2;
+                j++;
+            }
+
+            // Add the created stream configs to cameraIdsAndStreamCombinations
+            createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
+                                      &cti.config3_2, &cti.config3_4, &cti.config3_5,
+                                      jpegBufferSize);
+
+            cti.config3_5.streamConfigCounter = outputStreams.size();
+            CameraIdAndStreamCombination cameraIdAndStreamCombination;
+            cameraIdAndStreamCombination.cameraId = id;
+            cameraIdAndStreamCombination.streamConfiguration = cti.config3_4;
+            cameraIdsAndStreamCombinations.push_back(cameraIdAndStreamCombination);
+            i++;
+            cameraTestInfos.push_back(cti);
+        }
+        // Now verify that concurrent streams are supported
+        auto cb = [](Status s, bool supported) {
+            ASSERT_EQ(Status::OK, s);
+            ASSERT_EQ(supported, true);
+        };
+
+        auto ret = mProvider2_6->isConcurrentStreamCombinationSupported(
+                cameraIdsAndStreamCombinations, cb);
+
+        // Test the stream can actually be configured
+        for (const auto& cti : cameraTestInfos) {
+            if (cti.session3_5 != nullptr) {
+                bool expectStreamCombQuery = (isLogicalMultiCamera(cti.staticMeta) == Status::OK);
+                verifyStreamCombination(cti.cameraDevice3_5, cti.config3_4,
+                                        /*expectedStatus*/ true, expectStreamCombQuery);
+                ret = cti.session3_5->configureStreams_3_5(
+                        cti.config3_5,
+                        [&cti](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(cti.config3_5.v3_4.streams.size(), halConfig.streams.size());
+                        });
+            } else if (cti.session3_4 != nullptr) {
+                ret = cti.session3_4->configureStreams_3_4(
+                        cti.config3_4,
+                        [&cti](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(cti.config3_4.streams.size(), halConfig.streams.size());
+                        });
+            } else if (cti.session3_3 != nullptr) {
+                ret = cti.session3_3->configureStreams_3_3(
+                        cti.config3_2,
+                        [&cti](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(cti.config3_2.streams.size(), halConfig.streams.size());
+                        });
+            } else {
+                ret = cti.session->configureStreams(
+                        cti.config3_2, [&cti](Status s, HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(cti.config3_2.streams.size(), halConfig.streams.size());
+                        });
+            }
+            ASSERT_TRUE(ret.isOk());
+        }
+
+        for (const auto& cti : cameraTestInfos) {
+            free_camera_metadata(cti.staticMeta);
+            ret = cti.session->close();
+            ASSERT_TRUE(ret.isOk());
+        }
+    }
+}
+
 // Check for correct handling of invalid/incorrect configuration parameters.
-TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) {
+TEST_P(CameraHidlTest, configureStreamsInvalidOutputs) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<AvailableStream> outputStreams;
 
@@ -2970,11 +3456,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
+        sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         outputStreams.clear();
@@ -3146,7 +3633,7 @@
 
 // Check whether all supported ZSL output stream combinations can be
 // configured successfully.
-TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) {
+TEST_P(CameraHidlTest, configureStreamsZSLInputOutputs) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<AvailableStream> inputStreams;
     std::vector<AvailableZSLInputOutput> inputOutputMap;
@@ -3167,11 +3654,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
+        sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         Status rc = isZSLModeAvailable(staticMeta);
@@ -3312,7 +3800,7 @@
 
 // Check whether session parameters are supported. If Hal support for them
 // exist, then try to configure a preview stream using them.
-TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) {
+TEST_P(CameraHidlTest, configureStreamsWithSessionParameters) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<AvailableStream> outputPreviewStreams;
     AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -3334,8 +3822,9 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
+        sp<device::V3_6::ICameraDeviceSession> session3_6;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
             ASSERT_NE(session3_4, nullptr);
         } else {
@@ -3431,7 +3920,7 @@
 
 // Verify that all supported preview + still capture stream combinations
 // can be configured successfully.
-TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) {
+TEST_P(CameraHidlTest, configureStreamsPreviewStillOutputs) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<AvailableStream> outputBlobStreams;
     std::vector<AvailableStream> outputPreviewStreams;
@@ -3456,11 +3945,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
+        sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         // Check if camera support depth only
@@ -3554,7 +4044,7 @@
 // In case constrained mode is supported, test whether it can be
 // configured. Additionally check for common invalid inputs when
 // using this mode.
-TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) {
+TEST_P(CameraHidlTest, configureStreamsConstrainedOutputs) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -3573,11 +4063,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
+        sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         Status rc = isConstrainedModeAvailable(staticMeta);
@@ -3759,7 +4250,7 @@
 
 // Verify that all supported video + snapshot stream combinations can
 // be configured successfully.
-TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) {
+TEST_P(CameraHidlTest, configureStreamsVideoStillOutputs) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<AvailableStream> outputBlobStreams;
     std::vector<AvailableStream> outputVideoStreams;
@@ -3784,11 +4275,12 @@
         sp<device::V3_3::ICameraDeviceSession> session3_3;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
         sp<device::V3_5::ICameraDeviceSession> session3_5;
+        sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
         castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
 
         // Check if camera support depth only
@@ -3880,9 +4372,22 @@
 }
 
 // Generate and verify a camera capture request
-TEST_F(CameraHidlTest, processCaptureRequestPreview) {
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+TEST_P(CameraHidlTest, processCaptureRequestPreview) {
+    processCaptureRequestInternal(GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, RequestTemplate::PREVIEW,
+                                  false /*secureOnlyCameras*/);
+}
+
+// Generate and verify a secure camera capture request
+TEST_P(CameraHidlTest, processSecureCaptureRequest) {
+    processCaptureRequestInternal(GRALLOC1_PRODUCER_USAGE_PROTECTED, RequestTemplate::STILL_CAPTURE,
+                                  true /*secureOnlyCameras*/);
+}
+
+void CameraHidlTest::processCaptureRequestInternal(uint64_t bufferUsage,
+                                                   RequestTemplate reqTemplate,
+                                                   bool useSecureOnlyCameras) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider, useSecureOnlyCameras);
+    AvailableStream streamThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
                                         static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
     uint64_t bufferId = 1;
     uint32_t frameNumber = 1;
@@ -3898,17 +4403,17 @@
             return;
         }
 
-        V3_2::Stream previewStream;
+        V3_2::Stream testStream;
         HalStreamConfiguration halStreamConfig;
         sp<ICameraDeviceSession> session;
         sp<DeviceCb> cb;
         bool supportsPartialResults = false;
         bool useHalBufManager = false;
         uint32_t partialResultCount = 0;
-        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
-                &previewStream /*out*/, &halStreamConfig /*out*/,
-                &supportsPartialResults /*out*/,
-                &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/);
+        configureSingleStream(name, deviceVersion, mProvider, &streamThreshold, bufferUsage,
+                              reqTemplate, &session /*out*/, &testStream /*out*/,
+                              &halStreamConfig /*out*/, &supportsPartialResults /*out*/,
+                              &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/);
 
         std::shared_ptr<ResultMetadataQueue> resultQueue;
         auto resultQueueRet =
@@ -3929,7 +4434,6 @@
         InFlightRequest inflightReq = {1, false, supportsPartialResults,
                                        partialResultCount, resultQueue};
 
-        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
         Return<void> ret;
         ret = session->constructDefaultRequestSettings(reqTemplate,
                                                        [&](auto status, const auto& req) {
@@ -3948,7 +4452,7 @@
                             nullptr,
                             nullptr};
         } else {
-            allocateGraphicBuffer(previewStream.width, previewStream.height,
+            allocateGraphicBuffer(testStream.width, testStream.height,
                     android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
                         halStreamConfig.streams[0].consumerUsage),
                     halStreamConfig.streams[0].overrideFormat, &buffer_handle);
@@ -3997,7 +4501,7 @@
 
             ASSERT_FALSE(inflightReq.errorCodeValid);
             ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-            ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+            ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].streamId);
 
             request.frameNumber++;
             // Empty settings should be supported after the first call
@@ -4035,11 +4539,11 @@
 
             ASSERT_FALSE(inflightReq.errorCodeValid);
             ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-            ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+            ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].streamId);
         }
 
         if (useHalBufManager) {
-            verifyBuffersReturned(session, deviceVersion, previewStream.id, cb);
+            verifyBuffersReturned(session, deviceVersion, testStream.id, cb);
         }
 
         ret = session->close();
@@ -4048,7 +4552,7 @@
 }
 
 // Generate and verify a multi-camera capture request
-TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {
+TEST_P(CameraHidlTest, processMultiCaptureRequestPreview) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
                                         static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
@@ -4117,7 +4621,7 @@
 
         // Leave only 2 physical devices in the id set.
         auto it = physicalIds.begin();
-        string physicalDeviceId = *it; it++;
+        std::string physicalDeviceId = *it; it++;
         physicalIds.erase(++it, physicalIds.end());
         ASSERT_EQ(physicalIds.size(), 2u);
 
@@ -4157,7 +4661,7 @@
         ASSERT_TRUE(resultQueueRet.isOk());
 
         InFlightRequest inflightReq = {static_cast<ssize_t> (halStreamConfig.streams.size()), false,
-            supportsPartialResults, partialResultCount, resultQueue};
+            supportsPartialResults, partialResultCount, physicalIds, resultQueue};
 
         std::vector<hidl_handle> graphicBuffers;
         graphicBuffers.reserve(halStreamConfig.streams.size());
@@ -4236,7 +4740,7 @@
             request.v3_2.outputBuffers[0].buffer = nullptr;
             mInflightMap.clear();
             inflightReq = {static_cast<ssize_t> (physicalIds.size()), false,
-                supportsPartialResults, partialResultCount, resultQueue};
+                supportsPartialResults, partialResultCount, physicalIds, resultQueue};
             mInflightMap.add(request.v3_2.frameNumber, &inflightReq);
         }
 
@@ -4295,7 +4799,7 @@
 }
 
 // Generate and verify a burst containing alternating sensor sensitivity values
-TEST_F(CameraHidlTest, processCaptureRequestBurstISO) {
+TEST_P(CameraHidlTest, processCaptureRequestBurstISO) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
                                         static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
@@ -4453,7 +4957,7 @@
 
 // Test whether an incorrect capture request with missing settings will
 // be reported correctly.
-TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) {
+TEST_P(CameraHidlTest, processCaptureRequestInvalidSinglePreview) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<AvailableStream> outputPreviewStreams;
     AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -4526,9 +5030,210 @@
     }
 }
 
+// Verify camera offline session behavior
+TEST_P(CameraHidlTest, switchToOffline) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    AvailableStream threshold = {kMaxStillWidth, kMaxStillHeight,
+                                        static_cast<int32_t>(PixelFormat::BLOB)};
+    uint64_t bufferId = 1;
+    uint32_t frameNumber = 1;
+    ::android::hardware::hidl_vec<uint8_t> settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
+
+        camera_metadata_t* staticMetaBuffer;
+        {
+            Return<void> ret;
+            sp<ICameraDeviceSession> session;
+            openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta(
+                    staticMetaBuffer);
+
+            if (isOfflineSessionSupported(staticMetaBuffer) != Status::OK) {
+                ret = session->close();
+                ASSERT_TRUE(ret.isOk());
+                continue;
+            }
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+        }
+
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        V3_2::Stream stream;
+        V3_6::HalStreamConfiguration halStreamConfig;
+        sp<V3_6::ICameraDeviceSession> session;
+        sp<DeviceCb> cb;
+        uint32_t jpegBufferSize;
+        bool useHalBufManager;
+        configureOfflineStillStream(name, deviceVersion, mProvider, &threshold,
+                &session /*out*/, &stream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/, &partialResultCount /*out*/, &cb /*out*/,
+                &jpegBufferSize /*out*/, &useHalBufManager /*out*/);
+
+        auto ret = session->constructDefaultRequestSettings(RequestTemplate::STILL_CAPTURE,
+            [&](auto status, const auto& req) {
+                ASSERT_EQ(Status::OK, status);
+                settings = req; });
+        ASSERT_TRUE(ret.isOk());
+
+        std::shared_ptr<ResultMetadataQueue> resultQueue;
+        auto resultQueueRet =
+            session->getCaptureResultMetadataQueue(
+                [&resultQueue](const auto& descriptor) {
+                    resultQueue = std::make_shared<ResultMetadataQueue>(
+                            descriptor);
+                    if (!resultQueue->isValid() ||
+                            resultQueue->availableToWrite() <= 0) {
+                        ALOGE("%s: HAL returns empty result metadata fmq,"
+                                " not use it", __func__);
+                        resultQueue = nullptr;
+                        // Don't use the queue onwards.
+                    }
+                });
+        ASSERT_TRUE(resultQueueRet.isOk());
+
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta;
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
+        hidl_handle buffers[kBurstFrameCount];
+        StreamBuffer outputBuffers[kBurstFrameCount];
+        CaptureRequest requests[kBurstFrameCount];
+        InFlightRequest inflightReqs[kBurstFrameCount];
+        hidl_vec<uint8_t> requestSettings[kBurstFrameCount];
+        auto halStreamConfig3_2 = halStreamConfig.streams[0].v3_4.v3_3.v3_2;
+        for (uint32_t i = 0; i < kBurstFrameCount; i++) {
+            std::unique_lock<std::mutex> l(mLock);
+
+            if (useHalBufManager) {
+                outputBuffers[i] = {halStreamConfig3_2.id, /*bufferId*/ 0,
+                        buffers[i], BufferStatus::OK, nullptr, nullptr};
+            } else {
+                // jpeg buffer (w,h) = (blobLen, 1)
+                allocateGraphicBuffer(jpegBufferSize, /*height*/1,
+                        android_convertGralloc1To0Usage(halStreamConfig3_2.producerUsage,
+                            halStreamConfig3_2.consumerUsage),
+                        halStreamConfig3_2.overrideFormat, &buffers[i]);
+                outputBuffers[i] = {halStreamConfig3_2.id, bufferId + i,
+                    buffers[i], BufferStatus::OK, nullptr, nullptr};
+            }
+
+            requestMeta.clear();
+            requestMeta.append(reinterpret_cast<camera_metadata_t *> (settings.data()));
+
+            camera_metadata_t *metaBuffer = requestMeta.release();
+            requestSettings[i].setToExternal(reinterpret_cast<uint8_t *> (metaBuffer),
+                    get_camera_metadata_size(metaBuffer), true);
+
+            requests[i] = {frameNumber + i, 0 /* fmqSettingsSize */, requestSettings[i],
+                emptyInputBuffer, {outputBuffers[i]}};
+
+            inflightReqs[i] = {1, false, supportsPartialResults, partialResultCount,
+                    resultQueue};
+            mInflightMap.add(frameNumber + i, &inflightReqs[i]);
+        }
+
+        Status status = Status::INTERNAL_ERROR;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        hidl_vec<CaptureRequest> burstRequest;
+        burstRequest.setToExternal(requests, kBurstFrameCount);
+        Return<void> returnStatus = session->processCaptureRequest(burstRequest, cachesToRemove,
+                [&status, &numRequestProcessed] (auto s, uint32_t n) {
+                    status = s;
+                    numRequestProcessed = n;
+                });
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_EQ(numRequestProcessed, kBurstFrameCount);
+
+        hidl_vec<int32_t> offlineStreamIds = {halStreamConfig3_2.id};
+        V3_6::CameraOfflineSessionInfo offlineSessionInfo;
+        sp<device::V3_6::ICameraOfflineSession> offlineSession;
+        returnStatus = session->switchToOffline(offlineStreamIds,
+                [&status, &offlineSessionInfo, &offlineSession] (auto stat, auto info,
+                    auto offSession) {
+                    status = stat;
+                    offlineSessionInfo = info;
+                    offlineSession = offSession;
+                });
+        ASSERT_TRUE(returnStatus.isOk());
+
+        if (!halStreamConfig.streams[0].supportOffline) {
+            ASSERT_EQ(status, Status::ILLEGAL_ARGUMENT);
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        ASSERT_EQ(status, Status::OK);
+        // Hal might be unable to find any requests qualified for offline mode.
+        if (offlineSession == nullptr) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        ASSERT_EQ(offlineSessionInfo.offlineStreams.size(), 1u);
+        ASSERT_EQ(offlineSessionInfo.offlineStreams[0].id, halStreamConfig3_2.id);
+        ASSERT_NE(offlineSessionInfo.offlineRequests.size(), 0u);
+
+        // close device session to make sure offline session does not rely on it
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+
+        std::shared_ptr<ResultMetadataQueue> offlineResultQueue;
+        auto offlineResultQueueRet =
+            offlineSession->getCaptureResultMetadataQueue(
+                [&offlineResultQueue](const auto& descriptor) {
+                    offlineResultQueue = std::make_shared<ResultMetadataQueue>(
+                            descriptor);
+                    if (!offlineResultQueue->isValid() ||
+                            offlineResultQueue->availableToWrite() <= 0) {
+                        ALOGE("%s: offline session returns empty result metadata fmq,"
+                                " not use it", __func__);
+                        offlineResultQueue = nullptr;
+                        // Don't use the queue onwards.
+                    }
+                });
+        ASSERT_TRUE(offlineResultQueueRet.isOk());
+
+        updateInflightResultQueue(offlineResultQueue);
+
+        ret = offlineSession->setCallback(cb);
+        ASSERT_TRUE(ret.isOk());
+
+        for (size_t i = 0; i < kBurstFrameCount; i++) {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReqs[i].errorCodeValid && ((0 < inflightReqs[i].numBuffersLeft) ||
+                            (!inflightReqs[i].haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                        std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReqs[i].errorCodeValid);
+            ASSERT_NE(inflightReqs[i].resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(stream.id, inflightReqs[i].resultOutputBuffers[0].streamId);
+            ASSERT_FALSE(inflightReqs[i].collectedResult.isEmpty());
+        }
+
+
+        ret = offlineSession->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
 // Check whether an invalid capture request with missing output buffers
 // will be reported correctly.
-TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) {
+TEST_P(CameraHidlTest, processCaptureRequestInvalidBuffer) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<AvailableStream> outputBlobStreams;
     AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -4593,7 +5298,7 @@
 }
 
 // Generate, trigger and flush a preview request
-TEST_F(CameraHidlTest, flushPreviewRequest) {
+TEST_P(CameraHidlTest, flushPreviewRequest) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<AvailableStream> outputPreviewStreams;
     AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -4736,7 +5441,7 @@
 }
 
 // Verify that camera flushes correctly without any pending requests.
-TEST_F(CameraHidlTest, flushEmpty) {
+TEST_P(CameraHidlTest, flushEmpty) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     std::vector<AvailableStream> outputPreviewStreams;
     AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -4781,7 +5486,7 @@
 }
 
 // Test camera provider@2.5 notify method
-TEST_F(CameraHidlTest, providerDeviceStateNotification) {
+TEST_P(CameraHidlTest, providerDeviceStateNotification) {
 
     notifyDeviceState(provider::V2_5::DeviceState::BACK_COVERED);
     notifyDeviceState(provider::V2_5::DeviceState::NORMAL);
@@ -4789,7 +5494,7 @@
 
 // Retrieve all valid output stream resolutions from the camera
 // static characteristics.
-Status CameraHidlTest::getAvailableOutputStreams(camera_metadata_t *staticMeta,
+Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t *staticMeta,
         std::vector<AvailableStream> &outputStreams,
         const AvailableStream *threshold) {
     AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
@@ -4822,6 +5527,78 @@
     return Status::OK;
 }
 
+static Size getMinSize(Size a, Size b) {
+    if (a.width * a.height < b.width * b.height) {
+        return a;
+    }
+    return b;
+}
+
+// TODO: Add more combinations
+Status CameraHidlTest::getMandatoryConcurrentStreams(const camera_metadata_t* staticMeta,
+                                                     std::vector<AvailableStream>* outputStreams) {
+    if (nullptr == staticMeta || nullptr == outputStreams) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (isDepthOnly(staticMeta)) {
+        Size y16MaxSize(640, 480);
+        Size maxAvailableY16Size;
+        getMaxOutputSizeForFormat(staticMeta, PixelFormat::Y16, &maxAvailableY16Size);
+        Size y16ChosenSize = getMinSize(y16MaxSize, maxAvailableY16Size);
+        AvailableStream y16Stream = {.width = y16ChosenSize.width,
+                                     .height = y16ChosenSize.height,
+                                     .format = static_cast<int32_t>(PixelFormat::Y16)};
+        outputStreams->push_back(y16Stream);
+        return Status::OK;
+    }
+
+    Size yuvMaxSize(1280, 720);
+    Size jpegMaxSize(1920, 1440);
+    Size maxAvailableYuvSize;
+    Size maxAvailableJpegSize;
+    getMaxOutputSizeForFormat(staticMeta, PixelFormat::YCBCR_420_888, &maxAvailableYuvSize);
+    getMaxOutputSizeForFormat(staticMeta, PixelFormat::BLOB, &maxAvailableJpegSize);
+    Size yuvChosenSize = getMinSize(yuvMaxSize, maxAvailableYuvSize);
+    Size jpegChosenSize = getMinSize(jpegMaxSize, maxAvailableJpegSize);
+
+    AvailableStream yuvStream = {.width = yuvChosenSize.width,
+                                 .height = yuvChosenSize.height,
+                                 .format = static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
+
+    AvailableStream jpegStream = {.width = jpegChosenSize.width,
+                                  .height = jpegChosenSize.height,
+                                  .format = static_cast<int32_t>(PixelFormat::BLOB)};
+    outputStreams->push_back(yuvStream);
+    outputStreams->push_back(jpegStream);
+
+    return Status::OK;
+}
+
+Status CameraHidlTest::getMaxOutputSizeForFormat(const camera_metadata_t* staticMeta,
+                                                 PixelFormat format, Size* size) {
+    std::vector<AvailableStream> outputStreams;
+    if (size == nullptr || getAvailableOutputStreams(staticMeta, outputStreams) != Status::OK) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+    Size maxSize;
+    bool found = false;
+    for (auto& outputStream : outputStreams) {
+        if (static_cast<int32_t>(format) == outputStream.format &&
+            (outputStream.width * outputStream.height > maxSize.width * maxSize.height)) {
+            maxSize.width = outputStream.width;
+            maxSize.height = outputStream.height;
+            found = true;
+        }
+    }
+    if (!found) {
+        ALOGE("%s :chosen format %d not found", __FUNCTION__, static_cast<int32_t>(format));
+        return Status::ILLEGAL_ARGUMENT;
+    }
+    *size = maxSize;
+    return Status::OK;
+}
+
 void CameraHidlTest::fillOutputStreams(camera_metadata_ro_entry_t* entry,
         std::vector<AvailableStream>& outputStreams, const AvailableStream* threshold,
         const int32_t availableConfigOutputTag) {
@@ -4885,6 +5662,30 @@
     return ret;
 }
 
+// Check if the camera device has logical multi-camera capability.
+Status CameraHidlTest::isOfflineSessionSupported(const camera_metadata_t *staticMeta) {
+    Status ret = Status::METHOD_NOT_SUPPORTED;
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    for (size_t i = 0; i < entry.count; i++) {
+        if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING == entry.data.u8[i]) {
+            ret = Status::OK;
+            break;
+        }
+    }
+
+    return ret;
+}
+
 // Generate a list of physical camera ids backing a logical multi-camera.
 Status CameraHidlTest::getPhysicalCameraIds(const camera_metadata_t *staticMeta,
         std::unordered_set<std::string> *physicalIds) {
@@ -5059,6 +5860,39 @@
     return ret;
 }
 
+Status CameraHidlTest::getSystemCameraKind(const camera_metadata_t* staticMeta,
+                                           SystemCameraKind* systemCameraKind) {
+    Status ret = Status::OK;
+    if (nullptr == staticMeta || nullptr == systemCameraKind) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (entry.count == 1 &&
+        entry.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA) {
+        *systemCameraKind = SystemCameraKind::HIDDEN_SECURE_CAMERA;
+        return ret;
+    }
+
+    // Go through the capabilities and check if it has
+    // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA
+    for (size_t i = 0; i < entry.count; ++i) {
+        uint8_t capability = entry.data.u8[i];
+        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA) {
+            *systemCameraKind = SystemCameraKind::SYSTEM_ONLY_CAMERA;
+            return ret;
+        }
+    }
+    *systemCameraKind = SystemCameraKind::PUBLIC;
+    return ret;
+}
+
 // Check whether this is a monochrome camera using the static camera characteristics.
 Status CameraHidlTest::isMonochromeCamera(const camera_metadata_t *staticMeta) {
     Status ret = Status::METHOD_NOT_SUPPORTED;
@@ -5243,7 +6077,8 @@
     *outCb = cb;
 
     sp<device::V3_3::ICameraDeviceSession> session3_3;
-    castSession(session, deviceVersion, &session3_3, session3_4, session3_5);
+    sp<device::V3_6::ICameraDeviceSession> session3_6;
+    castSession(session, deviceVersion, &session3_3, session3_4, session3_5, &session3_6);
     ASSERT_NE(nullptr, (*session3_4).get());
 
     *useHalBufManager = false;
@@ -5315,10 +6150,10 @@
                     ASSERT_EQ(physicalIds.size(), halConfig.streams.size());
                     *halStreamConfig = halConfig;
                     if (*useHalBufManager) {
-                        hidl_vec<V3_2::Stream> streams(physicalIds.size());
+                        hidl_vec<V3_4::Stream> streams(physicalIds.size());
                         hidl_vec<V3_2::HalStream> halStreams(physicalIds.size());
                         for (size_t i = 0; i < physicalIds.size(); i++) {
-                            streams[i] = streams3_4[i].v3_2;
+                            streams[i] = streams3_4[i];
                             halStreams[i] = halConfig.streams[i].v3_3.v3_2;
                         }
                         cb->setCurrentStreamConfig(streams, halStreams);
@@ -5336,7 +6171,145 @@
     ASSERT_TRUE(ret.isOk());
 }
 
-bool CameraHidlTest::isDepthOnly(camera_metadata_t* staticMeta) {
+// Configure preview stream with possible offline session support
+void CameraHidlTest::configureOfflineStillStream(const std::string &name,
+        int32_t deviceVersion,
+        sp<ICameraProvider> provider,
+        const AvailableStream *threshold,
+        sp<device::V3_6::ICameraDeviceSession> *session/*out*/,
+        V3_2::Stream *stream /*out*/,
+        device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/,
+        bool *supportsPartialResults /*out*/,
+        uint32_t *partialResultCount /*out*/,
+        sp<DeviceCb> *outCb /*out*/,
+        uint32_t *jpegBufferSize /*out*/,
+        bool *useHalBufManager /*out*/) {
+    ASSERT_NE(nullptr, session);
+    ASSERT_NE(nullptr, halStreamConfig);
+    ASSERT_NE(nullptr, stream);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_NE(nullptr, outCb);
+    ASSERT_NE(nullptr, jpegBufferSize);
+    ASSERT_NE(nullptr, useHalBufManager);
+
+    std::vector<AvailableStream> outputStreams;
+    ::android::sp<device::V3_6::ICameraDevice> cameraDevice;
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+    Return<void> ret;
+    ret = provider->getCameraDeviceInterface_V3_x(
+        name,
+        [&cameraDevice](auto status, const auto& device) {
+            ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                  (int)status);
+            ASSERT_EQ(Status::OK, status);
+            ASSERT_NE(device, nullptr);
+            auto castResult = device::V3_6::ICameraDevice::castFrom(device);
+            ASSERT_TRUE(castResult.isOk());
+            cameraDevice = castResult;
+        });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_t *staticMeta;
+    ret = cameraDevice->getCameraCharacteristics([&] (Status s,
+            CameraMetadata metadata) {
+        ASSERT_EQ(Status::OK, s);
+        staticMeta = clone_camera_metadata(
+                reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+        ASSERT_NE(nullptr, staticMeta);
+    });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_ro_entry entry;
+    auto status = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+    if ((0 == status) && (entry.count > 0)) {
+        *partialResultCount = entry.data.i32[0];
+        *supportsPartialResults = (*partialResultCount > 1);
+    }
+
+    *useHalBufManager = false;
+    status = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+    if ((0 == status) && (entry.count == 1)) {
+        *useHalBufManager = (entry.data.u8[0] ==
+            ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    }
+
+    auto st = getJpegBufferSize(staticMeta, jpegBufferSize);
+    ASSERT_EQ(st, Status::OK);
+
+    sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta);
+    ret = cameraDevice->open(cb, [&session](auto status, const auto& newSession) {
+            ALOGI("device::open returns status:%d", (int)status);
+            ASSERT_EQ(Status::OK, status);
+            ASSERT_NE(newSession, nullptr);
+            auto castResult = device::V3_6::ICameraDeviceSession::castFrom(newSession);
+            ASSERT_TRUE(castResult.isOk());
+            *session = castResult;
+        });
+    ASSERT_TRUE(ret.isOk());
+    *outCb = cb;
+
+    outputStreams.clear();
+    auto rc = getAvailableOutputStreams(staticMeta,
+            outputStreams, threshold);
+    size_t idx = 0;
+    int currLargest = outputStreams[0].width * outputStreams[0].height;
+    for (size_t i = 0; i < outputStreams.size(); i++) {
+        int area = outputStreams[i].width * outputStreams[i].height;
+        if (area > currLargest) {
+            idx = i;
+            currLargest = area;
+        }
+    }
+    free_camera_metadata(staticMeta);
+    ASSERT_EQ(Status::OK, rc);
+    ASSERT_FALSE(outputStreams.empty());
+
+    V3_2::DataspaceFlags dataspaceFlag = 0;
+    switch (static_cast<PixelFormat>(outputStreams[idx].format)) {
+        case PixelFormat::BLOB:
+            dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::V0_JFIF);
+            break;
+        case PixelFormat::Y16:
+            dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::DEPTH);
+            break;
+        default:
+            dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::UNKNOWN);
+    }
+
+    ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(/*size*/1);
+    V3_4::Stream stream3_4 = {{ 0 /*streamId*/, StreamType::OUTPUT,
+        static_cast<uint32_t> (outputStreams[idx].width),
+        static_cast<uint32_t> (outputStreams[idx].height),
+        static_cast<PixelFormat> (outputStreams[idx].format),
+        GRALLOC1_CONSUMER_USAGE_CPU_READ, dataspaceFlag, StreamRotation::ROTATION_0},
+        nullptr /*physicalId*/, /*bufferSize*/ *jpegBufferSize};
+    streams3_4[0] = stream3_4;
+
+    ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+    ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
+    config3_4 = {streams3_4, StreamConfigurationMode::NORMAL_MODE, {}};
+
+    config3_5.v3_4 = config3_4;
+    config3_5.streamConfigCounter = 0;
+    ret = (*session)->configureStreams_3_6(config3_5,
+            [&] (Status s, device::V3_6::HalStreamConfiguration halConfig) {
+                ASSERT_EQ(Status::OK, s);
+                *halStreamConfig = halConfig;
+
+                if (*useHalBufManager) {
+                    hidl_vec<V3_2::HalStream> halStreams3_2(1);
+                    halStreams3_2[0] = halConfig.streams[0].v3_4.v3_3.v3_2;
+                    cb->setCurrentStreamConfig(streams3_4, halStreams3_2);
+                }
+            });
+    *stream = streams3_4[0].v3_2;
+    ASSERT_TRUE(ret.isOk());
+}
+
+bool CameraHidlTest::isDepthOnly(const camera_metadata_t* staticMeta) {
     camera_metadata_ro_entry scalarEntry;
     camera_metadata_ro_entry depthEntry;
 
@@ -5367,6 +6340,14 @@
     return false;
 }
 
+void CameraHidlTest::updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue) {
+    std::unique_lock<std::mutex> l(mLock);
+    for (size_t i = 0; i < mInflightMap.size(); i++) {
+        auto& req = mInflightMap.editValueAt(i);
+        req->resultQueue = resultQueue;
+    }
+}
+
 // Open a device session and configure a preview stream.
 void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t deviceVersion,
         sp<ICameraProvider> provider,
@@ -5379,6 +6360,19 @@
         bool *useHalBufManager /*out*/,
         sp<DeviceCb> *outCb /*out*/,
         uint32_t streamConfigCounter) {
+    configureSingleStream(name, deviceVersion, provider, previewThreshold,
+                          GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, RequestTemplate::PREVIEW, session,
+                          previewStream, halStreamConfig, supportsPartialResults,
+                          partialResultCount, useHalBufManager, outCb, streamConfigCounter);
+}
+// Open a device session and configure a preview stream.
+void CameraHidlTest::configureSingleStream(
+        const std::string& name, int32_t deviceVersion, sp<ICameraProvider> provider,
+        const AvailableStream* previewThreshold, uint64_t bufferUsage, RequestTemplate reqTemplate,
+        sp<ICameraDeviceSession>* session /*out*/, V3_2::Stream* previewStream /*out*/,
+        HalStreamConfiguration* halStreamConfig /*out*/, bool* supportsPartialResults /*out*/,
+        uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
+        sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter) {
     ASSERT_NE(nullptr, session);
     ASSERT_NE(nullptr, previewStream);
     ASSERT_NE(nullptr, halStreamConfig);
@@ -5435,7 +6429,8 @@
     sp<device::V3_3::ICameraDeviceSession> session3_3;
     sp<device::V3_4::ICameraDeviceSession> session3_4;
     sp<device::V3_5::ICameraDeviceSession> session3_5;
-    castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5);
+    sp<device::V3_6::ICameraDeviceSession> session3_6;
+    castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
 
     *useHalBufManager = false;
     status = find_camera_metadata_ro_entry(staticMeta,
@@ -5466,11 +6461,14 @@
             dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::UNKNOWN);
     }
 
-    V3_2::Stream stream3_2 = {0, StreamType::OUTPUT,
-            static_cast<uint32_t> (outputPreviewStreams[0].width),
-            static_cast<uint32_t> (outputPreviewStreams[0].height),
-            static_cast<PixelFormat> (outputPreviewStreams[0].format),
-            GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, dataspaceFlag, StreamRotation::ROTATION_0};
+    V3_2::Stream stream3_2 = {0,
+                              StreamType::OUTPUT,
+                              static_cast<uint32_t>(outputPreviewStreams[0].width),
+                              static_cast<uint32_t>(outputPreviewStreams[0].height),
+                              static_cast<PixelFormat>(outputPreviewStreams[0].format),
+                              bufferUsage,
+                              dataspaceFlag,
+                              StreamRotation::ROTATION_0};
     ::android::hardware::hidl_vec<V3_2::Stream> streams3_2 = {stream3_2};
     ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
     ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
@@ -5478,7 +6476,6 @@
     createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
                               &config3_2, &config3_4, &config3_5, jpegBufferSize);
     if (session3_5 != nullptr) {
-        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
         ret = session3_5->constructDefaultRequestSettings(reqTemplate,
                                                        [&config3_5](auto status, const auto& req) {
                                                            ASSERT_EQ(Status::OK, status);
@@ -5493,15 +6490,14 @@
                     halStreamConfig->streams.resize(1);
                     halStreamConfig->streams[0] = halConfig.streams[0].v3_3.v3_2;
                     if (*useHalBufManager) {
-                        hidl_vec<V3_2::Stream> streams(1);
+                        hidl_vec<V3_4::Stream> streams(1);
                         hidl_vec<V3_2::HalStream> halStreams(1);
-                        streams[0] = stream3_2;
+                        streams[0] = config3_4.streams[0];
                         halStreams[0] = halConfig.streams[0].v3_3.v3_2;
                         cb->setCurrentStreamConfig(streams, halStreams);
                     }
                 });
     } else if (session3_4 != nullptr) {
-        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
         ret = session3_4->constructDefaultRequestSettings(reqTemplate,
                                                        [&config3_4](auto status, const auto& req) {
                                                            ASSERT_EQ(Status::OK, status);
@@ -5550,12 +6546,19 @@
 }
 
 //Cast camera provider to corresponding version if available
-void CameraHidlTest::castProvider(const sp<ICameraProvider> &provider,
-        sp<provider::V2_5::ICameraProvider> *provider2_5 /*out*/) {
+void CameraHidlTest::castProvider(const sp<ICameraProvider>& provider,
+                                  sp<provider::V2_5::ICameraProvider>* provider2_5 /*out*/,
+                                  sp<provider::V2_6::ICameraProvider>* provider2_6 /*out*/) {
     ASSERT_NE(nullptr, provider2_5);
-    auto castResult = provider::V2_5::ICameraProvider::castFrom(provider);
-    if (castResult.isOk()) {
-        *provider2_5 = castResult;
+    auto castResult2_5 = provider::V2_5::ICameraProvider::castFrom(provider);
+    if (castResult2_5.isOk()) {
+        *provider2_5 = castResult2_5;
+    }
+
+    ASSERT_NE(nullptr, provider2_6);
+    auto castResult2_6 = provider::V2_6::ICameraProvider::castFrom(provider);
+    if (castResult2_6.isOk()) {
+        *provider2_6 = castResult2_6;
     }
 }
 
@@ -5563,12 +6566,20 @@
 void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
         sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
         sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
-        sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/) {
+        sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
+        sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/) {
     ASSERT_NE(nullptr, session3_3);
     ASSERT_NE(nullptr, session3_4);
     ASSERT_NE(nullptr, session3_5);
+    ASSERT_NE(nullptr, session3_6);
 
     switch (deviceVersion) {
+        case CAMERA_DEVICE_API_VERSION_3_6: {
+            auto castResult = device::V3_6::ICameraDeviceSession::castFrom(session);
+            ASSERT_TRUE(castResult.isOk());
+            *session3_6 = castResult;
+        }
+        [[fallthrough]];
         case CAMERA_DEVICE_API_VERSION_3_5: {
             auto castResult = device::V3_5::ICameraDeviceSession::castFrom(session);
             ASSERT_TRUE(castResult.isOk());
@@ -5616,13 +6627,20 @@
         const hidl_vec<hidl_string>& deviceNames) {
     const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
     ASSERT_NE(nullptr, metadata);
-
-    Status rc = isLogicalMultiCamera(metadata);
+    SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+    Status rc = getSystemCameraKind(metadata, &systemCameraKind);
+    ASSERT_EQ(rc, Status::OK);
+    rc = isLogicalMultiCamera(metadata);
     ASSERT_TRUE(Status::OK == rc || Status::METHOD_NOT_SUPPORTED == rc);
     if (Status::METHOD_NOT_SUPPORTED == rc) {
         return;
     }
 
+    camera_metadata_ro_entry entry;
+    int retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+    bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+
     std::string version, cameraId;
     ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId));
     std::unordered_set<std::string> physicalIds;
@@ -5630,15 +6648,45 @@
     for (auto physicalId : physicalIds) {
         ASSERT_NE(physicalId, cameraId);
         bool isPublicId = false;
+        std::string fullPublicId;
+        SystemCameraKind physSystemCameraKind = SystemCameraKind::PUBLIC;
         for (auto& deviceName : deviceNames) {
             std::string publicVersion, publicId;
             ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
             if (physicalId == publicId) {
                 isPublicId = true;
+                fullPublicId = deviceName;
                 break;
             }
         }
         if (isPublicId) {
+            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> subDevice;
+            Return<void> ret;
+            ret = mProvider->getCameraDeviceInterface_V3_x(
+                fullPublicId, [&](auto status, const auto& device) {
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(device, nullptr);
+                    subDevice = device;
+                });
+            ASSERT_TRUE(ret.isOk());
+
+            ret = subDevice->getCameraCharacteristics(
+                    [&](auto status, const auto& chars) {
+                ASSERT_EQ(Status::OK, status);
+                const camera_metadata_t* staticMeta =
+                        reinterpret_cast<const camera_metadata_t*>(chars.data());
+                rc = getSystemCameraKind(staticMeta, &physSystemCameraKind);
+                ASSERT_EQ(rc, Status::OK);
+                // Make sure that the system camera kind of a non-hidden
+                // physical cameras is the same as the logical camera associated
+                // with it.
+                ASSERT_EQ(physSystemCameraKind, systemCameraKind);
+                retcode = find_camera_metadata_ro_entry(staticMeta,
+                                                        ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+                bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+                ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
+            });
+            ASSERT_TRUE(ret.isOk());
             continue;
         }
 
@@ -5650,11 +6698,16 @@
         ASSERT_NE(device3_5, nullptr);
 
         // Check camera characteristics for hidden camera id
-        Return<void> ret = device3_5->getPhysicalCameraCharacteristics(physicalId,
-                [&](auto status, const auto& chars) {
-            verifyCameraCharacteristics(status, chars);
-            verifyMonochromeCharacteristics(chars, deviceVersion);
-        });
+        Return<void> ret = device3_5->getPhysicalCameraCharacteristics(
+                physicalId, [&](auto status, const auto& chars) {
+                    verifyCameraCharacteristics(status, chars);
+                    verifyMonochromeCharacteristics(chars, deviceVersion);
+                    retcode =
+                            find_camera_metadata_ro_entry((const camera_metadata_t*)chars.data(),
+                                                          ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+                    bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+                    ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
+                });
         ASSERT_TRUE(ret.isOk());
 
         // Check calling getCameraDeviceInterface_V3_x() on hidden camera id returns
@@ -5673,8 +6726,7 @@
     // Make sure ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID is available in
     // result keys.
     if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) {
-        camera_metadata_ro_entry entry;
-        int retcode = find_camera_metadata_ro_entry(metadata,
+        retcode = find_camera_metadata_ro_entry(metadata,
                 ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
         if ((0 == retcode) && (entry.count > 0)) {
                 ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count,
@@ -5772,6 +6824,245 @@
             ADD_FAILURE() << "Get Heic maxJpegAppSegmentsCount failed!";
         }
     }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_LENS_POSE_REFERENCE, &entry);
+    if (0 == retcode && entry.count > 0) {
+        uint8_t poseReference = entry.data.u8[0];
+        ASSERT_TRUE(poseReference <= ANDROID_LENS_POSE_REFERENCE_UNDEFINED &&
+                poseReference >= ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA);
+    }
+
+    verifyExtendedSceneModeCharacteristics(metadata);
+    verifyZoomCharacteristics(metadata);
+}
+
+void CameraHidlTest::verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata) {
+    camera_metadata_ro_entry entry;
+    int retcode = 0;
+
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_AVAILABLE_MODES, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        for (auto i = 0; i < entry.count; i++) {
+            ASSERT_TRUE(entry.data.u8[i] >= ANDROID_CONTROL_MODE_OFF &&
+                        entry.data.u8[i] <= ANDROID_CONTROL_MODE_USE_EXTENDED_SCENE_MODE);
+        }
+    } else {
+        ADD_FAILURE() << "Get camera controlAvailableModes failed!";
+    }
+
+    // Check key availability in capabilities, request and result.
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+    bool hasExtendedSceneModeRequestKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasExtendedSceneModeRequestKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_EXTENDED_SCENE_MODE) != entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+    bool hasExtendedSceneModeResultKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasExtendedSceneModeResultKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_EXTENDED_SCENE_MODE) != entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableResultKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+    bool hasExtendedSceneModeMaxSizesKey = false;
+    bool hasExtendedSceneModeZoomRatioRangesKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasExtendedSceneModeMaxSizesKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES) !=
+                entry.data.i32 + entry.count;
+        hasExtendedSceneModeZoomRatioRangesKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES) !=
+                entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
+    }
+
+    camera_metadata_ro_entry maxSizesEntry;
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES, &maxSizesEntry);
+    bool hasExtendedSceneModeMaxSizes = (0 == retcode && maxSizesEntry.count > 0);
+
+    camera_metadata_ro_entry zoomRatioRangesEntry;
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES,
+            &zoomRatioRangesEntry);
+    bool hasExtendedSceneModeZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0);
+
+    // Extended scene mode keys must all be available, or all be unavailable.
+    bool noExtendedSceneMode =
+            !hasExtendedSceneModeRequestKey && !hasExtendedSceneModeResultKey &&
+            !hasExtendedSceneModeMaxSizesKey && !hasExtendedSceneModeZoomRatioRangesKey &&
+            !hasExtendedSceneModeMaxSizes && !hasExtendedSceneModeZoomRatioRanges;
+    if (noExtendedSceneMode) {
+        return;
+    }
+    bool hasExtendedSceneMode = hasExtendedSceneModeRequestKey && hasExtendedSceneModeResultKey &&
+                                hasExtendedSceneModeMaxSizesKey &&
+                                hasExtendedSceneModeZoomRatioRangesKey &&
+                                hasExtendedSceneModeMaxSizes && hasExtendedSceneModeZoomRatioRanges;
+    ASSERT_TRUE(hasExtendedSceneMode);
+
+    // Must have DISABLED, and must have one of BOKEH_STILL_CAPTURE, BOKEH_CONTINUOUS, or a VENDOR
+    // mode.
+    ASSERT_TRUE((maxSizesEntry.count == 6 && zoomRatioRangesEntry.count == 2) ||
+            (maxSizesEntry.count == 9 && zoomRatioRangesEntry.count == 4));
+    bool hasDisabledMode = false;
+    bool hasBokehStillCaptureMode = false;
+    bool hasBokehContinuousMode = false;
+    bool hasVendorMode = false;
+    std::vector<AvailableStream> outputStreams;
+    ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams));
+    for (int i = 0, j = 0; i < maxSizesEntry.count && j < zoomRatioRangesEntry.count; i += 3) {
+        int32_t mode = maxSizesEntry.data.i32[i];
+        int32_t maxWidth = maxSizesEntry.data.i32[i+1];
+        int32_t maxHeight = maxSizesEntry.data.i32[i+2];
+        switch (mode) {
+            case ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED:
+                hasDisabledMode = true;
+                ASSERT_TRUE(maxWidth == 0 && maxHeight == 0);
+                break;
+            case ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE:
+                hasBokehStillCaptureMode = true;
+                j += 2;
+                break;
+            case ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS:
+                hasBokehContinuousMode = true;
+                j += 2;
+                break;
+            default:
+                if (mode < ANDROID_CONTROL_EXTENDED_SCENE_MODE_VENDOR_START) {
+                    ADD_FAILURE() << "Invalid extended scene mode advertised: " << mode;
+                } else {
+                    hasVendorMode = true;
+                    j += 2;
+                }
+                break;
+        }
+
+        if (mode != ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED) {
+            // Make sure size is supported.
+            bool sizeSupported = false;
+            for (const auto& stream : outputStreams) {
+                if ((stream.format == static_cast<int32_t>(PixelFormat::YCBCR_420_888) ||
+                        stream.format == static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED))
+                        && stream.width == maxWidth && stream.height == maxHeight) {
+                    sizeSupported = true;
+                    break;
+                }
+            }
+            ASSERT_TRUE(sizeSupported);
+
+            // Make sure zoom range is valid
+            float minZoomRatio = zoomRatioRangesEntry.data.f[0];
+            float maxZoomRatio = zoomRatioRangesEntry.data.f[1];
+            ASSERT_GT(minZoomRatio, 0.0f);
+            ASSERT_LE(minZoomRatio, maxZoomRatio);
+        }
+    }
+    ASSERT_TRUE(hasDisabledMode);
+    ASSERT_TRUE(hasBokehStillCaptureMode || hasBokehContinuousMode || hasVendorMode);
+}
+
+void CameraHidlTest::verifyZoomCharacteristics(const camera_metadata_t* metadata) {
+    camera_metadata_ro_entry entry;
+    int retcode = 0;
+
+    // Check key availability in capabilities, request and result.
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &entry);
+    float maxDigitalZoom = 1.0;
+    if ((0 == retcode) && (entry.count == 1)) {
+        maxDigitalZoom = entry.data.f[0];
+    } else {
+        ADD_FAILURE() << "Get camera scalerAvailableMaxDigitalZoom failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+    bool hasZoomRequestKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasZoomRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32+entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+    bool hasZoomResultKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasZoomResultKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32+entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableResultKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+    bool hasZoomCharacteristicsKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasZoomCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_ZOOM_RATIO_RANGE) != entry.data.i32+entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+    bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+
+    // Zoom keys must all be available, or all be unavailable.
+    bool noZoomRatio = !hasZoomRequestKey && !hasZoomResultKey && !hasZoomCharacteristicsKey &&
+            !hasZoomRatioRange;
+    if (noZoomRatio) {
+        return;
+    }
+    bool hasZoomRatio = hasZoomRequestKey && hasZoomResultKey && hasZoomCharacteristicsKey &&
+            hasZoomRatioRange;
+    ASSERT_TRUE(hasZoomRatio);
+
+    float minZoomRatio = entry.data.f[0];
+    float maxZoomRatio = entry.data.f[1];
+    constexpr float FLOATING_POINT_THRESHOLD = 0.00001f;
+    if (maxDigitalZoom > maxZoomRatio + FLOATING_POINT_THRESHOLD) {
+        ADD_FAILURE() << "Maximum digital zoom " << maxDigitalZoom
+                      << " is larger than maximum zoom ratio " << maxZoomRatio << " + threshold "
+                      << FLOATING_POINT_THRESHOLD << "!";
+    }
+    if (minZoomRatio > maxZoomRatio) {
+        ADD_FAILURE() << "Maximum zoom ratio is less than minimum zoom ratio!";
+    }
+    if (minZoomRatio > 1.0f) {
+        ADD_FAILURE() << "Minimum zoom ratio is more than 1.0!";
+    }
+    if (maxZoomRatio < 1.0f) {
+        ADD_FAILURE() << "Maximum zoom ratio is less than 1.0!";
+    }
+
+    // Make sure CROPPING_TYPE is CENTER_ONLY
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_SCALER_CROPPING_TYPE, &entry);
+    if ((0 == retcode) && (entry.count == 1)) {
+        int8_t croppingType = entry.data.u8[0];
+        ASSERT_EQ(croppingType, ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY);
+    } else {
+        ADD_FAILURE() << "Get camera scalerCroppingType failed!";
+    }
 }
 
 void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars,
@@ -5925,7 +7216,8 @@
     sp<device::V3_3::ICameraDeviceSession> session3_3;
     sp<device::V3_4::ICameraDeviceSession> session3_4;
     sp<device::V3_5::ICameraDeviceSession> session3_5;
-    castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+    sp<device::V3_6::ICameraDeviceSession> session3_6;
+    castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
     ASSERT_NE(nullptr, session3_5.get());
 
     hidl_vec<int32_t> streamIds(1);
@@ -6144,68 +7436,15 @@
         PixelFormat format, hidl_handle *buffer_handle /*out*/) {
     ASSERT_NE(buffer_handle, nullptr);
 
-    sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator =
-        android::hardware::graphics::allocator::V2_0::IAllocator::getService();
-    sp<android::hardware::graphics::allocator::V3_0::IAllocator> allocatorV3 =
-        android::hardware::graphics::allocator::V3_0::IAllocator::getService();
+    buffer_handle_t buffer;
+    uint32_t stride;
 
-    sp<android::hardware::graphics::mapper::V3_0::IMapper> mapperV3 =
-        android::hardware::graphics::mapper::V3_0::IMapper::getService();
-    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
-        android::hardware::graphics::mapper::V2_0::IMapper::getService();
-    ::android::hardware::hidl_vec<uint32_t> descriptor;
-    if (mapperV3 != nullptr && allocatorV3 != nullptr) {
-        android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo descriptorInfo {};
-        descriptorInfo.width = width;
-        descriptorInfo.height = height;
-        descriptorInfo.layerCount = 1;
-        descriptorInfo.format =
-                static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
-        descriptorInfo.usage = usage;
+    android::status_t err = android::GraphicBufferAllocator::get().allocateRawHandle(
+            width, height, static_cast<int32_t>(format), 1u /*layerCount*/, usage, &buffer, &stride,
+            "VtsHalCameraProviderV2_4");
+    ASSERT_EQ(err, android::NO_ERROR);
 
-        auto ret = mapperV3->createDescriptor(
-            descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V3_0::Error err,
-                                ::android::hardware::hidl_vec<uint32_t> desc) {
-                ASSERT_EQ(err, android::hardware::graphics::mapper::V3_0::Error::NONE);
-                descriptor = desc;
-            });
-        ASSERT_TRUE(ret.isOk());
-
-        ret = allocatorV3->allocate(descriptor, 1u,
-            [&](android::hardware::graphics::mapper::V3_0::Error err, uint32_t /*stride*/,
-                const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& buffers) {
-                ASSERT_EQ(android::hardware::graphics::mapper::V3_0::Error::NONE, err);
-                ASSERT_EQ(buffers.size(), 1u);
-                *buffer_handle = buffers[0];
-            });
-        ASSERT_TRUE(ret.isOk());
-    } else {
-        ASSERT_NE(mapper.get(), nullptr);
-        ASSERT_NE(allocator.get(), nullptr);
-        android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo {};
-        descriptorInfo.width = width;
-        descriptorInfo.height = height;
-        descriptorInfo.layerCount = 1;
-        descriptorInfo.format = format;
-        descriptorInfo.usage = usage;
-
-        auto ret = mapper->createDescriptor(
-            descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V2_0::Error err,
-                                ::android::hardware::hidl_vec<uint32_t> desc) {
-                ASSERT_EQ(err, android::hardware::graphics::mapper::V2_0::Error::NONE);
-                descriptor = desc;
-            });
-        ASSERT_TRUE(ret.isOk());
-
-        ret = allocator->allocate(descriptor, 1u,
-            [&](android::hardware::graphics::mapper::V2_0::Error err, uint32_t /*stride*/,
-                const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>& buffers) {
-                ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE, err);
-                ASSERT_EQ(buffers.size(), 1u);
-                *buffer_handle = buffers[0];
-            });
-        ASSERT_TRUE(ret.isOk());
-    }
+    buffer_handle->setTo(const_cast<native_handle_t*>(buffer), true /*shouldOwn*/);
 }
 
 void CameraHidlTest::verifyRecommendedConfigs(const CameraMetadata& chars) {
@@ -6325,11 +7564,27 @@
     }
 }
 
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  CameraHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
+void CameraHidlTest::verifyRequestTemplate(const camera_metadata_t* metadata,
+        RequestTemplate requestTemplate) {
+    ASSERT_NE(nullptr, metadata);
+    size_t entryCount =
+            get_camera_metadata_entry_count(metadata);
+    ALOGI("template %u metadata entry count is %zu", (int32_t)requestTemplate, entryCount);
+    // TODO: we can do better than 0 here. Need to check how many required
+    // request keys we've defined for each template
+    ASSERT_GT(entryCount, 0u);
+
+    // Check zoomRatio
+    camera_metadata_ro_entry zoomRatioEntry;
+    int foundZoomRatio = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_ZOOM_RATIO, &zoomRatioEntry);
+    if (foundZoomRatio == 0) {
+        ASSERT_EQ(zoomRatioEntry.count, 1);
+        ASSERT_EQ(zoomRatioEntry.data.f[0], 1.0f);
+    }
 }
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, CameraHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraProvider::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp
index 4563362..9ddf651 100644
--- a/camera/provider/2.5/default/Android.bp
+++ b/camera/provider/2.5/default/Android.bp
@@ -52,6 +52,8 @@
         "android.hardware.camera.provider@2.4-external",
         "android.hardware.camera.provider@2.5",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "camera.device@3.3-impl",
@@ -72,7 +74,8 @@
     ],
     header_libs: [
         "camera.device@3.4-external-impl_headers",
-        "camera.device@3.5-external-impl_headers"
+        "camera.device@3.5-external-impl_headers",
+        "camera.device@3.6-external-impl_headers"
     ],
     export_include_dirs: ["."],
 }
@@ -165,7 +168,10 @@
         "android.hardware.camera.provider@2.5",
         "android.hardware.camera.provider@2.5-external",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "libbinder",
+        "libcamera_metadata",
         "libhidlbase",
         "liblog",
         "libtinyxml2",
@@ -179,5 +185,6 @@
         "camera.device@3.4-impl_headers",
         "camera.device@3.5-external-impl_headers",
         "camera.device@3.5-impl_headers",
+        "camera.device@3.6-external-impl_headers",
     ],
 }
diff --git a/camera/provider/2.6/Android.bp b/camera/provider/2.6/Android.bp
new file mode 100644
index 0000000..6934c17
--- /dev/null
+++ b/camera/provider/2.6/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.provider@2.6",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "ICameraProvider.hal",
+        "ICameraProviderCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.common@1.0",
+        "android.hardware.camera.device@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.camera.provider@2.5",
+        "android.hardware.graphics.common@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal
new file mode 100644
index 0000000..d720b26
--- /dev/null
+++ b/camera/provider/2.6/ICameraProvider.hal
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.provider@2.6;
+
+import @2.5::ICameraProvider;
+import android.hardware.camera.common@1.0::Status;
+import android.hardware.camera.device@3.4::StreamConfiguration;
+
+/**
+ * Camera provider HAL
+ *
+ * @2.6::adds support for the getConcurrentStreamingCameraIds() and
+ * isConcurrentStreamCombinationSupported()
+ * @2.6::ICameraProviderCallback to receive physical camera availability
+ * callbacks for logical multi-cameras.
+ */
+interface ICameraProvider extends @2.5::ICameraProvider {
+    /**
+     * getConcurrentStreamingCameraIds
+     *
+     * Get a vector of combinations of camera device ids that are able to
+     * configure streams concurrently. Each camera device advertised in a
+     * combination MUST at the very least support the following streams while
+     * streaming concurrently with the other camera ids in the combination.
+     *
+     *       Target 1                  Target 2
+     * -----------------------------------------------------
+     * | 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)
+     *
+     * If a device has MONOCHROME capability (device's capabilities include
+     * ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) and therefore supports Y8
+     * outputs, stream combinations mentioned above, where YUV is substituted by
+     * Y8 must be also supported.
+     *
+     * Devices whose capabilities do not include
+     * ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE, must support
+     * at least a single Y16 stream, Dataspace::DEPTH with sVGA resolution,
+     * during concurrent operation.
+     * Where sVGA -  min (max output resolution for the given format, 640 X 480)
+     *
+     * 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.
+     *
+     * For each combination (and their subsets) of camera device ids returned by
+     * getConcurrentStreamingCameraIds(): If only the mandatory combinations can
+     * be supported concurrently by each device, then the resource costs must
+     * sum up to > 100 for the concurrent set, to ensure arbitration between
+     * camera applications work as expected. Only if resources are sufficient
+     * to run a set of cameras at full capability (maximally
+     * resource-consuming framerate and stream size settings available in the
+     * configuration settings exposed through camera metadata), should the sum
+     * of resource costs for the combination be <= 100.
+     *
+     * For guaranteed concurrent camera operation, the camera framework must call
+     * ICameraDevice.open() on all devices (intended for concurrent operation), before configuring
+     * any streams on them. This gives the camera HAL process an opportunity to potentially
+     * distribute hardware resources better before stream configuration.
+     *
+     * Due to potential hardware constraints around internal switching of physical camera devices,
+     * a device's complete ZOOM_RATIO_RANGE(if supported), may not apply during concurrent
+     * operation. If ZOOM_RATIO is supported, camera HALs must ensure ZOOM_RATIO_RANGE of
+     * [1.0, ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM] is supported by that device, during
+     * concurrent operation.
+     *
+     * @return status Status code for the operation
+     * @return cameraIds a list of camera id combinations that support
+     *         concurrent stream configurations with the minimum guarantees
+     *         specified.
+     */
+    getConcurrentStreamingCameraIds() generates (Status status, vec<vec<string>> cameraIds);
+
+    /**
+     * isConcurrentStreamCombinationSupported:
+     *
+     * Check for device support of specific camera stream combinations while
+     * streaming concurrently with other devices.
+     *
+     * The per device streamList must contain at least one output-capable stream, and may
+     * not contain more than one input-capable stream.
+     * In contrast to regular stream configuration the framework does not create
+     * or initialize any actual streams. This means that Hal must not use or
+     * consider the stream "id" value.
+     *
+     * ------------------------------------------------------------------------
+     *
+     * Preconditions:
+     *
+     * The framework can call this method at any time before, during and
+     * after active session configuration per device. This means that calls must not
+     * impact the performance of pending camera requests in any way. In
+     * particular there must not be any glitches or delays during normal
+     * camera streaming.
+     *
+     * The framework must not call this method with any combination of camera
+     * ids that is not a subset of the camera ids advertised by getConcurrentStreamingCameraIds of
+     * the same provider.
+     *
+     * Performance requirements:
+     * This call is expected to be significantly faster than stream
+     * configuration. In general HW and SW camera settings must not be
+     * changed and there must not be a user-visible impact on camera performance.
+     *
+     * @param configs a vector of camera ids and their corresponding stream
+     *                configurations that need to be queried for support.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *          On successful stream combination query.
+     *     METHOD_NOT_SUPPORTED:
+     *          The camera provider does not support stream combination query.
+     *     INTERNAL_ERROR:
+     *          The stream combination query cannot complete due to internal
+     *          error.
+     * @return true in case the stream combination is supported, false otherwise.
+     *
+     *
+     */
+    isConcurrentStreamCombinationSupported(vec<CameraIdAndStreamCombination> configs)
+        generates (Status status, bool queryStatus);
+};
diff --git a/camera/provider/2.6/ICameraProviderCallback.hal b/camera/provider/2.6/ICameraProviderCallback.hal
new file mode 100644
index 0000000..42c1092
--- /dev/null
+++ b/camera/provider/2.6/ICameraProviderCallback.hal
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.provider@2.6;
+
+import android.hardware.camera.common@1.0::types;
+import android.hardware.camera.provider@2.4::ICameraProviderCallback;
+
+/**
+ * Callback functions for a camera provider HAL to use to inform the camera
+ * service of changes to the camera subsystem.
+ *
+ * Version 2.6 adds support for physical camera device status callback for
+ * multi-camera.
+ */
+interface ICameraProviderCallback extends @2.4::ICameraProviderCallback {
+
+    /**
+     * cameraPhysicalDeviceStatusChange:
+     *
+     * Callback to the camera service to indicate that the state of a physical
+     * camera device of a logical multi-camera has changed.
+     *
+     * On camera service startup, when ICameraProvider::setCallback is invoked,
+     * the camera service must assume that all physical devices backing internal
+     * multi-camera devices are in the CAMERA_DEVICE_STATUS_PRESENT state.
+     *
+     * The provider must call this method to inform the camera service of any
+     * initially NOT_PRESENT physical devices, as soon as the callbacks are available
+     * through setCallback.
+     *
+     * @param cameraDeviceName The name of the logical multi-camera whose
+     *     physical camera has a new status.
+     * @param physicalCameraDeviceName The name of the physical camera device
+     *     that has a new status.
+     * @param newStatus The new status that device is in.
+     *
+     */
+    physicalCameraDeviceStatusChange(string cameraDeviceName,
+            string physicalCameraDeviceName, CameraDeviceStatus newStatus);
+};
diff --git a/camera/provider/2.6/types.hal b/camera/provider/2.6/types.hal
new file mode 100644
index 0000000..24c62aa
--- /dev/null
+++ b/camera/provider/2.6/types.hal
@@ -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.
+ */
+
+package android.hardware.camera.provider@2.6;
+
+import android.hardware.camera.device@3.4::StreamConfiguration;
+
+/**
+ * CameraIdAndStreamCombination:
+ * Pairs the cameraId and the StreamConfiguration to be
+ * tested with other concurrent camera id and StreamConfigurations
+ */
+struct CameraIdAndStreamCombination {
+    string cameraId;
+
+    @3.4::StreamConfiguration streamConfiguration;
+};
diff --git a/cas/1.0/vts/functional/Android.bp b/cas/1.0/vts/functional/Android.bp
index 622baa5..ab39c0e 100644
--- a/cas/1.0/vts/functional/Android.bp
+++ b/cas/1.0/vts/functional/Android.bp
@@ -29,6 +29,6 @@
     shared_libs: [
         "libbinder",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
index 14b8bbd..0f16de5 100644
--- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
+++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
@@ -16,8 +16,6 @@
 
 #define LOG_TAG "mediacas_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/cas/1.0/ICas.h>
 #include <android/hardware/cas/1.0/ICasListener.h>
@@ -27,8 +25,11 @@
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <android/hardware/cas/native/1.0/types.h>
 #include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
 #include <hidl/Status.h>
 #include <hidlmemory/FrameworkUtils.h>
 #include <utils/Condition.h>
@@ -208,29 +209,16 @@
     EXPECT_TRUE(mEventData == eventData);
 }
 
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static CasHidlEnvironment* Instance() {
-        static CasHidlEnvironment* instance = new CasHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override {
-        mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
-            CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+        mService = IMediaCasService::getService(GetParam());
         ASSERT_NE(mService, nullptr);
     }
 
-    sp<IMediaCasService> mService;
+    sp<IMediaCasService> mService = nullptr;
 
-   protected:
+  protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
     }
@@ -325,7 +313,7 @@
         return ::testing::AssertionFailure();
     }
 
-    uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->pointer()));
+    uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->unsecurePointer()));
     memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer));
 
     // hidlMemory is not to be passed out of scope!
@@ -419,7 +407,7 @@
     return ::testing::AssertionResult(returnVoid.isOk());
 }
 
-TEST_F(MediaCasHidlTest, EnumeratePlugins) {
+TEST_P(MediaCasHidlTest, EnumeratePlugins) {
     description("Test enumerate plugins");
     hidl_vec<HidlCasPluginDescriptor> descriptors;
     EXPECT_TRUE(mService
@@ -440,7 +428,7 @@
     }
 }
 
-TEST_F(MediaCasHidlTest, TestInvalidSystemIdFails) {
+TEST_P(MediaCasHidlTest, TestInvalidSystemIdFails) {
     description("Test failure for invalid system ID");
     sp<MediaCasListener> casListener = new MediaCasListener();
 
@@ -458,7 +446,7 @@
     EXPECT_EQ(descramblerBase, nullptr);
 }
 
-TEST_F(MediaCasHidlTest, TestClearKeyPluginInstalled) {
+TEST_P(MediaCasHidlTest, TestClearKeyPluginInstalled) {
     description("Test if ClearKey plugin is installed");
     hidl_vec<HidlCasPluginDescriptor> descriptors;
     EXPECT_TRUE(mService
@@ -480,7 +468,7 @@
     ASSERT_TRUE(false) << "ClearKey plugin not installed";
 }
 
-TEST_F(MediaCasHidlTest, TestClearKeyApis) {
+TEST_P(MediaCasHidlTest, TestClearKeyApis) {
     description("Test that valid call sequences succeed");
 
     ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -568,7 +556,7 @@
     EXPECT_EQ(Status::OK, descrambleStatus);
 
     ASSERT_NE(nullptr, dataMemory.get());
-    uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->pointer()));
+    uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->unsecurePointer()));
 
     int compareResult =
         memcmp(static_cast<const void*>(opBuffer), static_cast<const void*>(kOutRefBinaryBuffer),
@@ -584,7 +572,7 @@
     EXPECT_EQ(Status::OK, returnStatus);
 }
 
-TEST_F(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) {
+TEST_P(MediaCasHidlTest, TestClearKeySessionClosedAfterRelease) {
     description("Test that all sessions are closed after a MediaCas object is released");
 
     ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -611,7 +599,7 @@
     EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, returnStatus);
 }
 
-TEST_F(MediaCasHidlTest, TestClearKeyErrors) {
+TEST_P(MediaCasHidlTest, TestClearKeyErrors) {
     description("Test that invalid call sequences fail with expected error codes");
 
     ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -700,7 +688,7 @@
     EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("bad"));
 }
 
-TEST_F(MediaCasHidlTest, TestClearKeyOobFails) {
+TEST_P(MediaCasHidlTest, TestClearKeyOobFails) {
     description("Test that oob descramble request fails with expected error");
 
     ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -849,11 +837,7 @@
 
 }  // anonymous namespace
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    CasHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, MediaCasHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/cas/1.1/vts/functional/Android.bp b/cas/1.1/vts/functional/Android.bp
index 8afd19a..9e8eb52 100644
--- a/cas/1.1/vts/functional/Android.bp
+++ b/cas/1.1/vts/functional/Android.bp
@@ -30,6 +30,6 @@
     shared_libs: [
         "libbinder",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
index 88f1fb0..1b5797b 100644
--- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
+++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
@@ -16,8 +16,6 @@
 
 #define LOG_TAG "mediacas_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/cas/1.0/IDescramblerBase.h>
 #include <android/hardware/cas/1.0/types.h>
@@ -27,8 +25,11 @@
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <android/hardware/cas/native/1.0/types.h>
 #include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
 #include <hidl/Status.h>
 #include <hidlmemory/FrameworkUtils.h>
 #include <utils/Condition.h>
@@ -251,27 +252,14 @@
     EXPECT_TRUE(mEventData == eventData);
 }
 
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-  public:
-    // get the test environment singleton
-    static CasHidlEnvironment* Instance() {
-        static CasHidlEnvironment* instance = new CasHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
-        mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
-                CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+        mService = IMediaCasService::getService(GetParam());
         ASSERT_NE(mService, nullptr);
     }
 
-    sp<IMediaCasService> mService;
+    sp<IMediaCasService> mService = nullptr;
 
   protected:
     static void description(const std::string& description) {
@@ -366,7 +354,7 @@
         return ::testing::AssertionFailure();
     }
 
-    uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->pointer()));
+    uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->unsecurePointer()));
     memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer));
 
     // hidlMemory is not to be passed out of scope!
@@ -453,7 +441,7 @@
     return ::testing::AssertionResult(returnVoid.isOk());
 }
 
-TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) {
+TEST_P(MediaCasHidlTest, TestClearKeyApisWithSession) {
     description("Test that valid call sequences with SessionEvent send and receive");
 
     ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -543,7 +531,7 @@
     EXPECT_EQ(Status::OK, descrambleStatus);
 
     ASSERT_NE(nullptr, dataMemory.get());
-    uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->pointer()));
+    uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->unsecurePointer()));
 
     int compareResult =
             memcmp(static_cast<const void*>(opBuffer),
@@ -561,11 +549,7 @@
 
 }  // anonymous namespace
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    CasHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, MediaCasHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/cas/1.2/types.hal b/cas/1.2/types.hal
index 40c06cf..06199cd 100644
--- a/cas/1.2/types.hal
+++ b/cas/1.2/types.hal
@@ -45,6 +45,10 @@
      *  ERROR_CAS_BLACKOUT is used to report geographical blackout.
      */
     ERROR_CAS_BLACKOUT,
+    /**
+     * ERROR_CAS_REBOOTING is used to report CAS is during rebooting.
+     */
+    ERROR_CAS_REBOOTING,
 };
 
 /**
diff --git a/cas/1.2/vts/functional/Android.bp b/cas/1.2/vts/functional/Android.bp
index 9bc372c..2d6517f 100644
--- a/cas/1.2/vts/functional/Android.bp
+++ b/cas/1.2/vts/functional/Android.bp
@@ -31,6 +31,8 @@
     shared_libs: [
         "libbinder",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
-
diff --git a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
index 8439ceb..58e0f2e 100644
--- a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
+++ b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
@@ -16,8 +16,6 @@
 
 #define LOG_TAG "mediacas_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/cas/1.0/IDescramblerBase.h>
 #include <android/hardware/cas/1.0/types.h>
@@ -28,8 +26,11 @@
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <android/hardware/cas/native/1.0/types.h>
 #include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
 #include <hidl/Status.h>
 #include <hidlmemory/FrameworkUtils.h>
 #include <utils/Condition.h>
@@ -293,27 +294,14 @@
     EXPECT_EQ(mEventArg, static_cast<int32_t>(mode));
 }
 
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-  public:
-    // get the test environment singleton
-    static CasHidlEnvironment* Instance() {
-        static CasHidlEnvironment* instance = new CasHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
-        mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
-                CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+        mService = IMediaCasService::getService(GetParam());
         ASSERT_NE(mService, nullptr);
     }
 
-    sp<IMediaCasService> mService;
+    sp<IMediaCasService> mService = nullptr;
 
   protected:
     static void description(const std::string& description) {
@@ -497,7 +485,7 @@
     return ::testing::AssertionResult(returnVoid.isOk());
 }
 
-TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) {
+TEST_P(MediaCasHidlTest, TestClearKeyApisWithSession) {
     description("Test that valid call sequences with SessionEvent send and receive");
 
     ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -609,11 +597,7 @@
 
 }  // anonymous namespace
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    CasHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, MediaCasHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index f55e799..9ea4cdf 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -17,5 +17,13 @@
         cpp: {
             enabled: false,
         },
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.media.swcodec",
+            ],
+            min_sdk_version: "29",
+        },
     },
+    versions: ["1"],
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/1/.hash b/common/aidl/aidl_api/android.hardware.common/1/.hash
new file mode 100644
index 0000000..ad5102a
--- /dev/null
+++ b/common/aidl/aidl_api/android.hardware.common/1/.hash
@@ -0,0 +1 @@
+59e782d6ed4c2aed3744d37fb751ee23797835dd
diff --git a/common/aidl/aidl_api/android.hardware.common/1/android/hardware/common/NativeHandle.aidl b/common/aidl/aidl_api/android.hardware.common/1/android/hardware/common/NativeHandle.aidl
new file mode 100644
index 0000000..f37b7d5
--- /dev/null
+++ b/common/aidl/aidl_api/android.hardware.common/1/android/hardware/common/NativeHandle.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.common;
+@VintfStability
+parcelable NativeHandle {
+  ParcelFileDescriptor[] fds;
+  int[] ints;
+}
diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml
index cc4f0cd..e772b6f 100644
--- a/compatibility_matrices/compatibility_matrix.5.xml
+++ b/compatibility_matrices/compatibility_matrix.5.xml
@@ -34,17 +34,46 @@
     <hal format="hidl" optional="true">
         <name>android.hardware.automotive.audiocontrol</name>
         <version>1.0</version>
+        <version>2.0</version>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
-        <name>android.hardware.automotive.evs</name>
+        <name>android.hardware.automotive.can</name>
         <version>1.0</version>
         <interface>
+            <name>ICanBus</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+        <interface>
+            <name>ICanController</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.evs</name>
+        <version>1.0-1</version>
+        <interface>
             <name>IEvsEnumerator</name>
             <instance>default</instance>
+            <regex-instance>[a-z]+/[0-9]+</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.automotive.occupant_awareness</name>
+        <interface>
+            <name>IOccupantAwareness</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.sv</name>
+        <version>1.0</version>
+        <interface>
+            <name>ISurroundViewService</name>
+            <instance>default</instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
@@ -57,7 +86,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.biometrics.face</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IBiometricsFace</name>
             <instance>default</instance>
@@ -65,7 +94,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.biometrics.fingerprint</name>
-        <version>2.1</version>
+        <version>2.1-2</version>
         <interface>
             <name>IBiometricsFingerprint</name>
             <instance>default</instance>
@@ -113,7 +142,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.camera.provider</name>
-        <version>2.4-5</version>
+        <version>2.4-6</version>
         <interface>
             <name>ICameraProvider</name>
             <regex-instance>[^/]+/[0-9]+</regex-instance>
@@ -121,21 +150,13 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.cas</name>
-        <version>1.1</version>
+        <version>1.1-2</version>
         <interface>
             <name>IMediaCasService</name>
             <instance>default</instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
-        <name>android.hardware.configstore</name>
-        <version>1.1</version>
-        <interface>
-            <name>ISurfaceFlingerConfigs</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
         <name>android.hardware.confirmationui</name>
         <version>1.0</version>
         <interface>
@@ -145,7 +166,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>
@@ -153,7 +174,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.drm</name>
-        <version>1.0-2</version>
+        <version>1.3</version>
         <interface>
             <name>ICryptoFactory</name>
             <regex-instance>.*</regex-instance>
@@ -181,7 +202,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.gnss</name>
-        <version>2.0</version>
+        <version>2.0-1</version>
         <interface>
             <name>IGnss</name>
             <instance>default</instance>
@@ -189,8 +210,10 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.allocator</name>
+        <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.0</version>
         <version>3.0</version>
+        <version>4.0</version>
         <interface>
             <name>IAllocator</name>
             <instance>default</instance>
@@ -198,7 +221,7 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.composer</name>
-        <version>2.1-3</version>
+        <version>2.1-4</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>
@@ -206,8 +229,10 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.mapper</name>
+        <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.1</version>
         <version>3.0</version>
+        <version>4.0</version>
         <interface>
             <name>IMapper</name>
             <instance>default</instance>
@@ -269,14 +294,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>
@@ -286,7 +303,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.media.c2</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IComponentStore</name>
             <regex-instance>default[0-9]*</regex-instance>
@@ -354,6 +371,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.radio</name>
+        <version>1.4</version>
         <version>1.5</version>
         <interface>
             <name>IRadio</name>
@@ -389,6 +407,13 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.rebootescrow</name>
+        <interface>
+            <name>IRebootEscrow</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.secure_element</name>
         <version>1.0-2</version>
@@ -401,7 +426,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>
@@ -409,7 +434,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.soundtrigger</name>
-        <version>2.0-2</version>
+        <version>2.0-3</version>
         <interface>
             <name>ISoundTriggerHw</name>
             <instance>default</instance>
@@ -456,6 +481,14 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.tv.tuner</name>
+        <version>1.0</version>
+        <interface>
+            <name>ITuner</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.usb</name>
         <version>1.0-2</version>
         <interface>
@@ -465,7 +498,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.usb.gadget</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IUsbGadget</name>
             <instance>default</instance>
@@ -496,7 +529,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi</name>
-        <version>1.0-3</version>
+        <version>1.0-4</version>
         <interface>
             <name>IWifi</name>
             <instance>default</instance>
@@ -504,7 +537,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi.hostapd</name>
-        <version>1.0-1</version>
+        <version>1.0-2</version>
         <interface>
             <name>IHostapd</name>
             <instance>default</instance>
@@ -512,7 +545,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi.supplicant</name>
-        <version>1.0-2</version>
+        <version>1.0-3</version>
         <interface>
             <name>ISupplicant</name>
             <instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index e86b8ac..46cdf99 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -34,17 +34,46 @@
     <hal format="hidl" optional="true">
         <name>android.hardware.automotive.audiocontrol</name>
         <version>1.0</version>
+        <version>2.0</version>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
-        <name>android.hardware.automotive.evs</name>
+        <name>android.hardware.automotive.can</name>
         <version>1.0</version>
         <interface>
+            <name>ICanBus</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+        <interface>
+            <name>ICanController</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
+        <name>android.hardware.automotive.evs</name>
+        <version>1.0-1</version>
+        <interface>
             <name>IEvsEnumerator</name>
             <instance>default</instance>
+            <regex-instance>[a-z]+/[0-9]+</regex-instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.automotive.occupant_awareness</name>
+        <interface>
+            <name>IOccupantAwareness</name>
+            <instance>default</instance>
+        </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">
@@ -57,7 +86,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.biometrics.face</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IBiometricsFace</name>
             <instance>default</instance>
@@ -65,7 +94,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.biometrics.fingerprint</name>
-        <version>2.1</version>
+        <version>2.1-2</version>
         <interface>
             <name>IBiometricsFingerprint</name>
             <instance>default</instance>
@@ -113,7 +142,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.camera.provider</name>
-        <version>2.4-5</version>
+        <version>2.4-6</version>
         <interface>
             <name>ICameraProvider</name>
             <regex-instance>[^/]+/[0-9]+</regex-instance>
@@ -121,7 +150,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.cas</name>
-        <version>1.1</version>
+        <version>1.1-2</version>
         <interface>
             <name>IMediaCasService</name>
             <instance>default</instance>
@@ -137,7 +166,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>
@@ -145,7 +174,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.drm</name>
-        <version>1.0-2</version>
+        <version>1.3</version>
         <interface>
             <name>ICryptoFactory</name>
             <regex-instance>.*</regex-instance>
@@ -173,7 +202,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.gnss</name>
-        <version>2.0</version>
+        <version>2.0-1</version>
         <interface>
             <name>IGnss</name>
             <instance>default</instance>
@@ -181,8 +210,10 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.allocator</name>
+        <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.0</version>
         <version>3.0</version>
+        <version>4.0</version>
         <interface>
             <name>IAllocator</name>
             <instance>default</instance>
@@ -190,7 +221,7 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.composer</name>
-        <version>2.1-3</version>
+        <version>2.1-4</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>
@@ -198,8 +229,10 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.mapper</name>
+        <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.1</version>
         <version>3.0</version>
+        <version>4.0</version>
         <interface>
             <name>IMapper</name>
             <instance>default</instance>
@@ -261,14 +294,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>
@@ -278,7 +303,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.media.c2</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IComponentStore</name>
             <regex-instance>default[0-9]*</regex-instance>
@@ -381,6 +406,13 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.rebootescrow</name>
+        <interface>
+            <name>IRebootEscrow</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.secure_element</name>
         <version>1.0-2</version>
@@ -393,7 +425,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>
@@ -401,7 +433,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.soundtrigger</name>
-        <version>2.0-2</version>
+        <version>2.0-3</version>
         <interface>
             <name>ISoundTriggerHw</name>
             <instance>default</instance>
@@ -448,6 +480,14 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.tv.tuner</name>
+        <version>1.0</version>
+        <interface>
+            <name>ITuner</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.usb</name>
         <version>1.0-2</version>
         <interface>
@@ -457,7 +497,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.usb.gadget</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IUsbGadget</name>
             <instance>default</instance>
@@ -488,7 +528,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi</name>
-        <version>1.0-3</version>
+        <version>1.0-4</version>
         <interface>
             <name>IWifi</name>
             <instance>default</instance>
@@ -496,7 +536,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi.hostapd</name>
-        <version>1.0-1</version>
+        <version>1.0-2</version>
         <interface>
             <name>IHostapd</name>
             <instance>default</instance>
@@ -504,7 +544,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi.supplicant</name>
-        <version>1.0-2</version>
+        <version>1.0-3</version>
         <interface>
             <name>ISupplicant</name>
             <instance>default</instance>
diff --git a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
index b659be8..fc2893f 100644
--- a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
+++ b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
@@ -1,5 +1,5 @@
 service vendor.contexthub-hal-1-0 /vendor/bin/hw/android.hardware.contexthub@1.0-service
     interface android.hardware.contexthub@1.0::IContexthub default
     class hal
-    user system
-    group system
+    user context_hub
+    group context_hub
diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp
index 8fa4fa5..091f2dc 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",
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..9ee8e76
--- /dev/null
+++ b/contexthub/1.1/Android.bp
@@ -0,0 +1,15 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.contexthub@1.1",
+    root: "android.hardware",
+    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..b00b1bd
--- /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 context_hub
+    group context_hub
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/contexthub/1.1/types.hal b/contexthub/1.1/types.hal
new file mode 100644
index 0000000..885cf32
--- /dev/null
+++ b/contexthub/1.1/types.hal
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * Used to indicate the type of user setting that has changed.
+ */
+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/contexthub/1.1/vts/functional/Android.bp b/contexthub/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..f1625a6
--- /dev/null
+++ b/contexthub/1.1/vts/functional/Android.bp
@@ -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.
+//
+
+cc_test {
+    name: "VtsHalContexthubV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalContexthubV1_1TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.contexthub@1.0",
+        "android.hardware.contexthub@1.1",
+        "VtsHalContexthubUtils",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
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/contexthub/common/vts/Android.bp b/contexthub/common/vts/Android.bp
new file mode 100644
index 0000000..3d5196a
--- /dev/null
+++ b/contexthub/common/vts/Android.bp
@@ -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.
+ */
+
+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 d774dba..6f0debd 100644
--- a/current.txt
+++ b/current.txt
@@ -304,7 +304,6 @@
 fe28829dab10d171783b79ac9cc45412739f8ff275e90228d7c6370ef189b859 android.hardware.audio.effect@4.0::IVisualizerEffect
 21c8a702579356480236c6851b5b2c16b9bd369ce12bdd6ffdc4626a89f34f73 android.hardware.audio.effect@4.0::types
 a0f93c768c353cecee6237fe479bce47404eb10b629fafe07e32a054fd67f2af android.hardware.automotive.audiocontrol@1.0::IAudioControl
-ca515ff4b63c80cf5ad7b3395c997c57d6c56157361f6c367d1c96f23cc4860a android.hardware.automotive.audiocontrol@1.0::types
 f2904a4c108ad1b93eb2fa4e43b82bd01ce1ff26156316e49d1d9fc80dfecaad android.hardware.automotive.evs@1.0::IEvsCamera
 94cba6ad04c83aa840de2ed52b74ba2126a26dd960225e61ac36703315279a80 android.hardware.automotive.evs@1.0::IEvsCameraStream
 5ea36fb043d9e3b413219de3dfd7b046b48af4fda39f167f3528652e986cb76d android.hardware.automotive.evs@1.0::IEvsDisplay
@@ -583,6 +582,23 @@
 cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardware.wifi.supplicant@1.2::types
 
 # ABI preserving changes to HALs during Android R
+c3ec182ce325862b7d79e526f3e170c02cfee1497ed309d7c60d0de4ca636b0b android.hardware.automotive.audiocontrol@1.0::IAudioControl
+1b6d0927615ddbf4c56a993fa1845bca15543e315fb6f48c77276e2fa2918ac5 android.hardware.automotive.evs@1.0::IEvsCamera
+3901859d36b7b4d32910d61cd1e8982b0ffeb8fb77b457ac6349e8bf1abcd595 android.hardware.automotive.evs@1.0::IEvsCameraStream
+578f640c653726d58f99c84a7e1bb63862e21ef7cbb4f7d95c3cc62de00dca35 android.hardware.automotive.evs@1.0::IEvsDisplay
+f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardware.automotive.evs@1.0::IEvsEnumerator
+d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types
+2924c3e43858190ee3e2da4c2fb93bba8ae065fe314451f035a7ec52cb80c94a android.hardware.camera.device@3.2::ICameraDeviceCallback # b/155353799
+2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
+cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
+5cf81b1001296fbb3c5b3d275a859244f61cec5fa858d7be9cca46c5b7dfa733 android.hardware.camera.metadata@3.2::types # b/150331548
+a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types
+9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback
+dd6cd9dba4fde99a1bc3cb1728d82309f509a6e6e1993e5042dfa5ffe4af5442 android.hardware.gnss@2.0::IGnssMeasurementCallback
+af334f1fc85c62b343f84b74d0495eed6f495f7fecedb53463db10c202310058 android.hardware.gnss.measurement_corrections@1.0::types
+33a6b20c43af00fdfb305df891bc5911c06d9a9130b912759649932e5a4a6e6d android.hardware.gnss.visibility_control@1.0::IGnssVisibilityControlCallback
+bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider
+2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback
 b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
 eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
 92e101b30e47bdf526a01c52cecfbe730def5997b8260ab497eb949eb2a6dcdf android.hardware.neuralnetworks@1.0::types
@@ -595,18 +611,21 @@
 a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types
 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
 fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
+ff5dd821c2c7a9c78607159c4d788960b725487263c49d956ca5fa3d37008b45 android.hardware.wifi@1.2::IWifiStaIface
+5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface
 
 # HALs released in Android R
-e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types
-4540d12fe1cea996f21bd1712d4ae0906dcbd58177dac494efc605b004902d43 android.hardware.audio@6.0::IDevice
+7241bd4596a927cd46d4b82f5e29e2cbe57f194aa1b25555f1d1d352e8b15c61 android.hardware.audio@6.0::IDevice
 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory
 bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice
-7318b521ea12fdd4b6e3f381085c71784c810d1ec7a8d701ec2250f3f86712e4 android.hardware.audio@6.0::IStream
+fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream
 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn
-78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut
+164826a380f4c1700183003f62d7532e367b67381c30ea44f946c0cf00008f85 android.hardware.audio@6.0::IStreamOut
 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback
-b495a43bd6ff0c34a391824b0ba1a3f3f34b4a869690611a9a0afc404d75aa84 android.hardware.audio.common@6.0::types
-817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
+e7ca0db9a1098210f327a9b152fa6afe6bf019c41e5264c64829d04d50c0a526 android.hardware.audio@6.0::IStreamOutEventCallback
+aa2211abd803e03d05ea11c18749db068f785fe026f8d99bce64bd764f63d194 android.hardware.audio@6.0::IStreamOutEventCallback  # b/150175043
+822369cf4dc16a6f6b9622bcf86cbdc0b692dc82193fc15e967767175cbfdd8f android.hardware.audio@6.0::types
+bee662c62d997d8065e2bcb5c1e7a9578931f22ce28fd02c219fdb4d0630abf7 android.hardware.audio.common@6.0::types
 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect
 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect
 461b1114cb35d89f87e5694e0792ba53c112a7fa9a14d9b95188cf9c4764be23 android.hardware.audio.effect@6.0::IBassBoostEffect
@@ -621,21 +640,80 @@
 5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect
 282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect
 0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect
+817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
+ca515ff4b63c80cf5ad7b3395c997c57d6c56157361f6c367d1c96f23cc4860a android.hardware.automotive.audiocontrol@1.0::types
+4bc4e8087f5c389f013370ed68bc8a1a29cb2f203237937697f35e005a5ad0b4 android.hardware.automotive.audiocontrol@2.0::IAudioControl
+37ef585d6687cb31e35c67ab456140d70edba9c4333ce5a6ddd70e636e985773 android.hardware.automotive.audiocontrol@2.0::ICloseHandle
+3cf3e5e48ba2642052bbccc1aa4e8bb142933ac960ff40eeedd16e4fe452e7a5 android.hardware.automotive.audiocontrol@2.0::IFocusListener
+44c03f3341939524b5f5acb6680f8a91924d02e335a32840d56597616db7f1ea android.hardware.automotive.audiocontrol@2.0::types
+949a2582c9efa3f6f631f56120eae3f02313f251dbf9246c327e419cdf0652a2 android.hardware.automotive.can@1.0::ICanBus
+43cddb1907a30343bced68946884416ea25ab14ae2df4709357528b2bedba84c android.hardware.automotive.can@1.0::ICanController
+272e826492b27b0dbdeda408e84a41ae43e98f29e57995b6452ded270aae4eee android.hardware.automotive.can@1.0::ICanErrorListener
+07e387bd8bc0e4df5f372515ed960a0b1ae74ea7231d4490a0bb09b07046e4f1 android.hardware.automotive.can@1.0::ICanMessageListener
+2166132d6c247630a193217b4338074f634d6691b1ed6796cb26b3812e90b46e android.hardware.automotive.can@1.0::ICloseHandle
+83355471a3b6d7f777d3f129714585ffb77d9b6f8a3d0365741969631efb81b2 android.hardware.automotive.can@1.0::types
+50bfbeef15d7451bd07e4ad460fbcb7ff80521b89bb8049035c0d458b4125ae4 android.hardware.automotive.evs@1.1::IEvsCamera
+89ff5ab18b3069f21a57f559b290caa50670f0ae1b74178f630183aef39b496b android.hardware.automotive.evs@1.1::IEvsCameraStream
+4c67f768067a0aceac74381f6f62e778ab3b6a18f47db3c9b98c58190ef5619d android.hardware.automotive.evs@1.1::IEvsDisplay
+87958d728d7c0ee9b9391ab4a072b097914921a7b38f7dc3df427f933a5b528e android.hardware.automotive.evs@1.1::IEvsEnumerator
+f53b4e8de6209c6d0fa9036005671b34a2f98328b51423d3a5137a43bf42c84d android.hardware.automotive.evs@1.1::IEvsUltrasonicsArray
+0460bacbde906a846a3d71b2b7b33d6927cac3ff072e523ffac7853577464406 android.hardware.automotive.evs@1.1::IEvsUltrasonicsArrayStream
+f27cf8283e7b953d33dd258734749d2fca9cc63502ea41353060ffa78d8ce9f6 android.hardware.automotive.evs@1.1::types
+4e4904c4067dadae974ddf90351f362331dcd04bba1d890d313cc8ba91f68c15 android.hardware.automotive.sv@1.0::ISurroundView2dSession
+63336e9d03f545020ff2982ff76d9d8c44fa76ad476293b5ef6732cbbd71e61b android.hardware.automotive.sv@1.0::ISurroundView3dSession
+b7015428cd52ce8192d13bfcbf2c4455cda3727d57f2aac80d65a1747104f5ac android.hardware.automotive.sv@1.0::ISurroundViewService
+7d2e77ad86766bbc213fa7377eab739f44cc0866e567e6d33c0e27e7f99e27a8 android.hardware.automotive.sv@1.0::ISurroundViewSession
+d34769e55df919739bb46f25ae2e125e9c807733afa94daeca20feadd74de79c android.hardware.automotive.sv@1.0::ISurroundViewStream
+affd9c591f48a69773fcf43dc4a716d292cd4bc5ba2be8649276af0aedea435d android.hardware.automotive.sv@1.0::types
+140f8f62100ccf9cd282ae3685a0f4ef0a9f971d77dfbc7350ccb4e04cf295ec android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint
+82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback
+ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types
 362fd1c21641c2224f3b80c30d9797b988fa3f344243d531ba73c553779a5763 android.hardware.bluetooth@1.1::IBluetoothHci
 40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks
 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
-d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types
+b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice
+eb90c4d366f05a025d1d1a3672f8b4c3e33e420fa387f73f21b264645bfdf845 android.hardware.camera.device@3.6::ICameraDeviceSession
+a718c8a3acaa938de5a57923e8c4625ed7ca051e05a1d930ba6998557d7b57c8 android.hardware.camera.device@3.6::ICameraOfflineSession
+a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types
+02bdf82dba7dce273a554b4474468a8fb1fb4f61ab65da95eb16e080df63fff6 android.hardware.camera.metadata@3.5::types
+93cd94e47b22007bbf436c2f5c2703bb7b2859d1b714d6ae15520db55667ba6c android.hardware.camera.provider@2.6::ICameraProvider
+8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
+1edf7aef68ef3bd577a1175b1462fb82e3e39f01c6915dda61fba121028df283 android.hardware.camera.provider@2.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
 186bc152ae189ab48f3a761a44ddf5edd0d483073c5b6ca1f802f8b50488b754 android.hardware.dumpstate@1.1::IDumpstateDevice
+d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types
+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
+df52e2c39ed701a355b5e0fdbf83fe5fa7d04bfecd715116b39373d46dc3c682 android.hardware.gnss@2.1::IGnssMeasurementCallback
+769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types
+6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections
+956c1576ca0d6f11b42980ef59052062836b6763fe973af6cb709da50787f710 android.hardware.gnss.measurement_corrections@1.1::types
+a2dcf188b02102d3cf80ca0a280dce05d45a8df809751b3c52347426ed58ebbe android.hardware.graphics.allocator@4.0::IAllocator
+0a90c665605df3d7d7b0fcafcc4178c3345a6e4ba7e3148fefe4973629827463 android.hardware.graphics.composer@2.4::IComposer
+809b815bac3d9a5ead591b5fed20f08dbd2bcf7b5c6858201fdd0d8347db9177 android.hardware.graphics.composer@2.4::IComposerCallback
+8006ee6e02453443f7e79cfcd9f85d9863bed53c4cfc55519de98b64ca72edc2 android.hardware.graphics.composer@2.4::IComposerClient
+fda61f0a5a56cf4e0e8697fb4899a26a4dc450ff837f3425b53932fe34583d11 android.hardware.graphics.composer@2.4::types
+4d674afdc4447f614c8cc466ed45c5955a0192fa3d3c70884b11dd3c88f0b468 android.hardware.graphics.mapper@4.0::IMapper
+b58a5e83a8ab04ff6e500f6afc17a1129a1f3de044b296b4b6bd34a085220f87 android.hardware.graphics.mapper@4.0::types
 ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
 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
-8da9c938e58f7d636ddd2f92c646f99d9a9e79612e6441b6380ab12744251873 android.hardware.identity@1.0::IWritableIdentityCredential
 c5da8636c14cd30f1ae9f10c2219e35b4e29a64443103a5842352dd070afe514 android.hardware.keymaster@4.1::IKeymasterDevice
 ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types
+df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
+a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer
 278817920bfd5292a7713f97f1832cca53de3de640f7670e413d97c6e7fd581c android.hardware.neuralnetworks@1.3::IDevice
 127ba11efb8220dc3aec9a8f441b59eaf1c68d7f03f577833e1824de75a36b17 android.hardware.neuralnetworks@1.3::IExecutionCallback
@@ -645,17 +723,53 @@
 acf84925f8ee0a651f2ec547ac334034de266479b93af5434f6c1f25e66aba96 android.hardware.neuralnetworks@1.3::types
 e9080d04218e98512b63aace9ff3da52f0130238391f15cbbf7df396a3ec9072 android.hardware.neuralnetworks@1.3::types # b/155508675, b/155662254, b/155238914, b/155660285
 583dc88b41e702e940fd954edda1beb8b4151eab55a5c6d7e69e2781bce84b59 android.hardware.neuralnetworks@1.3::types # b/156918813
-a5bcd595a5108312fe2eb402e716d0b7dab8eb689a2a5f54fdef3ff71f3babd5 android.hardware.radio@1.5::types
 b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio
 fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication
 b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse
+a5bcd595a5108312fe2eb402e716d0b7dab8eb689a2a5f54fdef3ff71f3babd5 android.hardware.radio@1.5::types
+c2cc192edcc222a12b524fb0e0e7f17ef2b48d6b1c0be7b60bc114601793d7a9 android.hardware.secure_element@1.2::ISecureElement
+3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors
+3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback
+8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types
+b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw
+4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types
+b878fcad575742925690303f717e2186058a378670be6e2f85e7e503841954aa android.hardware.tv.cec@2.0::IHdmiCec
+009b9a02619b14da27027cb5d424fa01f098f6b6f6fa0829049497fc3612d67d android.hardware.tv.cec@2.0::IHdmiCecCallback
+af1443272c4db47dea5adc5b6c4293dd09c20466a58684c68a5d88c0e7e46261 android.hardware.tv.cec@2.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
+b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types
+7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
+3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
+84757251ff195b447dc511c0d3f055a684d4fed7847eb4d65a2455eb914059d2 android.hardware.wifi@1.4::IWifiApIface
+2e07983a70a1b963bee8aece050e5ea503a3dde31e21a9f8352cf17e9113d347 android.hardware.wifi@1.4::IWifiChip
+08c1912be480c08aa77f6d56bb083d66cd13eca11e01c2d3e727bcb3a1e4f79b android.hardware.wifi@1.4::IWifiChipEventCallback
+ff66371a467d1f3caacea15d93f39b7b767b0d6b8cd41d040337cdabf2514b87 android.hardware.wifi@1.4::IWifiNanIface
+10bd6f19198c281ee2052641048e970ad66b732e4f6ffe79a0f697ea15761e0f android.hardware.wifi@1.4::IWifiRttController
+fcd92a4c898360185dd659f0a1e3001c25eb40b59c3457fd235acf3a8c407525 android.hardware.wifi@1.4::IWifiRttControllerEventCallback
+d878c406d9c1cc67f9d9a3a66b16dcbd7d944e0ed520745fc9ad21d95031e839 android.hardware.wifi@1.4::types
+c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
+2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types
+a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
+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
 
 # ABI preserving changes to HALs during Android S
 cd84ab19c590e0e73dd2307b591a3093ee18147ef95e6d5418644463a6620076 android.hardware.neuralnetworks@1.2::IDevice
 9625e85f56515ad2cf87b6a1847906db669f746ea4ab02cd3d4ca25abc9b0109 android.hardware.neuralnetworks@1.2::types
 9e758e208d14f7256e0885d6d8ad0b61121b21d8c313864f981727ae55bffd16 android.hardware.neuralnetworks@1.3::types
-38d65fb20c60a5b823298560fc0825457ecdc49603a4b4e94bf81511790737da android.hardware.radio@1.4::types
-954c334efd80e8869b66d1ce5fe2755712d96ba4b3c38d415739c330af5fb4cb android.hardware.radio@1.5::types
 
 # HALs released in Android S
 # NOTE: waiting to freeze HALs until later in the release
diff --git a/drm/1.1/vts/functional/AndroidTest.xml b/drm/1.1/vts/functional/AndroidTest.xml
index 65c45ac..24eeb72 100644
--- a/drm/1.1/vts/functional/AndroidTest.xml
+++ b/drm/1.1/vts/functional/AndroidTest.xml
@@ -19,6 +19,10 @@
 
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
 
+    <target_preparer class="com.android.tradefed.targetprep.WifiPreparer" >
+        <option name="verify-only" value="true" />
+    </target_preparer>
+
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
         <option name="push-file" key="VtsHalDrmV1_1TargetTest" value="/data/local/tmp/VtsHalDrmV1_1TargetTest" />
diff --git a/drm/1.2/vts/functional/AndroidTest.xml b/drm/1.2/vts/functional/AndroidTest.xml
index 5da38ae..3285c37 100644
--- a/drm/1.2/vts/functional/AndroidTest.xml
+++ b/drm/1.2/vts/functional/AndroidTest.xml
@@ -19,6 +19,10 @@
 
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
 
+    <target_preparer class="com.android.tradefed.targetprep.WifiPreparer" >
+        <option name="verify-only" value="true" />
+    </target_preparer>
+
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
         <option name="push-file" key="VtsHalDrmV1_2TargetTest" value="/data/local/tmp/VtsHalDrmV1_2TargetTest" />
diff --git a/drm/1.3/Android.bp b/drm/1.3/Android.bp
new file mode 100644
index 0000000..9a2b9e1
--- /dev/null
+++ b/drm/1.3/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.drm@1.3",
+    root: "android.hardware",
+    srcs: [
+        "ICryptoFactory.hal",
+        "IDrmFactory.hal",
+    ],
+    interfaces: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/drm/1.3/ICryptoFactory.hal b/drm/1.3/ICryptoFactory.hal
new file mode 100644
index 0000000..d7864eb
--- /dev/null
+++ b/drm/1.3/ICryptoFactory.hal
@@ -0,0 +1,32 @@
+/*
+ * 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.drm@1.3;
+
+import @1.2::ICryptoFactory;
+
+/**
+ * ICryptoFactory is the main entry point for interacting with a vendor's
+ * crypto HAL to create crypto plugins. Crypto plugins create crypto sessions
+ * which are used by a codec to decrypt protected video content.
+ *
+ * The 1.3 factory must always create 1.2 ICryptoPlugin interfaces, which are
+ * returned via the 1.0 createPlugin method.
+ *
+ * The ICryptoFactory hal is required because all top-level interfaces
+ * have to be updated in a minor uprev.
+ */
+interface ICryptoFactory extends @1.2::ICryptoFactory {
+};
diff --git a/drm/1.3/IDrmFactory.hal b/drm/1.3/IDrmFactory.hal
new file mode 100644
index 0000000..5208028
--- /dev/null
+++ b/drm/1.3/IDrmFactory.hal
@@ -0,0 +1,38 @@
+/*
+ * 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.drm@1.3;
+
+import @1.2::IDrmFactory;
+
+/**
+ * IDrmFactory is the main entry point for interacting with a vendor's
+ * drm HAL to create drm plugin instances. A drm plugin instance
+ * creates drm sessions which are used to obtain keys for a crypto
+ * session so it can decrypt protected video content.
+ *
+ * The 1.3 factory must always create 1.2 IDrmPlugin interfaces, which are
+ * returned via the 1.0 createPlugin method.
+ */
+
+interface IDrmFactory extends @1.2::IDrmFactory {
+    /**
+     * Return vector of uuids identifying crypto schemes supported by this HAL.
+     *
+     * @return schemes Vector of uuids for which isCryptoSchemeSupported is true;
+     *                 each uuid can be used as input to createPlugin.
+     */
+    getSupportedCryptoSchemes() generates(vec<uint8_t[16]> schemes);
+};
diff --git a/drm/1.3/vts/OWNERS b/drm/1.3/vts/OWNERS
new file mode 100644
index 0000000..3a0672e
--- /dev/null
+++ b/drm/1.3/vts/OWNERS
@@ -0,0 +1,9 @@
+conglin@google.com
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+juce@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
+sigquit@google.com
diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..bd9db85
--- /dev/null
+++ b/drm/1.3/vts/functional/Android.bp
@@ -0,0 +1,92 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.drm@1.3-vts",
+    defaults: ["VtsHalTargetTestDefaults"],
+    local_include_dirs: [
+        "include",
+    ],
+    srcs: [
+        "drm_hal_test.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
+        "android.hardware.drm@1.3",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libcrypto",
+        "libhidlmemory",
+        "libnativehelper",
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0-helper",
+        "libdrmvtshelper",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
+
+cc_test {
+    name: "VtsHalDrmV1_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    include_dirs: ["hardware/interfaces/drm/1.0/vts/functional"],
+    srcs: [
+        "drm_hal_test_main.cpp",
+    ],
+    whole_static_libs: [
+        "android.hardware.drm@1.0-vts",
+        "android.hardware.drm@1.1-vts",
+        "android.hardware.drm@1.2-vts",
+        "android.hardware.drm@1.3-vts",
+    ],
+    shared_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
+        "android.hardware.drm@1.3",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libcrypto",
+        "libhidlmemory",
+        "libnativehelper",
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0-helper",
+        "libdrmvtshelper",
+    ],
+    arch: {
+        arm: {
+            data: [":libvtswidevine-arm-prebuilts"],
+        },
+        arm64: {
+            data: [":libvtswidevine-arm64-prebuilts"],
+        },
+        x86: {
+            data: [":libvtswidevine-x86-prebuilts"],
+        },
+        x86_64: {
+            data: [":libvtswidevine-x86_64-prebuilts"],
+        },
+    },
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/drm/1.3/vts/functional/AndroidTest.xml b/drm/1.3/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..9cc8e0c
--- /dev/null
+++ b/drm/1.3/vts/functional/AndroidTest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalDrmV1_3TargetTest.">
+    <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 class="com.android.tradefed.targetprep.WifiPreparer" >
+        <option name="verify-only" value="true" />
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="VtsHalDrmV1_3TargetTest" value="/data/local/tmp/VtsHalDrmV1_3TargetTest" />
+        <option name="push-file" key="libvtswidevine64.so" value="/data/local/tmp/64/lib/libvtswidevine.so" />
+        <option name="push-file" key="libvtswidevine32.so" value="/data/local/tmp/32/lib/libvtswidevine.so" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalDrmV1_3TargetTest" />
+    </test>
+</configuration>
diff --git a/drm/1.3/vts/functional/drm_hal_test.cpp b/drm/1.3/vts/functional/drm_hal_test.cpp
new file mode 100644
index 0000000..0958c35
--- /dev/null
+++ b/drm/1.3/vts/functional/drm_hal_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "drm_hal_test@1.3"
+
+#include "android/hardware/drm/1.3/vts/drm_hal_test.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_3 {
+namespace vts {
+
+TEST_P(DrmHalTestV1_3, SchemeSupported) {
+    EXPECT_TRUE(drmFactory_->isCryptoSchemeSupported(GetParam().scheme_));
+}
+
+TEST_P(DrmHalTestV1_3, SignRsaNotAllowed) {
+    hidl_array<uint8_t, 16> kWidevineUUID ({
+        0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
+        0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED
+    });
+
+    if (!drmFactory_->isCryptoSchemeSupported(kWidevineUUID)) {
+        GTEST_SKIP() << "Widevine only test";
+    }
+
+    // signRSA
+    const hidl_vec<uint8_t>& sessionId{0};
+    const hidl_string& algorithm{"RSASSA-PSS-SHA1"};
+    const hidl_vec<uint8_t>& message{0};
+    const hidl_vec<uint8_t>& wrappedKey{0};
+    auto res = drmPlugin_->signRSA(
+        sessionId, algorithm, message, wrappedKey,
+        [&](StatusV1_0 status, const hidl_vec<uint8_t>& signature) {
+            EXPECT_EQ(status, StatusV1_0::ERROR_DRM_UNKNOWN);
+            EXPECT_EQ(signature.size(), 0);
+        }
+    );
+    EXPECT_TRUE(res.isOk());
+}
+
+}  // namespace vts
+}  // namespace V1_3
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
diff --git a/drm/1.3/vts/functional/drm_hal_test_main.cpp b/drm/1.3/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000..02b45ea
--- /dev/null
+++ b/drm/1.3/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Instantiate the set of test cases for each vendor module
+ */
+
+#define LOG_TAG "drm_hal_test@1.3"
+
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h" // V1_0 tests
+#include "android/hardware/drm/1.0/vts/drm_hal_vendor_test.h"   // V1_0 tests
+#include "android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h" // V1_1 tests
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h"        // V1_2 tests
+#include "android/hardware/drm/1.3/vts/drm_hal_test.h"          // V1_3 tests
+
+using drm_vts::DrmHalTestParam;
+using drm_vts::PrintParamInstanceToString;
+
+using android::hardware::drm::V1_0::vts::DrmHalVendorFactoryTest;
+using android::hardware::drm::V1_0::vts::DrmHalVendorPluginTest;
+using android::hardware::drm::V1_0::vts::DrmHalVendorDecryptTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyFactoryTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyPluginTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyDecryptTest;
+using android::hardware::drm::V1_1::vts::DrmHalClearkeyTest;
+using android::hardware::drm::V1_2::vts::DrmHalTest;
+using android::hardware::drm::V1_2::vts::DrmHalClearkeyTestV1_2;
+using android::hardware::drm::V1_3::vts::DrmHalTestV1_3;
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+    using ::android::hardware::drm::V1_3::ICryptoFactory;
+    using ::android::hardware::drm::V1_3::IDrmFactory;
+
+    std::vector<std::string> drmInstances =
+            android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+    std::vector<std::string> cryptoInstances =
+            android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+    std::set<std::string> allInstances;
+    allInstances.insert(drmInstances.begin(), drmInstances.end());
+    allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+    std::vector<DrmHalTestParam> allInstanceUuidCombos;
+    for (const auto &instance : allInstances) {
+        auto drmFactory = IDrmFactory::getService(instance);
+        if (drmFactory == nullptr) {
+            continue;
+        }
+        drmFactory->getSupportedCryptoSchemes(
+            [&](const hidl_vec<hidl_array<uint8_t, 16>>& schemes) {
+                for (const auto &scheme : schemes) {
+                    allInstanceUuidCombos.push_back(DrmHalTestParam(instance, scheme));
+                }
+            });
+    }
+    return allInstanceUuidCombos;
+}();
+
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorFactoryTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorPluginTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorDecryptTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyFactoryTest,
+                         testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyPluginTest,
+                         testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyDecryptTest,
+                         testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_1, DrmHalClearkeyTest,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalTest,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalClearkeyTestV1_2,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_3, DrmHalTestV1_3,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+
+int main(int argc, char** argv) {
+#if defined(__LP64__)
+    const char* kModulePath = "/data/local/tmp/64/lib";
+#else
+    const char* kModulePath = "/data/local/tmp/32/lib";
+#endif
+    DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath);
+    if (DrmHalTest::gVendorModules->getPathList().size() == 0) {
+        std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
+                ", all vendor tests will be skipped" << std::endl;
+    }
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h
new file mode 100644
index 0000000..d8f5277
--- /dev/null
+++ b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DRM_HAL_TEST_V1_3_H
+#define DRM_HAL_TEST_V1_3_H
+
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "drm_hal_vendor_module_api.h"
+#include "drm_vts_helper.h"
+#include "vendor_modules.h"
+#include "VtsHalHidlTargetCallbackBase.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_3 {
+namespace vts {
+
+using android::hardware::hidl_array;
+using android::hardware::hidl_string;
+
+using drm_vts::DrmHalTestParam;
+
+using IDrmFactoryV1_3 = android::hardware::drm::V1_3::IDrmFactory;
+using IDrmPluginV1_0 = android::hardware::drm::V1_0::IDrmPlugin;
+using StatusV1_0 = android::hardware::drm::V1_0::Status;
+
+class DrmHalTestV1_3 : public ::testing::TestWithParam<DrmHalTestParam> {
+public:
+    DrmHalTestV1_3()
+        : drmFactory_(IDrmFactoryV1_3::getService(GetParam().instance_)) {}
+
+    virtual void SetUp() override {
+        ASSERT_NE(drmFactory_, nullptr);
+
+        // create plugin
+        hidl_string packageName("android.hardware.drm.V1_3.vts");
+        auto res = drmFactory_->createPlugin(
+            GetParam().scheme_, packageName,
+            [&](StatusV1_0 status, const sp<IDrmPluginV1_0>& pluginV1_0) {
+                EXPECT_EQ(StatusV1_0::OK, status);
+                drmPlugin_ = pluginV1_0;
+            });
+        EXPECT_TRUE(res.isOk());
+        ASSERT_NE(drmPlugin_, nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+protected:
+    sp<IDrmFactoryV1_3> drmFactory_;
+    sp<IDrmPluginV1_0> drmPlugin_;
+};
+
+}  // namespace vts
+}  // namespace V1_3
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
+
+#endif  // DRM_HAL_TEST_V1_3_H
diff --git a/drm/TEST_MAPPING b/drm/TEST_MAPPING
new file mode 100644
index 0000000..cff6819
--- /dev/null
+++ b/drm/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+  "imports": [
+    // gts and cts filters
+    {
+      "path": "frameworks/av/drm/libmediadrm"
+    }
+  ]
+}
diff --git a/gnss/1.0/IGnssCallback.hal b/gnss/1.0/IGnssCallback.hal
index d62676f..311ab21 100644
--- a/gnss/1.0/IGnssCallback.hal
+++ b/gnss/1.0/IGnssCallback.hal
@@ -90,6 +90,7 @@
          * - QZSS:    193-200
          * - Galileo: 1-36
          * - Beidou:  1-37
+         * - IRNSS:   1-14
          */
         int16_t svid;
 
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index a6c2940..97e7c27 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -22,6 +22,7 @@
 #include <log/log.h>
 
 #include <chrono>
+#include <cmath>
 #include <condition_variable>
 #include <mutex>
 
@@ -39,9 +40,9 @@
 using android::sp;
 
 static bool IsAutomotiveDevice() {
-  char buffer[PROPERTY_VALUE_MAX] = {0};
-  property_get("ro.hardware.type", buffer, "");
-  return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+    char buffer[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware.type", buffer, "");
+    return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
 }
 
 #define TIMEOUT_SEC 2  // for basic commands/responses
@@ -411,6 +412,34 @@
 }
 
 /*
+ * InjectSeedLocation:
+ * Injects a seed location and ensures the injected seed location is not fused in the resulting
+ * GNSS location.
+ */
+TEST_P(GnssHalTest, InjectSeedLocation) {
+    // An arbitrary position in North Pacific Ocean (where no VTS labs will ever likely be located).
+    const double seedLatDegrees = 32.312894;
+    const double seedLngDegrees = -172.954117;
+    const float seedAccuracyMeters = 150.0;
+
+    auto result = gnss_hal_->injectLocation(seedLatDegrees, seedLngDegrees, seedAccuracyMeters);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    StartAndGetSingleLocation(false);
+
+    // Ensure we don't get a location anywhere within 111km (1 degree of lat or lng) of the seed
+    // location.
+    EXPECT_TRUE(std::abs(last_location_.latitudeDegrees - seedLatDegrees) > 1.0 ||
+                std::abs(last_location_.longitudeDegrees - seedLngDegrees) > 1.0);
+
+    StopAndClearLocations();
+
+    auto resultVoid = gnss_hal_->deleteAidingData(IGnss::GnssAidingData::DELETE_POSITION);
+    ASSERT_TRUE(resultVoid.isOk());
+}
+
+/*
  * GetAllExtentions:
  * Tries getting all optional extensions, and ensures a valid return
  *   null or actual extension, no crash.
diff --git a/gnss/1.1/default/Android.bp b/gnss/1.1/default/Android.bp
index 95bd7f3..9c498d5 100644
--- a/gnss/1.1/default/Android.bp
+++ b/gnss/1.1/default/Android.bp
@@ -14,6 +14,8 @@
         "libhidlbase",
         "libutils",
         "liblog",
+        "android.hardware.gnss@2.1",
+        "android.hardware.gnss@2.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@1.0",
     ],
diff --git a/gnss/1.1/default/Gnss.cpp b/gnss/1.1/default/Gnss.cpp
index 4abe707..5043649 100644
--- a/gnss/1.1/default/Gnss.cpp
+++ b/gnss/1.1/default/Gnss.cpp
@@ -44,7 +44,7 @@
             auto svStatus = this->getMockSvStatus();
             this->reportSvStatus(svStatus);
 
-            auto location = Utils::getMockLocation();
+            auto location = Utils::getMockLocationV1_0();
             this->reportLocation(location);
 
             std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
@@ -197,14 +197,14 @@
 Return<GnssSvStatus> Gnss::getMockSvStatus() const {
     std::unique_lock<std::recursive_mutex> lock(mGnssConfiguration->getMutex());
     GnssSvInfo mockGnssSvInfoList[] = {
-            Utils::getSvInfo(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5),
-            Utils::getSvInfo(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5),
-            Utils::getSvInfo(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0),
-            Utils::getSvInfo(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0),
-            Utils::getSvInfo(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0),
-            Utils::getSvInfo(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0),
-            Utils::getSvInfo(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0),
-            Utils::getSvInfo(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)};
+            Utils::getMockSvInfoV1_0(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5),
+            Utils::getMockSvInfoV1_0(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5),
+            Utils::getMockSvInfoV1_0(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0),
+            Utils::getMockSvInfoV1_0(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0),
+            Utils::getMockSvInfoV1_0(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0),
+            Utils::getMockSvInfoV1_0(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0),
+            Utils::getMockSvInfoV1_0(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0),
+            Utils::getMockSvInfoV1_0(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)};
 
     GnssSvStatus svStatus = {.numSvs = sizeof(mockGnssSvInfoList) / sizeof(GnssSvInfo)};
     for (uint32_t i = 0; i < svStatus.numSvs; i++) {
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index 237ac42..c9914fb 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -30,6 +30,10 @@
     ],
     shared_libs: [
         "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss.measurement_corrections@1.1",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
index ca9eef4..4a0a7f9 100644
--- a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
+++ b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
@@ -15,15 +15,15 @@
  */
 #define LOG_TAG "VtsHalGnssV1_1TargetTest"
 
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "gnss_hal_test.h"
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    GnssHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+using android::hardware::gnss::V1_1::IGnss;
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GnssHalTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index e6e3c85..52aaa69 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "GnssHalTest"
 
 #include <android/hidl/manager/1.2/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
 
 #include <gnss_hal_test.h>
@@ -28,18 +30,8 @@
 
 using ::android::hardware::gnss::common::Utils;
 
-// Implementations for the main test class for GNSS HAL
-GnssHalTest::GnssHalTest()
-    : info_called_count_(0),
-      capabilities_called_count_(0),
-      location_called_count_(0),
-      name_called_count_(0),
-      notify_count_(0) {}
-
 void GnssHalTest::SetUp() {
-    gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
-        GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
-    list_gnss_sv_status_.clear();
+    gnss_hal_ = IGnss::getService(GetParam());
     ASSERT_NE(gnss_hal_, nullptr);
 
     SetUpGnssCallback();
@@ -48,14 +40,15 @@
 void GnssHalTest::TearDown() {
     if (gnss_hal_ != nullptr) {
         gnss_hal_->cleanup();
+        gnss_hal_ = nullptr;
     }
-    if (notify_count_ > 0) {
-        ALOGW("%d unprocessed callbacks discarded", notify_count_);
-    }
+
+    // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
+    gnss_cb_ = nullptr;
 }
 
 void GnssHalTest::SetUpGnssCallback() {
-    gnss_cb_ = new GnssCallback(*this);
+    gnss_cb_ = new GnssCallback();
     ASSERT_NE(gnss_cb_, nullptr);
 
     auto result = gnss_hal_->setCallback_1_1(gnss_cb_);
@@ -69,13 +62,13 @@
     /*
      * All capabilities, name and systemInfo callbacks should trigger
      */
-    EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
-    EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
-    EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+    EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC));
+    EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC));
+    EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC));
 
-    EXPECT_EQ(capabilities_called_count_, 1);
-    EXPECT_EQ(info_called_count_, 1);
-    EXPECT_EQ(name_called_count_, 1);
+    EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1);
+    EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1);
+    EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1);
 }
 
 void GnssHalTest::StopAndClearLocations() {
@@ -89,9 +82,9 @@
      * the last reply for final startup messages to arrive (esp. system
      * info.)
      */
-    while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) {
+    while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) {
     }
-    location_called_count_ = 0;
+    gnss_cb_->location_cbq_.reset();
 }
 
 void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
@@ -106,7 +99,7 @@
     EXPECT_TRUE(result);
 }
 
-bool GnssHalTest::StartAndCheckFirstLocation() {
+bool GnssHalTest::StartAndCheckFirstLocation(bool strict) {
     auto result = gnss_hal_->start();
 
     EXPECT_TRUE(result.isOk());
@@ -117,20 +110,26 @@
      * so allow time to demodulate ephemeris over the air.
      */
     const int kFirstGnssLocationTimeoutSeconds = 75;
+    int locationCalledCount = 0;
 
-    wait(kFirstGnssLocationTimeoutSeconds);
-    EXPECT_EQ(location_called_count_, 1);
+    if (strict) {
+        EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+                                                     kFirstGnssLocationTimeoutSeconds));
+        locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+        EXPECT_EQ(locationCalledCount, 1);
+    }
 
-    if (location_called_count_ > 0) {
+    if (locationCalledCount > 0) {
         // don't require speed on first fix
-        CheckLocation(last_location_, false);
+        CheckLocation(gnss_cb_->last_location_, false);
         return true;
     }
     return false;
 }
 
 void GnssHalTest::CheckLocation(GnssLocation& location, bool check_speed) {
-    bool check_more_accuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017);
+    const bool check_more_accuracies =
+            (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017);
 
     Utils::checkLocation(location, check_speed, check_more_accuracies);
 }
@@ -142,15 +141,17 @@
 
     SetPositionMode(kMinIntervalMsec, kLowPowerMode);
 
-    EXPECT_TRUE(StartAndCheckFirstLocation());
+    EXPECT_TRUE(StartAndCheckFirstLocation(/* strict= */ true));
 
     for (int i = 1; i < count; i++) {
-        EXPECT_EQ(std::cv_status::no_timeout, wait(kLocationTimeoutSubsequentSec));
-        EXPECT_EQ(location_called_count_, i + 1);
+        EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+                                                     kLocationTimeoutSubsequentSec));
+        int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+        EXPECT_EQ(locationCalledCount, i + 1);
         // Don't cause confusion by checking details if no location yet
-        if (location_called_count_ > 0) {
+        if (locationCalledCount > 0) {
             // Should be more than 1 location by now, but if not, still don't check first fix speed
-            CheckLocation(last_location_, location_called_count_ > 1);
+            CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1);
         }
     }
 }
@@ -174,22 +175,33 @@
                 hasGnssHalVersion_2_0 = registered.size() != 0;
             });
 
-    return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
+    bool hasGnssHalVersion_2_1 = false;
+    manager->listManifestByInterface(
+            "android.hardware.gnss@2.1::IGnss",
+            [&hasGnssHalVersion_2_1](const hidl_vec<hidl_string>& registered) {
+                hasGnssHalVersion_2_1 = registered.size() != 0;
+            });
+
+    return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0 && !hasGnssHalVersion_2_1;
 }
 
-GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation() {
-    const int kLocationsToAwait = 3;
-
-    StartAndCheckLocations(kLocationsToAwait);
+GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
+        const int locations_to_await, const int gnss_sv_info_list_timeout) {
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(locations_to_await);
+    const int location_called_count = gnss_cb_->location_cbq_.calledCount();
 
     // Tolerate 1 less sv status to handle edge cases in reporting.
-    EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
-    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
-          (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
+    int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+    EXPECT_GE(sv_status_cbq_size + 1, locations_to_await);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size,
+          locations_to_await, location_called_count);
 
-    // Find first non-GPS constellation
+    // Find first non-GPS constellation to blacklist
     GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
-    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+    for (int i = 0; i < sv_status_cbq_size; ++i) {
+        IGnssCallback::GnssSvStatus gnss_sv_status;
+        gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, gnss_sv_info_list_timeout);
         for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
             const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
             if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
@@ -207,66 +219,47 @@
 
     if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
         ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
-        // Proceed functionally to return something.
+        // Proceed functionally to blacklist something.
         constellation_to_blacklist = GnssConstellationType::GLONASS;
     }
     return constellation_to_blacklist;
 }
 
-void GnssHalTest::notify() {
-    std::unique_lock<std::mutex> lock(mtx_);
-    notify_count_++;
-    cv_.notify_one();
-}
-
-std::cv_status GnssHalTest::wait(int timeout_seconds) {
-    std::unique_lock<std::mutex> lock(mtx_);
-
-    auto status = std::cv_status::no_timeout;
-    while (notify_count_ == 0) {
-        status = cv_.wait_for(lock, std::chrono::seconds(timeout_seconds));
-        if (status == std::cv_status::timeout) return status;
-    }
-    notify_count_--;
-    return status;
-}
+GnssHalTest::GnssCallback::GnssCallback()
+    : info_cbq_("system_info"),
+      name_cbq_("name"),
+      capabilities_cbq_("capabilities"),
+      location_cbq_("location"),
+      sv_status_cbq_("sv_status") {}
 
 Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
     const IGnssCallback::GnssSystemInfo& info) {
     ALOGI("Info received, year %d", info.yearOfHw);
-    parent_.info_called_count_++;
-    parent_.last_info_ = info;
-    parent_.notify();
+    info_cbq_.store(info);
     return Void();
 }
 
 Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
     ALOGI("Capabilities received %d", capabilities);
-    parent_.capabilities_called_count_++;
-    parent_.last_capabilities_ = capabilities;
-    parent_.notify();
+    capabilities_cbq_.store(capabilities);
     return Void();
 }
 
 Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
     ALOGI("Name received: %s", name.c_str());
-    parent_.name_called_count_++;
-    parent_.last_name_ = name;
-    parent_.notify();
+    name_cbq_.store(name);
     return Void();
 }
 
 Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation& location) {
     ALOGI("Location received");
-    parent_.location_called_count_++;
-    parent_.last_location_ = location;
-    parent_.notify();
+    location_cbq_.store(location);
     return Void();
 }
 
 Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(
     const IGnssCallback::GnssSvStatus& svStatus) {
     ALOGI("GnssSvStatus received");
-    parent_.list_gnss_sv_status_.emplace_back(svStatus);
+    sv_status_cbq_.store(svStatus);
     return Void();
 }
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index 09ebadc..75c4216 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -19,18 +19,15 @@
 
 #include <android/hardware/gnss/1.1/IGnss.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
-#include <condition_variable>
-#include <list>
-#include <mutex>
+#include <gtest/gtest.h>
+#include "GnssCallbackEventQueue.h"
 
 using android::hardware::Return;
 using android::hardware::Void;
 
 using android::hardware::gnss::V1_0::GnssLocation;
 
+using android::hardware::gnss::common::GnssCallbackEventQueue;
 using android::hardware::gnss::V1_0::GnssConstellationType;
 using android::hardware::gnss::V1_0::GnssLocationFlags;
 using android::hardware::gnss::V1_1::IGnss;
@@ -40,26 +37,9 @@
 
 #define TIMEOUT_SEC 2  // for basic commands/responses
 
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static GnssHidlEnvironment* Instance() {
-        static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
-   private:
-    GnssHidlEnvironment() {}
-};
-
 // The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
-    GnssHalTest();
-
+class GnssHalTest : public testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override;
 
     virtual void TearDown() override;
@@ -73,32 +53,40 @@
     /* Callback class for data & Event. */
     class GnssCallback : public IGnssCallback {
        public:
-        GnssHalTest& parent_;
+         IGnssCallback::GnssSystemInfo last_info_;
+         android::hardware::hidl_string last_name_;
+         uint32_t last_capabilities_;
+         GnssLocation last_location_;
 
-        GnssCallback(GnssHalTest& parent) : parent_(parent){};
+         GnssCallbackEventQueue<IGnssCallback::GnssSystemInfo> info_cbq_;
+         GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
+         GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+         GnssCallbackEventQueue<GnssLocation> location_cbq_;
+         GnssCallbackEventQueue<IGnssCallback::GnssSvStatus> sv_status_cbq_;
 
-        virtual ~GnssCallback() = default;
+         GnssCallback();
+         virtual ~GnssCallback() = default;
 
-        // Dummy callback handlers
-        Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override {
-            return Void();
-        }
-        Return<void> gnssNmeaCb(int64_t /* timestamp */,
-                                const android::hardware::hidl_string& /* nmea */) override {
-            return Void();
-        }
-        Return<void> gnssAcquireWakelockCb() override { return Void(); }
-        Return<void> gnssReleaseWakelockCb() override { return Void(); }
-        Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
-            return Void();
-        }
-        Return<void> gnssRequestTimeCb() override { return Void(); }
-        // Actual (test) callback handlers
-        Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
-        Return<void> gnssLocationCb(const GnssLocation& location) override;
-        Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
-        Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
-        Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
+         // Dummy callback handlers
+         Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override {
+             return Void();
+         }
+         Return<void> gnssNmeaCb(int64_t /* timestamp */,
+                                 const android::hardware::hidl_string& /* nmea */) override {
+             return Void();
+         }
+         Return<void> gnssAcquireWakelockCb() override { return Void(); }
+         Return<void> gnssReleaseWakelockCb() override { return Void(); }
+         Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
+             return Void();
+         }
+         Return<void> gnssRequestTimeCb() override { return Void(); }
+         // Actual (test) callback handlers
+         Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+         Return<void> gnssLocationCb(const GnssLocation& location) override;
+         Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+         Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
+         Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
     };
 
     /*
@@ -114,9 +102,11 @@
      *   <p> Note this leaves the Location request active, to enable Stop call vs. other call
      *   reordering tests.
      *
+     *   <p> if 'strict' is true, the test will fail if no location is generated.
+     *
      * returns  true if a location was successfully generated
      */
-    bool StartAndCheckFirstLocation();
+    bool StartAndCheckFirstLocation(bool strict);
 
     /*
      * CheckLocation:
@@ -160,29 +150,11 @@
      * Note that location is not stopped in this method. The client should call
      * StopAndClearLocations() after the call.
      */
-    GnssConstellationType startLocationAndGetNonGpsConstellation();
+    GnssConstellationType startLocationAndGetNonGpsConstellation(
+            const int locations_to_await, const int gnss_sv_info_list_timeout);
 
     sp<IGnss> gnss_hal_;         // GNSS HAL to call into
-    sp<IGnssCallback> gnss_cb_;  // Primary callback interface
-
-    /* Count of calls to set the following items, and the latest item (used by
-     * test.)
-     */
-    int info_called_count_;
-    IGnssCallback::GnssSystemInfo last_info_;
-    uint32_t last_capabilities_;
-    int capabilities_called_count_;
-    int location_called_count_;
-    GnssLocation last_location_;
-    list<IGnssCallback::GnssSvStatus> list_gnss_sv_status_;
-
-    int name_called_count_;
-    android::hardware::hidl_string last_name_;
-
-   private:
-    std::mutex mtx_;
-    std::condition_variable cv_;
-    int notify_count_;
+    sp<GnssCallback> gnss_cb_;   // Primary callback interface
 };
 
 #endif  // GNSS_HAL_TEST_H_
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 7c54a80..e6a51eb 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -18,10 +18,9 @@
 
 #include <gnss_hal_test.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 #include <android/hardware/gnss/1.1/IGnssConfiguration.h>
 #include <cutils/properties.h>
+#include <gtest/gtest.h>
 
 using android::hardware::hidl_vec;
 
@@ -35,9 +34,9 @@
 using android::hardware::gnss::V1_1::IGnssMeasurement;
 
 static bool IsAutomotiveDevice() {
-  char buffer[PROPERTY_VALUE_MAX] = {0};
-  property_get("ro.hardware.type", buffer, "");
-  return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+    char buffer[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware.type", buffer, "");
+    return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
 }
 
 /*
@@ -46,18 +45,18 @@
  *
  * Empty test fixture to verify basic Setup & Teardown
  */
-TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
 
 /*
  * TestGnssMeasurementCallback:
  * Gets the GnssMeasurementExtension and verify that it returns an actual extension.
  */
-TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
+TEST_P(GnssHalTest, TestGnssMeasurementCallback) {
     auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
     ASSERT_TRUE(gnssMeasurement_1_1.isOk());
     auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
     ASSERT_TRUE(gnssMeasurement_1_0.isOk());
-    if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
+    if (gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
         sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
         sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
         // At least one interface must be non-null.
@@ -72,7 +71,7 @@
  * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
  * each received location.
  */
-TEST_F(GnssHalTest, GetLocationLowPower) {
+TEST_P(GnssHalTest, GetLocationLowPower) {
     if (!IsGnssHalVersion_1_1()) {
         ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1.");
         return;
@@ -85,14 +84,16 @@
     const bool kLowPowerMode = true;
 
     // Warmup period - VTS doesn't have AGPS access via GnssLocationProvider
-    StartAndCheckLocations(5);
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToCheck);
     StopAndClearLocations();
+    gnss_cb_->location_cbq_.reset();
 
     // Start of Low Power Mode test
     SetPositionMode(kMinIntervalMsec, kLowPowerMode);
 
     // Don't expect true - as without AGPS access
-    if (!StartAndCheckFirstLocation()) {
+    if (!StartAndCheckFirstLocation(/* strict= */ false)) {
         ALOGW("GetLocationLowPower test - no first low power location received.");
     }
 
@@ -100,24 +101,26 @@
         // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
         // ensure that no location is received yet
 
-        wait(kNoLocationPeriodSec);
+        gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
+        const int location_called_count = gnss_cb_->location_cbq_.calledCount();
         // Tolerate (ignore) one extra location right after the first one
         // to handle startup edge case scheduling limitations in some implementations
-        if ((i == 1) && (location_called_count_ == 2)) {
-            CheckLocation(last_location_, true);
+        if ((i == 1) && (location_called_count == 2)) {
+            CheckLocation(gnss_cb_->last_location_, true);
             continue;  // restart the quiet wait period after this too-fast location
         }
-        EXPECT_LE(location_called_count_, i);
-        if (location_called_count_ != i) {
+        EXPECT_LE(location_called_count, i);
+        if (location_called_count != i) {
             ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
-                  location_called_count_, i);
+                  location_called_count, i);
         }
 
-        if (std::cv_status::no_timeout !=
-            wait(kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
+        if (!gnss_cb_->location_cbq_.retrieve(
+                    gnss_cb_->last_location_,
+                    kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
             ALOGW("GetLocationLowPower test - timeout awaiting location %d", i);
         } else {
-            CheckLocation(last_location_, true);
+            CheckLocation(gnss_cb_->last_location_, true);
         }
     }
 
@@ -134,7 +137,8 @@
  */
 
 IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
-    const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status, const int min_observations) {
+        const std::list<IGnssCallback::GnssSvStatus> list_gnss_sv_status,
+        const int min_observations) {
     struct ComparableBlacklistedSource {
         IGnssConfiguration::BlacklistedSource id;
 
@@ -220,7 +224,7 @@
  * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
  * formerly strongest satellite
  */
-TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
     if (!IsGnssHalVersion_1_1()) {
         ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 1.1.");
         return;
@@ -229,12 +233,15 @@
     const int kLocationsToAwait = 3;
     const int kRetriesToUnBlacklist = 10;
 
+    gnss_cb_->location_cbq_.reset();
     StartAndCheckLocations(kLocationsToAwait);
+    int location_called_count = gnss_cb_->location_cbq_.calledCount();
 
     // Tolerate 1 less sv status to handle edge cases in reporting.
-    EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
-    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
-          (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
+    int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+    EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size,
+          kLocationsToAwait, location_called_count);
 
     /*
      * Identify strongest SV seen at least kLocationsToAwait -1 times
@@ -242,8 +249,14 @@
      * observability (one epoch RF null)
      */
 
+    const int kGnssSvStatusTimeout = 2;
+    std::list<IGnssCallback::GnssSvStatus> sv_status_list;
+    int count = gnss_cb_->sv_status_cbq_.retrieve(sv_status_list, sv_status_cbq_size,
+                                                  kGnssSvStatusTimeout);
+    ASSERT_EQ(count, sv_status_cbq_size);
+
     IGnssConfiguration::BlacklistedSource source_to_blacklist =
-        FindStrongFrequentNonGpsSource(list_gnss_sv_status_, kLocationsToAwait - 1);
+            FindStrongFrequentNonGpsSource(sv_status_list, kLocationsToAwait - 1);
 
     if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) {
         // Cannot find a non-GPS satellite. Let the test pass.
@@ -267,21 +280,26 @@
     EXPECT_TRUE(result);
 
     // retry and ensure satellite not used
-    list_gnss_sv_status_.clear();
+    gnss_cb_->sv_status_cbq_.reset();
 
+    gnss_cb_->location_cbq_.reset();
     StartAndCheckLocations(kLocationsToAwait);
 
     // early exit if test is being run with insufficient signal
-    if (location_called_count_ == 0) {
+    location_called_count = gnss_cb_->location_cbq_.calledCount();
+    if (location_called_count == 0) {
         ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
     }
-    ASSERT_TRUE(location_called_count_ > 0);
+    ASSERT_TRUE(location_called_count > 0);
 
     // Tolerate 1 less sv status to handle edge cases in reporting.
-    EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
-    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
-          (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
-    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+    sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+    EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size,
+          kLocationsToAwait, location_called_count);
+    for (int i = 0; i < sv_status_cbq_size; ++i) {
+        IGnssCallback::GnssSvStatus gnss_sv_status;
+        gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
         for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
             const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
             EXPECT_FALSE((gnss_sv.svid == source_to_blacklist.svid) &&
@@ -302,24 +320,28 @@
     int unblacklist_loops_remaining = kRetriesToUnBlacklist;
     while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
         StopAndClearLocations();
-        list_gnss_sv_status_.clear();
+        gnss_cb_->sv_status_cbq_.reset();
 
+        gnss_cb_->location_cbq_.reset();
         StartAndCheckLocations(kLocationsToAwait);
 
         // early exit loop if test is being run with insufficient signal
-        if (location_called_count_ == 0) {
+        location_called_count = gnss_cb_->location_cbq_.calledCount();
+        if (location_called_count == 0) {
             ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
         }
-        ASSERT_TRUE(location_called_count_ > 0);
+        ASSERT_TRUE(location_called_count > 0);
 
         // Tolerate 1 less sv status to handle edge cases in reporting.
-        EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
-        ALOGD(
-            "Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
-            ", tries remaining %d",
-            (int)list_gnss_sv_status_.size(), kLocationsToAwait, unblacklist_loops_remaining);
+        sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+        EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+        ALOGD("Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
+              ", tries remaining %d",
+              sv_status_cbq_size, kLocationsToAwait, unblacklist_loops_remaining);
 
-        for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+        for (int i = 0; i < sv_status_cbq_size; ++i) {
+            IGnssCallback::GnssSvStatus gnss_sv_status;
+            gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
             for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
                 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
                 if ((gnss_sv.svid == source_to_blacklist.svid) &&
@@ -346,15 +368,18 @@
  * GnssStatus does not use any constellation but GPS.
  * 4a & b) Clean up by turning off location, and send in empty blacklist.
  */
-TEST_F(GnssHalTest, BlacklistConstellationWithLocationOff) {
+TEST_P(GnssHalTest, BlacklistConstellationWithLocationOff) {
     if (!IsGnssHalVersion_1_1()) {
         ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
         return;
     }
 
     const int kLocationsToAwait = 3;
+    const int kGnssSvStatusTimeout = 2;
+
     // Find first non-GPS constellation to blacklist
-    GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
+    GnssConstellationType constellation_to_blacklist =
+            startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvStatusTimeout);
 
     // Turns off location
     StopAndClearLocations();
@@ -372,21 +397,25 @@
     sources.resize(1);
     sources[0] = source_to_blacklist;
 
+    // setBlacklist when location is off.
     auto result = gnss_configuration_hal->setBlacklist(sources);
     ASSERT_TRUE(result.isOk());
     EXPECT_TRUE(result);
 
     // retry and ensure constellation not used
-    list_gnss_sv_status_.clear();
+    gnss_cb_->sv_status_cbq_.reset();
 
-    location_called_count_ = 0;
+    gnss_cb_->location_cbq_.reset();
     StartAndCheckLocations(kLocationsToAwait);
 
     // Tolerate 1 less sv status to handle edge cases in reporting.
-    EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
-    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+    int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+    EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_status_cbq_size,
           kLocationsToAwait);
-    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+    for (int i = 0; i < sv_status_cbq_size; ++i) {
+        IGnssCallback::GnssSvStatus gnss_sv_status;
+        gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
         for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
             const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
             EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
@@ -407,19 +436,23 @@
  *
  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
  * GnssStatus for any non-GPS constellations.
- * 2a & b) Blacklist first non-GPS constellations, and turns off location.
+ * 2a & b) Blacklist first non-GPS constellation, and turn off location.
  * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
  * GnssStatus does not use any constellation but GPS.
  * 4a & b) Clean up by turning off location, and send in empty blacklist.
  */
-TEST_F(GnssHalTest, BlacklistConstellationWithLocationOn) {
+TEST_P(GnssHalTest, BlacklistConstellationWithLocationOn) {
     if (!IsGnssHalVersion_1_1()) {
         ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
         return;
     }
 
     const int kLocationsToAwait = 3;
-    GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
+    const int kGnssSvStatusTimeout = 2;
+
+    // Find first non-GPS constellation to blacklist
+    GnssConstellationType constellation_to_blacklist =
+            startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvStatusTimeout);
 
     IGnssConfiguration::BlacklistedSource source_to_blacklist;
     source_to_blacklist.constellation = constellation_to_blacklist;
@@ -434,7 +467,7 @@
     sources.resize(1);
     sources[0] = source_to_blacklist;
 
-    // setBlacklist when location is on.
+    // setBlacklist when location is still on
     auto result = gnss_configuration_hal->setBlacklist(sources);
     ASSERT_TRUE(result.isOk());
     EXPECT_TRUE(result);
@@ -443,16 +476,19 @@
     StopAndClearLocations();
 
     // retry and ensure constellation not used
-    list_gnss_sv_status_.clear();
+    gnss_cb_->sv_status_cbq_.reset();
 
-    location_called_count_ = 0;
+    gnss_cb_->location_cbq_.reset();
     StartAndCheckLocations(kLocationsToAwait);
 
     // Tolerate 1 less sv status to handle edge cases in reporting.
-    EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
-    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+    int sv_status_cbq_size = gnss_cb_->sv_status_cbq_.size();
+    EXPECT_GE(sv_status_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_status_cbq_size,
           kLocationsToAwait);
-    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+    for (int i = 0; i < sv_status_cbq_size; ++i) {
+        IGnssCallback::GnssSvStatus gnss_sv_status;
+        gnss_cb_->sv_status_cbq_.retrieve(gnss_sv_status, kGnssSvStatusTimeout);
         for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
             const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
             EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
@@ -473,9 +509,9 @@
  *
  * Ensure successfully injecting a location.
  */
-TEST_F(GnssHalTest, InjectBestLocation) {
+TEST_P(GnssHalTest, InjectBestLocation) {
     StartAndCheckLocations(1);
-    GnssLocation gnssLocation = last_location_;
+    GnssLocation gnssLocation = gnss_cb_->last_location_;
     CheckLocation(gnssLocation, true);
 
     auto result = gnss_hal_->injectBestLocation(gnssLocation);
@@ -492,10 +528,11 @@
  * GnssDebugValuesSanityTest:
  * Ensures that GnssDebug values make sense.
  */
-TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
+TEST_P(GnssHalTest, GnssDebugValuesSanityTest) {
     auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
     ASSERT_TRUE(gnssDebug.isOk());
-    if (!IsAutomotiveDevice() && info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
+    if (!IsAutomotiveDevice() && gnss_cb_->info_cbq_.calledCount() > 0 &&
+        gnss_cb_->last_info_.yearOfHw >= 2017) {
         sp<IGnssDebug> iGnssDebug = gnssDebug;
         EXPECT_NE(iGnssDebug, nullptr);
 
diff --git a/gnss/2.0/IGnssMeasurementCallback.hal b/gnss/2.0/IGnssMeasurementCallback.hal
index e055f7a..76c7943 100644
--- a/gnss/2.0/IGnssMeasurementCallback.hal
+++ b/gnss/2.0/IGnssMeasurementCallback.hal
@@ -402,6 +402,8 @@
          * Value "C" represents GPS L1 C/A,  GPS L2 C/A, GLONASS G1 C/A, GLONASS G2 C/A, GALILEO E1C,
          * GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C.
          *
+         * value "D" represents BDS B1C D.
+         *
          * Value "I" represents GPS L5 I, GLONASS G3 I, GALILEO E5a I, GALILEO E5b I, GALILEO E5a+b I,
          * SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I.
          *
@@ -411,7 +413,7 @@
          *
          * Value "N" represents GPS L1 codeless, GPS L2 codeless.
          *
-         * Value "P" represents GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P.
+         * Value "P" represents GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P, BDS B1C P.
          *
          * Value "Q" represents GPS L5 Q, GLONASS G3 Q, GALILEO E5a Q, GALILEO E5b Q, GALILEO E5a+b Q,
          * SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
@@ -423,7 +425,7 @@
          * Value "X" represents GPS L1C (D+P), GPS L2C (M+L), GPS L5 (I+Q), GLONASS G3 (I+Q),
          * GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO E5a+b(I+Q),
          * GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q),
-         * LEX(6) (S+L), BDS B1 (I+Q), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
+         * LEX(6) (S+L), BDS B1 (I+Q), BDS B1C (D+P), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
          *
          * Value "Y" represents GPS L1Y, GPS L2Y.
          *
diff --git a/gnss/2.0/default/Android.bp b/gnss/2.0/default/Android.bp
index 3ba89da..37de55d 100644
--- a/gnss/2.0/default/Android.bp
+++ b/gnss/2.0/default/Android.bp
@@ -25,7 +25,7 @@
         "AGnss.cpp",
         "AGnssRil.cpp",
         "Gnss.cpp",
-	"GnssBatching.cpp",
+        "GnssBatching.cpp",
         "GnssMeasurement.cpp",
         "GnssMeasurementCorrections.cpp",
         "GnssVisibilityControl.cpp",
@@ -35,9 +35,10 @@
         "libhidlbase",
         "libutils",
         "liblog",
-        "android.hardware.gnss@2.0",
         "android.hardware.gnss.measurement_corrections@1.0",
         "android.hardware.gnss.visibility_control@1.0",
+        "android.hardware.gnss@2.1",
+        "android.hardware.gnss@2.0",
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
     ],
diff --git a/gnss/2.0/default/Gnss.cpp b/gnss/2.0/default/Gnss.cpp
index 3d64fc3..09f2fc0 100644
--- a/gnss/2.0/default/Gnss.cpp
+++ b/gnss/2.0/default/Gnss.cpp
@@ -19,7 +19,6 @@
 #include "Gnss.h"
 
 #include <log/log.h>
-#include <utils/SystemClock.h>
 
 #include "AGnss.h"
 #include "AGnssRil.h"
@@ -47,24 +46,6 @@
 sp<V2_0::IGnssCallback> Gnss::sGnssCallback_2_0 = nullptr;
 sp<V1_1::IGnssCallback> Gnss::sGnssCallback_1_1 = nullptr;
 
-namespace {
-
-V2_0::GnssLocation getMockLocationV2_0() {
-    const ElapsedRealtime timestamp = {
-            .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
-                     ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
-            .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
-            // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
-            // In an actual implementation provide an estimate of the synchronization uncertainty
-            // or don't set the field.
-            .timeUncertaintyNs = 1000000};
-
-    V2_0::GnssLocation location = {.v1_0 = Utils::getMockLocation(), .elapsedRealtime = timestamp};
-    return location;
-}
-
-}  // namespace
-
 Gnss::Gnss() : mMinIntervalMs(1000) {}
 
 Gnss::~Gnss() {
@@ -86,7 +67,7 @@
     mIsActive = true;
     mThread = std::thread([this]() {
         while (mIsActive == true) {
-            const auto location = getMockLocationV2_0();
+            const auto location = Utils::getMockLocationV2_0();
             this->reportLocation(location);
 
             std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp
index 1f95ff9..a3ea807 100644
--- a/gnss/2.0/default/GnssMeasurement.cpp
+++ b/gnss/2.0/default/GnssMeasurement.cpp
@@ -16,6 +16,7 @@
 #define LOG_TAG "GnssMeasurement"
 
 #include "GnssMeasurement.h"
+#include "Utils.h"
 
 #include <log/log.h>
 #include <utils/SystemClock.h>
@@ -29,6 +30,7 @@
 using GnssConstellationType = V2_0::GnssConstellationType;
 using GnssMeasurementFlags = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags;
 using GnssMeasurementState = V2_0::IGnssMeasurementCallback::GnssMeasurementState;
+using Utils = common::Utils;
 
 sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback = nullptr;
 
@@ -47,8 +49,8 @@
 
 Return<void> GnssMeasurement::close() {
     ALOGD("close");
-    std::unique_lock<std::mutex> lock(mMutex);
     stop();
+    std::unique_lock<std::mutex> lock(mMutex);
     sCallback = nullptr;
     return Void();
 }
@@ -81,7 +83,7 @@
     mIsActive = true;
     mThread = std::thread([this]() {
         while (mIsActive == true) {
-            auto measurement = this->getMockMeasurement();
+            auto measurement = Utils::getMockMeasurementV2_0();
             this->reportMeasurement(measurement);
 
             std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
@@ -97,60 +99,6 @@
     }
 }
 
-GnssData GnssMeasurement::getMockMeasurement() {
-    V1_0::IGnssMeasurementCallback::GnssMeasurement measurement_1_0 = {
-            .flags = (uint32_t)GnssMeasurementFlags::HAS_CARRIER_FREQUENCY,
-            .svid = (int16_t)6,
-            .constellation = V1_0::GnssConstellationType::UNKNOWN,
-            .timeOffsetNs = 0.0,
-            .receivedSvTimeInNs = 8195997131077,
-            .receivedSvTimeUncertaintyInNs = 15,
-            .cN0DbHz = 30.0,
-            .pseudorangeRateMps = -484.13739013671875,
-            .pseudorangeRateUncertaintyMps = 1.0379999876022339,
-            .accumulatedDeltaRangeState = (uint32_t)V1_0::IGnssMeasurementCallback::
-                    GnssAccumulatedDeltaRangeState::ADR_STATE_UNKNOWN,
-            .accumulatedDeltaRangeM = 0.0,
-            .accumulatedDeltaRangeUncertaintyM = 0.0,
-            .carrierFrequencyHz = 1.59975e+09,
-            .multipathIndicator =
-                    V1_0::IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN};
-    V1_1::IGnssMeasurementCallback::GnssMeasurement measurement_1_1 = {.v1_0 = measurement_1_0};
-    V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = {
-            .v1_1 = measurement_1_1,
-            .codeType = "C",
-            .state = GnssMeasurementState::STATE_CODE_LOCK | GnssMeasurementState::STATE_BIT_SYNC |
-                     GnssMeasurementState::STATE_SUBFRAME_SYNC |
-                     GnssMeasurementState::STATE_TOW_DECODED |
-                     GnssMeasurementState::STATE_GLO_STRING_SYNC |
-                     GnssMeasurementState::STATE_GLO_TOD_DECODED,
-            .constellation = GnssConstellationType::GLONASS,
-    };
-
-    hidl_vec<IGnssMeasurementCallback::GnssMeasurement> measurements(1);
-    measurements[0] = measurement_2_0;
-    V1_0::IGnssMeasurementCallback::GnssClock clock = {.timeNs = 2713545000000,
-                                                       .fullBiasNs = -1226701900521857520,
-                                                       .biasNs = 0.59689998626708984,
-                                                       .biasUncertaintyNs = 47514.989972114563,
-                                                       .driftNsps = -51.757811607455452,
-                                                       .driftUncertaintyNsps = 310.64968328491528,
-                                                       .hwClockDiscontinuityCount = 1};
-
-    ElapsedRealtime timestamp = {
-            .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
-                     ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
-            .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
-            // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
-            // In an actual implementation provide an estimate of the synchronization uncertainty
-            // or don't set the field.
-            .timeUncertaintyNs = 1000000};
-
-    GnssData gnssData = {
-            .measurements = measurements, .clock = clock, .elapsedRealtime = timestamp};
-    return gnssData;
-}
-
 void GnssMeasurement::reportMeasurement(const GnssData& data) {
     ALOGD("reportMeasurement()");
     std::unique_lock<std::mutex> lock(mMutex);
diff --git a/gnss/2.0/default/GnssMeasurement.h b/gnss/2.0/default/GnssMeasurement.h
index c24c00e..73eaa13 100644
--- a/gnss/2.0/default/GnssMeasurement.h
+++ b/gnss/2.0/default/GnssMeasurement.h
@@ -59,13 +59,16 @@
    private:
     void start();
     void stop();
-    GnssData getMockMeasurement();
     void reportMeasurement(const GnssData&);
 
+    // Guarded by mMutex
     static sp<IGnssMeasurementCallback> sCallback;
+
     std::atomic<long> mMinIntervalMillis;
     std::atomic<bool> mIsActive;
     std::thread mThread;
+
+    // Synchronization lock for sCallback
     mutable std::mutex mMutex;
 };
 
diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp
index 278d87b..da5289d 100644
--- a/gnss/2.0/vts/functional/Android.bp
+++ b/gnss/2.0/vts/functional/Android.bp
@@ -28,6 +28,8 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
+        "android.hardware.gnss@2.1",
         "android.hardware.gnss@common-vts-lib",
     ],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
index ae36c50..2c74fa3 100644
--- a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
+++ b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
@@ -15,15 +15,15 @@
  */
 #define LOG_TAG "VtsHalGnssV2_0TargetTest"
 
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "gnss_hal_test.h"
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    GnssHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+using android::hardware::gnss::V2_0::IGnss;
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GnssHalTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index c01e91d..1cb44c5 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -16,16 +16,20 @@
 
 #define LOG_TAG "GnssHalTest"
 
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <gnss_hal_test.h>
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
 #include <chrono>
 #include "Utils.h"
 
+using ::android::hardware::hidl_string;
+
 using ::android::hardware::gnss::common::Utils;
 
 // Implementations for the main test class for GNSS HAL
 void GnssHalTest::SetUp() {
-    gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
-        GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
+    gnss_hal_ = IGnss::getService(GetParam());
     ASSERT_NE(gnss_hal_, nullptr);
 
     SetUpGnssCallback();
@@ -93,23 +97,24 @@
     EXPECT_TRUE(result);
 }
 
-bool GnssHalTest::StartAndCheckFirstLocation() {
+bool GnssHalTest::StartAndCheckFirstLocation(bool strict) {
     const auto result = gnss_hal_->start();
 
     EXPECT_TRUE(result.isOk());
     EXPECT_TRUE(result);
-
     /*
      * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
      * so allow time to demodulate ephemeris over the air.
      */
     const int kFirstGnssLocationTimeoutSeconds = 75;
+    int locationCalledCount = 0;
 
-    EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
-                                                 kFirstGnssLocationTimeoutSeconds));
-    int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
-    EXPECT_EQ(locationCalledCount, 1);
-
+    if (strict) {
+        EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+                                                     kFirstGnssLocationTimeoutSeconds));
+        locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+        EXPECT_EQ(locationCalledCount, 1);
+    }
     if (locationCalledCount > 0) {
         // don't require speed on first fix
         CheckLocation(gnss_cb_->last_location_, false);
@@ -132,7 +137,7 @@
 
     SetPositionMode(kMinIntervalMsec, kLowPowerMode);
 
-    EXPECT_TRUE(StartAndCheckFirstLocation());
+    EXPECT_TRUE(StartAndCheckFirstLocation(/* strict= */ true));
 
     for (int i = 1; i < count; i++) {
         EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
@@ -147,6 +152,27 @@
     }
 }
 
+bool GnssHalTest::IsGnssHalVersion_2_0() const {
+    using ::android::hidl::manager::V1_2::IServiceManager;
+    sp<IServiceManager> manager = ::android::hardware::defaultServiceManager1_2();
+
+    bool hasGnssHalVersion_2_0 = false;
+    manager->listManifestByInterface(
+            "android.hardware.gnss@2.0::IGnss",
+            [&hasGnssHalVersion_2_0](const hidl_vec<hidl_string>& registered) {
+                hasGnssHalVersion_2_0 = registered.size() != 0;
+            });
+
+    bool hasGnssHalVersion_2_1 = false;
+    manager->listManifestByInterface(
+            "android.hardware.gnss@2.1::IGnss",
+            [&hasGnssHalVersion_2_1](const hidl_vec<hidl_string>& registered) {
+                hasGnssHalVersion_2_1 = registered.size() != 0;
+            });
+
+    return hasGnssHalVersion_2_0 && !hasGnssHalVersion_2_1;
+}
+
 GnssHalTest::GnssCallback::GnssCallback()
     : info_cbq_("system_info"),
       name_cbq_("name"),
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 5bfcb1f..7fbd735 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -18,18 +18,15 @@
 #define GNSS_HAL_TEST_H_
 
 #include <android/hardware/gnss/2.0/IGnss.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include "GnssCallbackEventQueue.h"
 
-#include <condition_variable>
-#include <deque>
-#include <list>
-#include <mutex>
+#include <gtest/gtest.h>
 
 using android::hardware::hidl_vec;
 using android::hardware::Return;
 using android::hardware::Void;
 
+using android::hardware::gnss::common::GnssCallbackEventQueue;
 using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
 using android::hardware::gnss::V1_0::GnssLocationFlags;
 using android::hardware::gnss::V2_0::IGnss;
@@ -51,72 +48,13 @@
 
 #define TIMEOUT_SEC 2  // for basic commands/responses
 
-// Test environment for GNSS HIDL HAL.
-class GnssHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static GnssHidlEnvironment* Instance() {
-        static GnssHidlEnvironment* instance = new GnssHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IGnss>(); }
-
-   private:
-    GnssHidlEnvironment() {}
-};
-
 // The main test class for GNSS HAL.
-class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
+class GnssHalTest : public testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override;
 
     virtual void TearDown() override;
 
-    /* Producer/consumer queue for storing/retrieving callback events from GNSS HAL */
-    template <class T>
-    class CallbackQueue {
-      public:
-        CallbackQueue(const std::string& name) : name_(name), called_count_(0){};
-        ~CallbackQueue() { reset(); }
-
-        /* Adds callback event to the end of the queue. */
-        void store(const T& event);
-
-        /*
-         * Removes the callack event at the front of the queue, stores it in event parameter
-         * and returns true. Returns false on timeout and event is not populated.
-         */
-        bool retrieve(T& event, int timeout_seconds);
-
-        /*
-         * Removes parameter count number of callack events at the front of the queue, stores
-         * them in event_list parameter and returns the number of events retrieved. Waits up to
-         * timeout_seconds to retrieve each event. If timeout occurs, it returns the number of
-         * items retrieved which will be less than count.
-         */
-        int retrieve(list<T>& event_list, int count, int timeout_seconds);
-
-        /* Returns the number of events pending to be retrieved from the callback event queue. */
-        int size() const;
-
-        /* Returns the number of callback events received since last reset(). */
-        int calledCount() const;
-
-        /* Clears the callback event queue and resets the calledCount() to 0. */
-        void reset();
-
-      private:
-        CallbackQueue(const CallbackQueue&) = delete;
-        CallbackQueue& operator=(const CallbackQueue&) = delete;
-
-        std::string name_;
-        int called_count_;
-        mutable std::recursive_mutex mtx_;
-        std::condition_variable_any cv_;
-        std::deque<T> events_;
-    };
-
     /* Callback class for data & Event. */
     class GnssCallback : public IGnssCallback_2_0 {
       public:
@@ -125,11 +63,11 @@
         uint32_t last_capabilities_;
         GnssLocation_2_0 last_location_;
 
-        CallbackQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
-        CallbackQueue<android::hardware::hidl_string> name_cbq_;
-        CallbackQueue<uint32_t> capabilities_cbq_;
-        CallbackQueue<GnssLocation_2_0> location_cbq_;
-        CallbackQueue<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_list_cbq_;
+        GnssCallbackEventQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
+        GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
+        GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+        GnssCallbackEventQueue<GnssLocation_2_0> location_cbq_;
+        GnssCallbackEventQueue<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_list_cbq_;
 
         GnssCallback();
         virtual ~GnssCallback() = default;
@@ -172,7 +110,7 @@
     /* Callback class for GnssMeasurement. */
     class GnssMeasurementCallback : public IGnssMeasurementCallback_2_0 {
       public:
-        CallbackQueue<IGnssMeasurementCallback_2_0::GnssData> measurement_cbq_;
+        GnssCallbackEventQueue<IGnssMeasurementCallback_2_0::GnssData> measurement_cbq_;
 
         GnssMeasurementCallback() : measurement_cbq_("measurement"){};
         virtual ~GnssMeasurementCallback() = default;
@@ -195,7 +133,7 @@
     class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
       public:
         uint32_t last_capabilities_;
-        CallbackQueue<uint32_t> capabilities_cbq_;
+        GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
 
         GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
         virtual ~GnssMeasurementCorrectionsCallback() = default;
@@ -217,9 +155,11 @@
      *   <p> Note this leaves the Location request active, to enable Stop call vs. other call
      *   reordering tests.
      *
+     *   <p> if 'strict' is true, the test will fail if no location is generated.
+     *
      * returns  true if a location was successfully generated
      */
-    bool StartAndCheckFirstLocation();
+    bool StartAndCheckFirstLocation(bool strict);
 
     /*
      * CheckLocation:
@@ -246,6 +186,12 @@
     void StopAndClearLocations();
 
     /*
+     * IsGnssHalVersion_2_0:
+     * returns  true if the GNSS HAL version is exactly 2.0.
+     */
+    bool IsGnssHalVersion_2_0() const;
+
+    /*
      * SetPositionMode:
      * Helper function to set positioning mode and verify output
      */
@@ -265,61 +211,4 @@
     sp<GnssCallback> gnss_cb_;   // Primary callback interface
 };
 
-template <class T>
-void GnssHalTest::CallbackQueue<T>::store(const T& event) {
-    std::unique_lock<std::recursive_mutex> lock(mtx_);
-    events_.push_back(event);
-    ++called_count_;
-    lock.unlock();
-    cv_.notify_all();
-}
-
-template <class T>
-bool GnssHalTest::CallbackQueue<T>::retrieve(T& event, int timeout_seconds) {
-    std::unique_lock<std::recursive_mutex> lock(mtx_);
-    cv_.wait_for(lock, std::chrono::seconds(timeout_seconds), [&] { return !events_.empty(); });
-    if (events_.empty()) {
-        return false;
-    }
-    event = events_.front();
-    events_.pop_front();
-    return true;
-}
-
-template <class T>
-int GnssHalTest::CallbackQueue<T>::retrieve(list<T>& event_list, int count, int timeout_seconds) {
-    for (int i = 0; i < count; ++i) {
-        T event;
-        if (!retrieve(event, timeout_seconds)) {
-            return i;
-        }
-        event_list.push_back(event);
-    }
-
-    return count;
-}
-
-template <class T>
-int GnssHalTest::CallbackQueue<T>::size() const {
-    std::unique_lock<std::recursive_mutex> lock(mtx_);
-    return events_.size();
-}
-
-template <class T>
-int GnssHalTest::CallbackQueue<T>::calledCount() const {
-    std::unique_lock<std::recursive_mutex> lock(mtx_);
-    return called_count_;
-}
-
-template <class T>
-void GnssHalTest::CallbackQueue<T>::reset() {
-    std::unique_lock<std::recursive_mutex> lock(mtx_);
-    if (!events_.empty()) {
-        ALOGW("%u unprocessed events discarded in callback queue %s", (unsigned int)events_.size(),
-              name_.c_str());
-    }
-    events_.clear();
-    called_count_ = 0;
-}
-
 #endif  // GNSS_HAL_TEST_H_
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index 13bb901..51dcf0d 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -16,10 +16,11 @@
 
 #define LOG_TAG "GnssHalTestCases"
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <gnss_hal_test.h>
 #include "Utils.h"
 
+#include <gtest/gtest.h>
+
 using android::hardware::hidl_string;
 using android::hardware::hidl_vec;
 
@@ -49,13 +50,13 @@
  *
  * Empty test fixture to verify basic Setup & Teardown
  */
-TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
 
 /*
  * TestGnssMeasurementExtension:
  * Gets the GnssMeasurementExtension and verifies that it returns an actual extension.
  */
-TEST_F(GnssHalTest, TestGnssMeasurementExtension) {
+TEST_P(GnssHalTest, TestGnssMeasurementExtension) {
     auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0();
     auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
     auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
@@ -78,7 +79,7 @@
  * The GNSS HAL 2.0 implementation must support @2.0::IGnssConfiguration interface due to
  * the deprecation of some methods in @1.0::IGnssConfiguration interface.
  */
-TEST_F(GnssHalTest, TestGnssConfigurationExtension) {
+TEST_P(GnssHalTest, TestGnssConfigurationExtension) {
     auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
     ASSERT_TRUE(gnssConfiguration.isOk());
     sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -94,7 +95,7 @@
  * TestGnssConfiguration_setSuplEs_Deprecation:
  * Calls setSuplEs and verifies that it returns false.
  */
-TEST_F(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) {
+TEST_P(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) {
     auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
     ASSERT_TRUE(gnssConfiguration.isOk());
     sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -109,7 +110,7 @@
  * TestGnssConfiguration_setGpsLock_Deprecation:
  * Calls setGpsLock and verifies that it returns false.
  */
-TEST_F(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) {
+TEST_P(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) {
     auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0();
     ASSERT_TRUE(gnssConfiguration.isOk());
     sp<IGnssConfiguration_2_0> iGnssConfiguration = gnssConfiguration;
@@ -128,7 +129,7 @@
  * @2.0::IAGnssRil interface due to the deprecation of framework network API methods needed
  * to support the @1.0::IAGnssRil interface.
  */
-TEST_F(GnssHalTest, TestAGnssRilExtension) {
+TEST_P(GnssHalTest, TestAGnssRilExtension) {
     auto agnssRil_2_0 = gnss_hal_->getExtensionAGnssRil_2_0();
     ASSERT_TRUE(agnssRil_2_0.isOk());
     sp<IAGnssRil_2_0> iAGnssRil_2_0 = agnssRil_2_0;
@@ -146,7 +147,7 @@
  * 1. Updates GNSS HAL that a network has connected.
  * 2. Updates GNSS HAL that network has disconnected.
  */
-TEST_F(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) {
+TEST_P(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) {
     auto agnssRil = gnss_hal_->getExtensionAGnssRil_2_0();
     ASSERT_TRUE(agnssRil.isOk());
     sp<IAGnssRil_2_0> iAGnssRil = agnssRil;
@@ -178,7 +179,11 @@
  * 2. constellation is valid.
  * 3. state is valid.
  */
-TEST_F(GnssHalTest, TestGnssMeasurementFields) {
+TEST_P(GnssHalTest, TestGnssMeasurementFields) {
+    if (!IsGnssHalVersion_2_0()) {
+        ALOGI("Test GnssMeasurementFields skipped. GNSS HAL version is greater than 2.0.");
+        return;
+    }
     const int kFirstGnssMeasurementTimeoutSeconds = 10;
 
     auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -233,7 +238,7 @@
  * @2.0::IAGnss interface due to the deprecation of framework network API methods needed
  * to support the @1.0::IAGnss interface.
  */
-TEST_F(GnssHalTest, TestAGnssExtension) {
+TEST_P(GnssHalTest, TestAGnssExtension) {
     auto agnss_2_0 = gnss_hal_->getExtensionAGnss_2_0();
     ASSERT_TRUE(agnss_2_0.isOk());
     sp<IAGnss_2_0> iAGnss_2_0 = agnss_2_0;
@@ -257,7 +262,7 @@
  * TestGnssNiExtension_Deprecation:
  * Gets the @1.0::IGnssNi extension and verifies that it is a nullptr.
  */
-TEST_F(GnssHalTest, TestGnssNiExtension_Deprecation) {
+TEST_P(GnssHalTest, TestGnssNiExtension_Deprecation) {
     // Verify IGnssNi 1.0 is not supported.
     auto gnssNi = gnss_hal_->getExtensionGnssNi();
     ASSERT_TRUE(!gnssNi.isOk() || ((sp<IGnssNi>)gnssNi) == nullptr);
@@ -268,7 +273,7 @@
  * Gets the GnssVisibilityControlExtension and if it is not null, verifies that it supports
  * the gnss.visibility_control@1.0::IGnssVisibilityControl interface by invoking a method.
  */
-TEST_F(GnssHalTest, TestGnssVisibilityControlExtension) {
+TEST_P(GnssHalTest, TestGnssVisibilityControlExtension) {
     auto gnssVisibilityControl = gnss_hal_->getExtensionVisibilityControl();
     ASSERT_TRUE(gnssVisibilityControl.isOk());
     sp<IGnssVisibilityControl> iGnssVisibilityControl = gnssVisibilityControl;
@@ -289,7 +294,13 @@
  * capabilities are reported and the mandatory LOS_SATS or the EXCESS_PATH_LENGTH
  * capability flag is set.
  */
-TEST_F(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) {
+TEST_P(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) {
+    if (!IsGnssHalVersion_2_0()) {
+        ALOGI("Test GnssMeasurementCorrectionsCapabilities skipped. GNSS HAL version is greater "
+              "than 2.0.");
+        return;
+    }
+
     if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) {
         return;
     }
@@ -317,7 +328,7 @@
  * If measurement corrections capability is supported, verifies that it supports the
  * gnss.measurement_corrections@1.0::IMeasurementCorrections interface by invoking a method.
  */
-TEST_F(GnssHalTest, TestGnssMeasurementCorrections) {
+TEST_P(GnssHalTest, TestGnssMeasurementCorrections) {
     if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) {
         return;
     }
@@ -347,7 +358,7 @@
  * Sets a GnssMeasurementCallback, waits for a GnssData object, and verifies the flags in member
  * elapsedRealitme are valid.
  */
-TEST_F(GnssHalTest, TestGnssDataElapsedRealtimeFlags) {
+TEST_P(GnssHalTest, TestGnssDataElapsedRealtimeFlags) {
     const int kFirstGnssMeasurementTimeoutSeconds = 10;
 
     auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -382,8 +393,8 @@
     iGnssMeasurement->close();
 }
 
-TEST_F(GnssHalTest, TestGnssLocationElapsedRealtime) {
-    StartAndCheckFirstLocation();
+TEST_P(GnssHalTest, TestGnssLocationElapsedRealtime) {
+    StartAndCheckFirstLocation(/* strict= */ true);
 
     ASSERT_TRUE((int)gnss_cb_->last_location_.elapsedRealtime.flags <=
                 (int)(ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
@@ -398,8 +409,8 @@
 }
 
 // This test only verify that injectBestLocation_2_0 does not crash.
-TEST_F(GnssHalTest, TestInjectBestLocation_2_0) {
-    StartAndCheckFirstLocation();
+TEST_P(GnssHalTest, TestInjectBestLocation_2_0) {
+    StartAndCheckFirstLocation(/* strict= */ true);
     gnss_hal_->injectBestLocation_2_0(gnss_cb_->last_location_);
     StopAndClearLocations();
 }
@@ -409,7 +420,7 @@
  * Gets the @2.0::IGnssBatching extension and verifies that it doesn't return an error. Support
  * for this interface is optional.
  */
-TEST_F(GnssHalTest, TestGnssBatchingExtension) {
+TEST_P(GnssHalTest, TestGnssBatchingExtension) {
     auto gnssBatching_2_0 = gnss_hal_->getExtensionGnssBatching_2_0();
     ASSERT_TRUE(gnssBatching_2_0.isOk());
 }
@@ -421,7 +432,7 @@
  * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
  * each received location.
  */
-TEST_F(GnssHalTest, GetLocationLowPower) {
+TEST_P(GnssHalTest, GetLocationLowPower) {
     if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::LOW_POWER_MODE)) {
         ALOGI("Test GetLocationLowPower skipped. LOW_POWER_MODE capability not supported.");
         return;
@@ -443,7 +454,7 @@
     SetPositionMode(kMinIntervalMsec, kLowPowerMode);
 
     // Don't expect true - as without AGPS access
-    if (!StartAndCheckFirstLocation()) {
+    if (!StartAndCheckFirstLocation(/* strict= */ false)) {
         ALOGW("GetLocationLowPower test - no first low power location received.");
     }
 
@@ -452,18 +463,18 @@
         // ensure that no location is received yet
 
         gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
-        const int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+        const int location_called_count = gnss_cb_->location_cbq_.calledCount();
 
         // Tolerate (ignore) one extra location right after the first one
         // to handle startup edge case scheduling limitations in some implementations
-        if ((i == 1) && (locationCalledCount == 2)) {
+        if ((i == 1) && (location_called_count == 2)) {
             CheckLocation(gnss_cb_->last_location_, true);
             continue;  // restart the quiet wait period after this too-fast location
         }
-        EXPECT_LE(locationCalledCount, i);
-        if (locationCalledCount != i) {
-            ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
-                  locationCalledCount, i);
+        EXPECT_LE(location_called_count, i);
+        if (location_called_count != i) {
+            ALOGW("GetLocationLowPower test - too many locations received. %d vs. %d expected ",
+                  location_called_count, i);
         }
 
         if (!gnss_cb_->location_cbq_.retrieve(
@@ -487,7 +498,7 @@
  *         or a source with constellation == UNKNOWN if none are found sufficient times
  */
 IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource(
-        const list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
+        const std::list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
         const int min_observations) {
     struct ComparableBlacklistedSource {
         IGnssConfiguration_1_1::BlacklistedSource id;
@@ -573,7 +584,12 @@
  * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
  * formerly strongest satellite
  */
-TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
+    if (!IsGnssHalVersion_2_0()) {
+        ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 2.0.");
+        return;
+    }
+
     if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
         ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
               " not supported.");
@@ -600,7 +616,7 @@
      */
 
     const int kGnssSvStatusTimeout = 2;
-    list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
+    std::list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
     int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, sv_info_list_cbq_size,
                                                      kGnssSvStatusTimeout);
     ASSERT_EQ(count, sv_info_list_cbq_size);
@@ -718,7 +734,11 @@
  * GnssStatus does not use any constellation but GPS.
  * 4a & b) Clean up by turning off location, and send in empty blacklist.
  */
-TEST_F(GnssHalTest, BlacklistConstellationWithLocationOff) {
+TEST_P(GnssHalTest, BlacklistConstellationWithLocationOff) {
+    if (!IsGnssHalVersion_2_0()) {
+        ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0.");
+        return;
+    }
     if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
         ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
         return;
@@ -790,7 +810,12 @@
  * GnssStatus does not use any constellation but GPS.
  * 4a & b) Clean up by turning off location, and send in empty blacklist.
  */
-TEST_F(GnssHalTest, BlacklistConstellationWithLocationOn) {
+TEST_P(GnssHalTest, BlacklistConstellationWithLocationOn) {
+    if (!IsGnssHalVersion_2_0()) {
+        ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0.");
+        return;
+    }
+
     if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
         ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
         return;
@@ -850,4 +875,4 @@
     result = gnss_configuration_hal->setBlacklist(sources);
     ASSERT_TRUE(result.isOk());
     EXPECT_TRUE(result);
-}
\ No newline at end of file
+}
diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp
new file mode 100644
index 0000000..affbeae
--- /dev/null
+++ b/gnss/2.1/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.gnss@2.1",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IGnss.hal",
+        "IGnssAntennaInfo.hal",
+        "IGnssAntennaInfoCallback.hal",
+        "IGnssCallback.hal",
+        "IGnssConfiguration.hal",
+        "IGnssMeasurement.hal",
+        "IGnssMeasurementCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss.measurement_corrections@1.1",
+        "android.hardware.gnss.visibility_control@1.0",
+        "android.hardware.gnss@1.0",
+        "android.hardware.gnss@1.1",
+        "android.hardware.gnss@2.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+    gen_java_constants: true,
+}
diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal
new file mode 100644
index 0000000..a880b3f
--- /dev/null
+++ b/gnss/2.1/IGnss.hal
@@ -0,0 +1,86 @@
+/*
+ * 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.gnss@2.1;
+
+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.
+ */
+interface IGnss extends @2.0::IGnss {
+    /**
+     * Opens the interface and provides the callback routines to the implementation of this
+     * interface.
+     *
+     * The framework calls this method to instruct the GPS engine to prepare for serving requests
+     * from the framework. The GNSS HAL implementation must respond to all GNSS requests from the
+     * framework upon successful return from this method until cleanup() method is called to
+     * close this interface.
+     *
+     * @param callback Callback interface for IGnss.
+     *
+     * @return success Returns true on success.
+     */
+    setCallback_2_1(IGnssCallback callback) generates (bool success);
+
+    /**
+     * This method returns the IGnssMeasurement interface.
+     *
+     * getExtensionGnssMeasurement(), getExtensionGnssMeasurement_1_1(),
+     * getExtensionGnssMeasurement_2_0(), and getExtensionGnssMeasurement_2_1() methods must return
+     * non-null. They can all return the same, latest version of IGnssMeasurement.
+     *
+     * @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
+     */
+    getExtensionGnssMeasurement_2_1() generates (IGnssMeasurement gnssMeasurementIface);
+
+    /**
+     * This method returns the IGnssConfiguration interface.
+     *
+     * getExtensionGnssConfiguration(), getExtensionGnssConfiguration_1_1(),
+     * getExtensionGnssConfiguration_2_0(), and getExtensionGnssConfiguration_2_1() methods must
+     * return non-null. They can all return the same, latest version of IGnssConfiguration.
+     *
+     * @return gnssConfigurationIface Handle to the IGnssConfiguration interface.
+     */
+    getExtensionGnssConfiguration_2_1() generates (IGnssConfiguration gnssConfigurationIface);
+
+    /**
+     * This method returns the IMeasurementCorrections interface.
+     *
+     * Both getExtensionMeasurementCorrections and getExtensionMeasurementCorrections_1_1 must
+     * return non-null. Both methods can return the same V1.1 IMeasurementCorrections object.
+     *
+     * @return measurementCorrectionsIface Handle to the IMeasurementCorrections interface.
+     */
+    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
new file mode 100644
index 0000000..94be915
--- /dev/null
+++ b/gnss/2.1/IGnssCallback.hal
@@ -0,0 +1,77 @@
+/*
+ * 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.gnss@2.1;
+
+import @2.0::IGnssCallback;
+
+/**
+ * This interface is required for the HAL to communicate certain information
+ * like status and location info back to the platform, the platform implements
+ * 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,
+    };
+
+    /**
+     * 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.
+         */
+        @2.0::IGnssCallback.GnssSvInfo v2_0;
+
+        /**
+         * Baseband Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. It contains
+         * the measured C/N0 value for the signal measured at the baseband.
+         *
+         * This is typically a few dB weaker than the value estimated for C/N0 at the antenna port,
+         * which is reported in cN0DbHz.
+         *
+         * If a signal has separate components (e.g. Pilot and Data channels) and the receiver only
+         * processes one of the components, then the reported basebandCN0DbHz reflects only the
+         * component that is processed.
+         *
+         * This value is mandatory. Like cN0DbHz, it may be reported as 0 for satellites being
+         * reported that may be searched for, but not yet tracked.
+         */
+        double basebandCN0DbHz;
+    };
+
+    /**
+     * Callback for the HAL to pass a vector of GnssSvInfo back to the client.
+     *
+     * @param svInfoList SV info list information from HAL.
+     */
+    gnssSvStatusCb_2_1(vec<GnssSvInfo> svInfoList);
+};
diff --git a/gnss/2.1/IGnssConfiguration.hal b/gnss/2.1/IGnssConfiguration.hal
new file mode 100644
index 0000000..550f325
--- /dev/null
+++ b/gnss/2.1/IGnssConfiguration.hal
@@ -0,0 +1,68 @@
+/*
+ * 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.gnss@2.1;
+
+import @2.0::IGnssConfiguration;
+import @2.0::GnssConstellationType;
+
+/**
+ * Extended interface for GNSS Configuration support.
+ */
+interface IGnssConfiguration extends @2.0::IGnssConfiguration {
+    /**
+     * Represents a blacklisted source, updating the GnssConstellationType to 2.0, which supports
+     * IRNSS.
+     */
+    struct BlacklistedSource {
+        /**
+         * Defines the constellation of the given satellite(s).
+         */
+        GnssConstellationType constellation;
+
+        /**
+         * Satellite (space vehicle) ID number, as defined in GnssSvInfo::svid
+         *
+         * Or 0 to blacklist all svid's for the specified constellation
+         */
+        int16_t svid;
+    };
+
+    /**
+     * Injects a vector of BlacklistedSource(s) which the HAL must not use to calculate the
+     * GNSS location output.
+     *
+     * The superset of all satellite sources provided, including wildcards, in the latest call
+     * to this method, is the set of satellites sources that must not be used in calculating
+     * location.
+     *
+     * All measurements from the specified satellites, across frequency bands, are blacklisted
+     * together.
+     *
+     * If this method is never called after the IGnssConfiguration.hal connection is made on boot,
+     * or is called with an empty vector, then no satellites are to be blacklisted as a result of
+     * this API.
+     *
+     * This blacklist must be considered as an additional source of which satellites
+     * should not be trusted for location on top of existing sources of similar information
+     * such as satellite broadcast health being unhealthy and measurement outlier removal.
+     *
+     * @param blacklist The BlacklistedSource(s) of satellites the HAL must not use.
+     *
+     * @return success Whether the HAL accepts and abides by the provided blacklist.
+     */
+    setBlacklist_2_1(vec<BlacklistedSource> blacklist) generates (bool success);
+};
diff --git a/gnss/2.1/IGnssMeasurement.hal b/gnss/2.1/IGnssMeasurement.hal
new file mode 100644
index 0000000..49ba7eb
--- /dev/null
+++ b/gnss/2.1/IGnssMeasurement.hal
@@ -0,0 +1,50 @@
+/*
+ * 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.gnss@2.1;
+
+import @1.0::IGnssMeasurement;
+import @1.1::IGnssMeasurement;
+import @2.0::IGnssMeasurement;
+import IGnssMeasurementCallback;
+
+/**
+ * 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
+     * output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec
+     * can be tolerated.)
+     *
+     * @param callback Handle to GnssMeasurement callback interface.
+     * @param enableFullTracking If true, GNSS chipset must switch off duty cycling. In such mode
+     *     no clock discontinuities are expected and, when supported, carrier phase should be
+     *     continuous in good signal conditions. All non-blacklisted, healthy constellations,
+     *     satellites and frequency bands that the chipset supports must be reported in this mode.
+     *     The GNSS chipset is allowed to consume more power in this mode. If false, API must behave
+     *     as in HAL V1_0, optimizing power via duty cycling, constellations and frequency limits,
+     *     etc.
+     *
+     * @return initRet Returns SUCCESS if successful. Returns ERROR_ALREADY_INIT if a callback has
+     *     already been registered without a corresponding call to 'close'. Returns ERROR_GENERIC
+     *     for any other error. The HAL must not generate any other updates upon returning this
+     *     error code.
+     */
+    setCallback_2_1(IGnssMeasurementCallback callback, bool enableFullTracking)
+        generates (GnssMeasurementStatus initRet);
+};
diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal
new file mode 100644
index 0000000..60a5423
--- /dev/null
+++ b/gnss/2.1/IGnssMeasurementCallback.hal
@@ -0,0 +1,198 @@
+/*
+ * 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.gnss@2.1;
+
+import @1.0::IGnssMeasurementCallback;
+import @2.0::IGnssMeasurementCallback;
+import @2.0::ElapsedRealtime;
+import GnssSignalType;
+
+/**
+ * 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 : @1.0::IGnssMeasurementCallback.GnssMeasurementFlags {
+        /**
+         * A valid full inter-signal bias is stored in the data structure.
+         */
+        HAS_FULL_ISB = 1 << 16,
+        /**
+         * A valid full inter-signal bias uncertainty is stored in the data structure.
+         */
+        HAS_FULL_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
+     * and satelliteInterSignalBiasUncertaintyNs.
+     */
+    struct GnssMeasurement {
+        /**
+         * GNSS measurement information for a single satellite and frequency, as in the 2.0 version
+         * of the HAL.
+         *
+         * In this version of the HAL, the field 'flags' in the v2_0.v1_1.v1_0 struct is deprecated,
+         * and is no longer used by the framework. The GNSS measurement flags are instead reported
+         * in @2.1::IGnssMeasurementCallback.GnssMeasurement.flags.
+         *
+         */
+        @2.0::IGnssMeasurementCallback.GnssMeasurement v2_0;
+
+        /**
+         * A set of flags indicating the validity of the fields in this data
+         * structure.
+         *
+         * Fields for which there is no corresponding flag must be filled in
+         * with a valid value.  For convenience, these are marked as mandatory.
+         *
+         * Others fields may have invalid information in them, if not marked as
+         * valid by the corresponding bit in flags.
+         */
+        bitfield<GnssMeasurementFlags> flags;
+
+        /**
+         * The full inter-signal bias (ISB) in nanoseconds.
+         *
+         * This value is the sum of the estimated receiver-side and the space-segment-side
+         * inter-system bias, inter-frequency bias and inter-code bias, including
+         *
+         * - Receiver inter-constellation bias (with respect to the constellation in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Receiver inter-frequency bias (with respect to the carrier frequency in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Receiver inter-code bias (with respect to the code type in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset
+         *   (TauGps), BDS-GLO Time Offset (BGTO)) (with respect to the constellation in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Group delay (e.g., Total Group Delay (TGD))
+         * - Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the
+         *   code type in GnssClock.referenceSignalTypeForIsb)
+         *
+         * If a component of the above is already compensated in the provided
+         * GnssMeasurement.receivedSvTimeInNs, then it must not be included in the reported full
+         * ISB.
+         *
+         * The value does not include the inter-frequency Ionospheric bias.
+         *
+         * The full ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
+         */
+        double fullInterSignalBiasNs;
+
+        /**
+         * 1-sigma uncertainty associated with the full inter-signal bias in nanoseconds.
+         */
+        double fullInterSignalBiasUncertaintyNs;
+
+        /**
+         * The satellite inter-signal bias in nanoseconds.
+         *
+         * This value is the sum of the space-segment-side inter-system bias, inter-frequency bias
+         * and inter-code bias, including
+         *
+         * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset
+         *   (TauGps), BDS-GLO Time Offset (BGTO)) (with respect to the constellation in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Group delay (e.g., Total Group Delay (TGD))
+         * - Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in
+         *   GnssClock.referenceSignalTypeForIsb)
+         * - Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the
+         *   code type in GnssClock.referenceSignalTypeForIsb)
+         *
+         * The satellite ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0
+         * nanoseconds.
+         */
+        double satelliteInterSignalBiasNs;
+
+        /**
+         * 1-sigma uncertainty associated with the satellite inter-signal bias in nanoseconds.
+         */
+        double satelliteInterSignalBiasUncertaintyNs;
+
+        /**
+         * Baseband Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. It contains
+         * the measured C/N0 value for the signal measured at the baseband.
+         *
+         * This is typically a few dB weaker than the value estimated for C/N0 at the antenna port,
+         * which is reported in cN0DbHz.
+         *
+         * If a signal has separate components (e.g. Pilot and Data channels) and the receiver only
+         * processes one of the components, then the reported basebandCN0DbHz reflects only the
+         * component that is processed.
+         *
+         * This value is mandatory.
+         */
+        double basebandCN0DbHz;
+    };
+
+    /**
+     * Extends a GNSS clock time, adding a referenceSignalTypeForIsb.
+     */
+    struct GnssClock {
+        /**
+         * GNSS clock time information, as in the 1.0 version of the HAL.
+         */
+        @1.0::IGnssMeasurementCallback.GnssClock v1_0;
+
+        /**
+         * Reference GNSS signal type for inter-signal bias.
+         */
+        GnssSignalType referenceSignalTypeForIsb;
+    };
+
+    /**
+     * Complete set of GNSS Measurement data, same as 2.0 with additional fields in measurements.
+     */
+    struct GnssData {
+        /**
+         * The full set of satellite measurement observations.
+         */
+        vec<GnssMeasurement> measurements;
+
+        /**
+         * The GNSS clock time reading.
+         */
+        GnssClock clock;
+
+        /**
+         * Timing information of the GNSS data synchronized with SystemClock.elapsedRealtimeNanos()
+         * clock.
+         */
+        ElapsedRealtime elapsedRealtime;
+    };
+
+    /**
+     * Callback for the hal to pass a GnssData structure back to the client.
+     *
+     * @param data Contains a reading of GNSS measurements.
+     */
+    gnssMeasurementCb_2_1(GnssData data);
+};
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
new file mode 100644
index 0000000..c4dc8fd
--- /dev/null
+++ b/gnss/2.1/default/Android.bp
@@ -0,0 +1,47 @@
+/*
+ * 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.gnss@2.1-service",
+    init_rc: ["android.hardware.gnss@2.1-service.rc"],
+    relative_install_path: "hw",
+    vendor: true,
+    vintf_fragments: ["android.hardware.gnss@2.1-service.xml"],
+    srcs: [
+        "Gnss.cpp",
+        "GnssAntennaInfo.cpp",
+        "GnssDebug.cpp",
+        "GnssMeasurement.cpp",
+        "GnssMeasurementCorrections.cpp",
+        "GnssConfiguration.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libutils",
+        "liblog",
+        "android.hardware.gnss.measurement_corrections@1.1",
+        "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss.visibility_control@1.0",
+        "android.hardware.gnss@2.1",
+        "android.hardware.gnss@1.0",
+        "android.hardware.gnss@1.1",
+        "android.hardware.gnss@2.0",
+    ],
+    static_libs: [
+        "android.hardware.gnss@common-default-lib",
+    ],
+}
diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp
new file mode 100644
index 0000000..2b327a9
--- /dev/null
+++ b/gnss/2.1/default/Gnss.cpp
@@ -0,0 +1,439 @@
+/*
+ * 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 "Gnss"
+
+#include "Gnss.h"
+#include "GnssAntennaInfo.h"
+#include "GnssDebug.h"
+#include "GnssMeasurement.h"
+#include "GnssMeasurementCorrections.h"
+#include "Utils.h"
+
+#include <log/log.h>
+
+using ::android::hardware::gnss::common::Utils;
+using ::android::hardware::gnss::measurement_corrections::V1_1::implementation::
+        GnssMeasurementCorrections;
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+sp<V2_1::IGnssCallback> Gnss::sGnssCallback_2_1 = nullptr;
+sp<V2_0::IGnssCallback> Gnss::sGnssCallback_2_0 = nullptr;
+sp<V1_1::IGnssCallback> Gnss::sGnssCallback_1_1 = nullptr;
+sp<V1_0::IGnssCallback> Gnss::sGnssCallback_1_0 = nullptr;
+
+Gnss::Gnss() : mMinIntervalMs(1000), mGnssConfiguration{new GnssConfiguration()} {}
+
+Gnss::~Gnss() {
+    stop();
+}
+
+Return<bool> Gnss::start() {
+    ALOGD("start");
+    if (mIsActive) {
+        ALOGW("Gnss has started. Restarting...");
+        stop();
+    }
+
+    mIsActive = true;
+    mThread = std::thread([this]() {
+        while (mIsActive == true) {
+            auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
+            this->reportSvStatus(svStatus);
+
+            if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) {
+                const auto location = Utils::getMockLocationV2_0();
+                this->reportLocation(location);
+            } else {
+                const auto location = Utils::getMockLocationV1_0();
+                this->reportLocation(location);
+            }
+
+            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
+        }
+    });
+    return true;
+}
+
+hidl_vec<GnssSvInfo> Gnss::filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList) {
+    for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
+        if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) {
+            gnssSvInfoList[i].v2_0.v1_0.svFlag &=
+                    ~static_cast<uint8_t>(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
+        }
+    }
+    return gnssSvInfoList;
+}
+
+Return<bool> Gnss::stop() {
+    ALOGD("stop");
+    mIsActive = false;
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+    return true;
+}
+
+// Methods from V1_0::IGnss follow.
+Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback) {
+    if (callback == nullptr) {
+        ALOGE("%s: Null callback ignored", __func__);
+        return false;
+    }
+
+    sGnssCallback_1_0 = callback;
+
+    uint32_t capabilities = 0x0 | V1_0::IGnssCallback::Capabilities::MEASUREMENTS |
+                            V1_0::IGnssCallback::Capabilities::SCHEDULING;
+    auto ret = sGnssCallback_1_0->gnssSetCapabilitesCb(capabilities);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
+
+    ret = sGnssCallback_1_0->gnssSetSystemInfoCb(gnssInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    return true;
+}
+
+Return<void> Gnss::cleanup() {
+    sGnssCallback_2_1 = nullptr;
+    sGnssCallback_2_0 = nullptr;
+    return Void();
+}
+
+Return<bool> Gnss::injectTime(int64_t, int64_t, int32_t) {
+    return true;
+}
+
+Return<bool> Gnss::injectLocation(double, double, float) {
+    return true;
+}
+
+Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData) {
+    // TODO implement
+    return Void();
+}
+
+Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode,
+                                   V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
+                                   uint32_t, uint32_t) {
+    mMinIntervalMs = minIntervalMs;
+    return true;
+}
+
+Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
+    // TODO implement
+    return ::android::sp<V1_0::IAGnssRil>{};
+}
+
+Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssGeofencing>{};
+}
+
+Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss() {
+    // TODO implement
+    return ::android::sp<V1_0::IAGnss>{};
+}
+
+Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssNi>{};
+}
+
+Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
+    ALOGD("Gnss::getExtensionGnssMeasurement");
+    return new GnssMeasurement();
+}
+
+Return<sp<V1_0::IGnssNavigationMessage>> Gnss::getExtensionGnssNavigationMessage() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssNavigationMessage>{};
+}
+
+Return<sp<V1_0::IGnssXtra>> Gnss::getExtensionXtra() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssXtra>{};
+}
+
+Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssConfiguration>{};
+}
+
+Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
+    return new V1_1::implementation::GnssDebug();
+}
+
+Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssBatching>{};
+}
+
+// Methods from V1_1::IGnss follow.
+Return<bool> Gnss::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
+    if (callback == nullptr) {
+        ALOGE("%s: Null callback ignored", __func__);
+        return false;
+    }
+
+    sGnssCallback_1_1 = callback;
+
+    uint32_t capabilities = 0x0;
+    auto ret = sGnssCallback_1_1->gnssSetCapabilitesCb(capabilities);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
+
+    ret = sGnssCallback_1_1->gnssSetSystemInfoCb(gnssInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    auto gnssName = "Google Mock GNSS Implementation v2.1";
+    ret = sGnssCallback_1_1->gnssNameCb(gnssName);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    return true;
+}
+
+Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode,
+                                       V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
+                                       uint32_t, uint32_t, bool) {
+    mMinIntervalMs = minIntervalMs;
+    return true;
+}
+
+Return<sp<V1_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_1_1() {
+    // TODO implement
+    return ::android::sp<V1_1::IGnssConfiguration>{};
+}
+
+Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() {
+    // TODO implement
+    return ::android::sp<V1_1::IGnssMeasurement>{};
+}
+
+Return<bool> Gnss::injectBestLocation(const V1_0::GnssLocation&) {
+    return true;
+}
+
+// Methods from V2_0::IGnss follow.
+Return<bool> Gnss::setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) {
+    ALOGD("Gnss::setCallback_2_0");
+    if (callback == nullptr) {
+        ALOGE("%s: Null callback ignored", __func__);
+        return false;
+    }
+
+    sGnssCallback_2_0 = callback;
+
+    using Capabilities = V2_0::IGnssCallback::Capabilities;
+    const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
+                              Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST;
+    auto ret = sGnssCallback_2_0->gnssSetCapabilitiesCb_2_0(capabilities);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2019};
+
+    ret = sGnssCallback_2_0->gnssSetSystemInfoCb(gnssInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    auto gnssName = "Google Mock GNSS Implementation v2.1";
+    ret = sGnssCallback_2_0->gnssNameCb(gnssName);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    return true;
+}
+
+Return<sp<V2_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_0() {
+    ALOGD("Gnss::getExtensionGnssConfiguration_2_0");
+    return mGnssConfiguration;
+}
+
+Return<sp<V2_0::IGnssDebug>> Gnss::getExtensionGnssDebug_2_0() {
+    // TODO implement
+    return ::android::sp<V2_0::IGnssDebug>{};
+}
+
+Return<sp<V2_0::IAGnss>> Gnss::getExtensionAGnss_2_0() {
+    // TODO implement
+    return ::android::sp<V2_0::IAGnss>{};
+}
+
+Return<sp<V2_0::IAGnssRil>> Gnss::getExtensionAGnssRil_2_0() {
+    // TODO implement
+    return ::android::sp<V2_0::IAGnssRil>{};
+}
+
+Return<sp<V2_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_0() {
+    ALOGD("Gnss::getExtensionGnssMeasurement_2_0");
+    return new GnssMeasurement();
+}
+
+Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
+Gnss::getExtensionMeasurementCorrections() {
+    ALOGD("Gnss::getExtensionMeasurementCorrections()");
+    return new GnssMeasurementCorrections();
+}
+
+Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> Gnss::getExtensionVisibilityControl() {
+    // TODO implement
+    return ::android::sp<visibility_control::V1_0::IGnssVisibilityControl>{};
+}
+
+Return<sp<V2_0::IGnssBatching>> Gnss::getExtensionGnssBatching_2_0() {
+    // TODO implement
+    return ::android::sp<V2_0::IGnssBatching>{};
+}
+
+Return<bool> Gnss::injectBestLocation_2_0(const V2_0::GnssLocation&) {
+    // TODO(b/124012850): Implement function.
+    return bool{};
+}
+
+// Methods from V2_1::IGnss follow.
+Return<bool> Gnss::setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) {
+    ALOGD("Gnss::setCallback_2_1");
+    if (callback == nullptr) {
+        ALOGE("%s: Null callback ignored", __func__);
+        return false;
+    }
+
+    sGnssCallback_2_1 = callback;
+
+    using Capabilities = V2_1::IGnssCallback::Capabilities;
+    const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
+                              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__);
+    }
+
+    V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2020};
+
+    ret = sGnssCallback_2_1->gnssSetSystemInfoCb(gnssInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    auto gnssName = "Android Mock GNSS Implementation v2.1";
+    ret = sGnssCallback_2_1->gnssNameCb(gnssName);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    return true;
+}
+
+Return<sp<V2_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_1() {
+    ALOGD("Gnss::getExtensionGnssMeasurement_2_1");
+    return new GnssMeasurement();
+}
+
+Return<sp<V2_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_1() {
+    ALOGD("Gnss::getExtensionGnssConfiguration_2_1");
+    return mGnssConfiguration;
+}
+
+Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
+Gnss::getExtensionMeasurementCorrections_1_1() {
+    ALOGD("Gnss::getExtensionMeasurementCorrections_1_1()");
+    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
+    if (sGnssCallback_2_1 == nullptr) {
+        ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
+        return;
+    }
+    auto ret = sGnssCallback_2_1->gnssSvStatusCb_2_1(svInfoList);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+}
+
+void Gnss::reportLocation(const V1_0::GnssLocation& location) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sGnssCallback_1_1 != nullptr) {
+        auto ret = sGnssCallback_1_1->gnssLocationCb(location);
+        if (!ret.isOk()) {
+            ALOGE("%s: Unable to invoke callback v1.1", __func__);
+        }
+        return;
+    }
+    if (sGnssCallback_1_0 == nullptr) {
+        ALOGE("%s: No non-null callback", __func__);
+        return;
+    }
+    auto ret = sGnssCallback_1_0->gnssLocationCb(location);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback v1.0", __func__);
+    }
+}
+
+void Gnss::reportLocation(const V2_0::GnssLocation& location) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sGnssCallback_2_1 != nullptr) {
+        auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
+        if (!ret.isOk()) {
+            ALOGE("%s: Unable to invoke callback v2.1", __func__);
+        }
+        return;
+    }
+    if (sGnssCallback_2_0 == nullptr) {
+        ALOGE("%s: No non-null callback", __func__);
+        return;
+    }
+    auto ret = sGnssCallback_2_0->gnssLocationCb_2_0(location);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback v2.0", __func__);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h
new file mode 100644
index 0000000..bd5e6e8
--- /dev/null
+++ b/gnss/2.1/default/Gnss.h
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
+#include "GnssAntennaInfo.h"
+#include "GnssConfiguration.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+
+using GnssSvInfo = IGnssCallback::GnssSvInfo;
+
+namespace implementation {
+
+struct Gnss : public IGnss {
+    Gnss();
+    ~Gnss();
+    // Methods from V1_0::IGnss follow.
+    Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback) override;
+    Return<bool> start() override;
+    Return<bool> stop() override;
+    Return<void> cleanup() override;
+    Return<bool> injectTime(int64_t timeMs, int64_t timeReferenceMs,
+                            int32_t uncertaintyMs) override;
+    Return<bool> injectLocation(double latitudeDegrees, double longitudeDegrees,
+                                float accuracyMeters) override;
+    Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override;
+    Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+                                 V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                 uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+                                 uint32_t preferredTimeMs) override;
+    Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+    Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+    Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+    Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+    Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+    Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override;
+    Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override;
+    Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+    Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+    Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+    // Methods from V1_1::IGnss follow.
+    Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
+    Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+                                     V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                     uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+                                     uint32_t preferredTimeMs, bool lowPowerMode) override;
+    Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
+    Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
+    Return<bool> injectBestLocation(const V1_0::GnssLocation& location) override;
+
+    // Methods from V2_0::IGnss follow.
+    Return<bool> setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) override;
+    Return<sp<V2_0::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override;
+    Return<sp<V2_0::IGnssDebug>> getExtensionGnssDebug_2_0() override;
+    Return<sp<V2_0::IAGnss>> getExtensionAGnss_2_0() override;
+    Return<sp<V2_0::IAGnssRil>> getExtensionAGnssRil_2_0() override;
+    Return<sp<V2_0::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override;
+    Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
+    getExtensionMeasurementCorrections() override;
+    Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> getExtensionVisibilityControl()
+            override;
+    Return<sp<V2_0::IGnssBatching>> getExtensionGnssBatching_2_0() override;
+    Return<bool> injectBestLocation_2_0(const V2_0::GnssLocation& location) override;
+
+    // Methods from V2_1::IGnss follow.
+    Return<bool> setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) override;
+    Return<sp<V2_1::IGnssMeasurement>> getExtensionGnssMeasurement_2_1() override;
+    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;
+    void reportLocation(const V1_0::GnssLocation&) const;
+    void reportSvStatus(const hidl_vec<GnssSvInfo>&) const;
+
+    static sp<V2_1::IGnssCallback> sGnssCallback_2_1;
+    static sp<V2_0::IGnssCallback> sGnssCallback_2_0;
+    static sp<V1_1::IGnssCallback> sGnssCallback_1_1;
+    static sp<V1_0::IGnssCallback> sGnssCallback_1_0;
+    std::atomic<long> mMinIntervalMs;
+    sp<GnssConfiguration> mGnssConfiguration;
+    std::atomic<bool> mIsActive;
+    std::thread mThread;
+    mutable std::mutex mMutex;
+    hidl_vec<GnssSvInfo> filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList);
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gnss/2.1/default/GnssAntennaInfo.cpp b/gnss/2.1/default/GnssAntennaInfo.cpp
new file mode 100644
index 0000000..ed183a9
--- /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");
+    stop();
+    std::unique_lock<std::mutex> lock(mMutex);
+    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..94b2111
--- /dev/null
+++ b/gnss/2.1/default/GnssAntennaInfo.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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;
+
+    // Guarded by mMutex
+    static sp<IGnssAntennaInfoCallback> sCallback;
+
+    std::atomic<long> mMinIntervalMillis;
+    std::atomic<bool> mIsActive;
+    std::thread mThread;
+
+    // Synchronization lock for sCallback
+    mutable std::mutex mMutex;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
diff --git a/gnss/2.1/default/GnssConfiguration.cpp b/gnss/2.1/default/GnssConfiguration.cpp
new file mode 100644
index 0000000..cd8f07f
--- /dev/null
+++ b/gnss/2.1/default/GnssConfiguration.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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 "GnssConfiguration"
+
+#include "GnssConfiguration.h"
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setSuplEs(bool enable) {
+    ALOGD("setSuplEs enable: %d", enable);
+    // Method deprecated in 2.0 and not expected to be called by the framework.
+    return false;
+}
+
+Return<bool> GnssConfiguration::setSuplVersion(uint32_t) {
+    return true;
+}
+
+Return<bool> GnssConfiguration::setSuplMode(hidl_bitfield<SuplMode>) {
+    return true;
+}
+
+Return<bool> GnssConfiguration::setGpsLock(hidl_bitfield<GpsLock> gpsLock) {
+    ALOGD("setGpsLock gpsLock: %hhu", static_cast<GpsLock>(gpsLock));
+    // Method deprecated in 2.0 and not expected to be called by the framework.
+    return false;
+}
+
+Return<bool> GnssConfiguration::setLppProfile(hidl_bitfield<LppProfile>) {
+    return true;
+}
+
+Return<bool> GnssConfiguration::setGlonassPositioningProtocol(hidl_bitfield<GlonassPosProtocol>) {
+    return true;
+}
+
+Return<bool> GnssConfiguration::setEmergencySuplPdn(bool) {
+    return true;
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setBlacklist(
+        const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>&) {
+    // TODO (b/122463906): Reuse 1.1 implementation.
+    return bool{};
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setEsExtensionSec(uint32_t emergencyExtensionSeconds) {
+    ALOGD("setEsExtensionSec emergencyExtensionSeconds: %d", emergencyExtensionSeconds);
+    return true;
+}
+
+// Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setBlacklist_2_1(
+        const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& sourceList) {
+    std::unique_lock<std::recursive_mutex> lock(mMutex);
+    mBlacklistedConstellationSet.clear();
+    mBlacklistedSourceSet.clear();
+    for (auto source : sourceList) {
+        if (source.svid == 0) {
+            // Wildcard blacklist, i.e., blacklist entire constellation.
+            mBlacklistedConstellationSet.insert(source.constellation);
+        } else {
+            mBlacklistedSourceSet.insert(source);
+        }
+    }
+    return true;
+}
+
+Return<bool> GnssConfiguration::isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const {
+    std::unique_lock<std::recursive_mutex> lock(mMutex);
+    if (mBlacklistedConstellationSet.find(gnssSvInfo.v2_0.constellation) !=
+        mBlacklistedConstellationSet.end()) {
+        return true;
+    }
+    BlacklistedSourceV2_1 source = {.constellation = gnssSvInfo.v2_0.constellation,
+                                    .svid = gnssSvInfo.v2_0.v1_0.svid};
+    return (mBlacklistedSourceSet.find(source) != mBlacklistedSourceSet.end());
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/gnss/2.1/default/GnssConfiguration.h b/gnss/2.1/default/GnssConfiguration.h
new file mode 100644
index 0000000..662d61d
--- /dev/null
+++ b/gnss/2.1/default/GnssConfiguration.h
@@ -0,0 +1,101 @@
+/*
+ * 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_GNSS_V2_1_GNSSCONFIGURATION_H
+#define ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
+
+#include <android/hardware/gnss/2.1/IGnssCallback.h>
+#include <android/hardware/gnss/2.1/IGnssConfiguration.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <mutex>
+#include <unordered_set>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+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;
+
+using BlacklistedSourceV2_1 =
+        ::android::hardware::gnss::V2_1::IGnssConfiguration::BlacklistedSource;
+using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType;
+using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo;
+
+struct BlacklistedSourceHashV2_1 {
+    inline int operator()(const BlacklistedSourceV2_1& source) const {
+        return int(source.constellation) * 1000 + int(source.svid);
+    }
+};
+
+struct BlacklistedSourceEqualV2_1 {
+    inline bool operator()(const BlacklistedSourceV2_1& s1, const BlacklistedSourceV2_1& s2) const {
+        return (s1.constellation == s2.constellation) && (s1.svid == s2.svid);
+    }
+};
+
+using BlacklistedSourceSetV2_1 =
+        std::unordered_set<BlacklistedSourceV2_1, BlacklistedSourceHashV2_1,
+                           BlacklistedSourceEqualV2_1>;
+using BlacklistedConstellationSetV2_1 = std::unordered_set<GnssConstellationTypeV2_0>;
+
+struct GnssConfiguration : public IGnssConfiguration {
+    // Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+    Return<bool> setSuplEs(bool enabled) override;
+    Return<bool> setSuplVersion(uint32_t version) override;
+    Return<bool> setSuplMode(hidl_bitfield<SuplMode> mode) override;
+    Return<bool> setGpsLock(hidl_bitfield<GpsLock> lock) override;
+    Return<bool> setLppProfile(hidl_bitfield<LppProfile> lppProfile) override;
+    Return<bool> setGlonassPositioningProtocol(hidl_bitfield<GlonassPosProtocol> protocol) override;
+    Return<bool> setEmergencySuplPdn(bool enable) override;
+
+    // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+    Return<bool> setBlacklist(
+            const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;
+
+    std::recursive_mutex& getMutex() const;
+
+    // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+    Return<bool> setEsExtensionSec(uint32_t emergencyExtensionSeconds) override;
+
+    // Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
+    Return<bool> setBlacklist_2_1(
+            const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;
+
+    Return<bool> isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const;
+
+  private:
+    mutable std::recursive_mutex mMutex;
+
+    BlacklistedSourceSetV2_1 mBlacklistedSourceSet;
+    BlacklistedConstellationSetV2_1 mBlacklistedConstellationSet;
+};
+
+}  // 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/GnssDebug.cpp b/gnss/2.1/default/GnssDebug.cpp
new file mode 100644
index 0000000..a9f7ded
--- /dev/null
+++ b/gnss/2.1/default/GnssDebug.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "GnssDebug"
+
+#include <log/log.h>
+
+#include "Constants.h"
+#include "GnssDebug.h"
+
+using namespace ::android::hardware::gnss::common;
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+Return<void> GnssDebug::getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) {
+    PositionDebug positionDebug = {
+            .valid = true,
+            .latitudeDegrees = kMockLatitudeDegrees,
+            .longitudeDegrees = kMockLongitudeDegrees,
+            .altitudeMeters = kMockAltitudeMeters,
+            .speedMetersPerSec = kMockSpeedMetersPerSec,
+            .bearingDegrees = kMockBearingDegrees,
+            .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
+            .verticalAccuracyMeters = kMockVerticalAccuracyMeters,
+            .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
+            .bearingAccuracyDegrees = kMockBearingAccuracyDegrees,
+            .ageSeconds = 0.99};
+
+    TimeDebug timeDebug = {.timeEstimate = kMockTimestamp,
+                           .timeUncertaintyNs = 1000,
+                           .frequencyUncertaintyNsPerSec = 5.0e4};
+
+    DebugData data = {.position = positionDebug, .time = timeDebug};
+
+    _hidl_cb(data);
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gnss/2.1/default/GnssDebug.h b/gnss/2.1/default/GnssDebug.h
new file mode 100644
index 0000000..969d337
--- /dev/null
+++ b/gnss/2.1/default/GnssDebug.h
@@ -0,0 +1,51 @@
+/*
+ * 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_gnss_V1_1_GnssDebug_H_
+#define android_hardware_gnss_V1_1_GnssDebug_H_
+
+#include <android/hardware/gnss/1.0/IGnssDebug.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using V1_0::IGnssDebug;
+
+/* Interface for GNSS Debug support. */
+struct GnssDebug : public IGnssDebug {
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+     * These declarations were generated from IGnssDebug.hal.
+     */
+    Return<void> getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_gnss_V1_1_GnssDebug_H_
diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp
new file mode 100644
index 0000000..63bbc0a
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurement.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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 "GnssMeasurement"
+
+#include "GnssMeasurement.h"
+#include <log/log.h>
+#include "Utils.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+
+using common::Utils;
+
+namespace V2_1 {
+namespace implementation {
+
+sp<V2_1::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_1 = nullptr;
+sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_0 = nullptr;
+
+GnssMeasurement::GnssMeasurement() : mMinIntervalMillis(1000) {}
+
+GnssMeasurement::~GnssMeasurement() {
+    stop();
+}
+
+// Methods from V1_0::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
+        const sp<V1_0::IGnssMeasurementCallback>&) {
+    // TODO implement
+    return V1_0::IGnssMeasurement::GnssMeasurementStatus{};
+}
+
+Return<void> GnssMeasurement::close() {
+    ALOGD("close");
+    stop();
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback_2_1 = nullptr;
+    sCallback_2_0 = nullptr;
+    return Void();
+}
+
+// Methods from V1_1::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_1_1(
+        const sp<V1_1::IGnssMeasurementCallback>&, bool) {
+    // TODO implement
+    return V1_0::IGnssMeasurement::GnssMeasurementStatus{};
+}
+
+// Methods from V2_0::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0(
+        const sp<V2_0::IGnssMeasurementCallback>& callback, bool) {
+    ALOGD("setCallback_2_0");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback_2_0 = callback;
+
+    if (mIsActive) {
+        ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+        stop();
+    }
+    start();
+
+    return V1_0::IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
+}
+
+// Methods from V2_1::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_1(
+        const sp<V2_1::IGnssMeasurementCallback>& callback, bool) {
+    ALOGD("setCallback_2_1");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback_2_1 = callback;
+
+    if (mIsActive) {
+        ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+        stop();
+    }
+    start();
+
+    return V1_0::IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
+}
+
+void GnssMeasurement::start() {
+    ALOGD("start");
+    mIsActive = true;
+    mThread = std::thread([this]() {
+        while (mIsActive == true) {
+            if (sCallback_2_1 != nullptr) {
+                auto measurement = Utils::getMockMeasurementV2_1();
+                this->reportMeasurement(measurement);
+            } else {
+                auto measurement = Utils::getMockMeasurementV2_0();
+                this->reportMeasurement(measurement);
+            }
+
+            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
+        }
+    });
+}
+
+void GnssMeasurement::stop() {
+    ALOGD("stop");
+    mIsActive = false;
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void GnssMeasurement::reportMeasurement(const GnssDataV2_0& data) {
+    ALOGD("reportMeasurement()");
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sCallback_2_0 == nullptr) {
+        ALOGE("%s: GnssMeasurement::sCallback_2_0 is null.", __func__);
+        return;
+    }
+    auto ret = sCallback_2_0->gnssMeasurementCb_2_0(data);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+}
+
+void GnssMeasurement::reportMeasurement(const GnssDataV2_1& data) {
+    ALOGD("reportMeasurement()");
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sCallback_2_1 == nullptr) {
+        ALOGE("%s: GnssMeasurement::sCallback_2_1 is null.", __func__);
+        return;
+    }
+    auto ret = sCallback_2_1->gnssMeasurementCb_2_1(data);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/2.1/default/GnssMeasurement.h
new file mode 100644
index 0000000..d446419
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurement.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/2.1/IGnssMeasurement.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
+using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
+
+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 GnssMeasurement : public IGnssMeasurement {
+    GnssMeasurement();
+    ~GnssMeasurement();
+    // Methods from V1_0::IGnssMeasurement follow.
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback(
+            const sp<V1_0::IGnssMeasurementCallback>& callback) override;
+    Return<void> close() override;
+
+    // Methods from V1_1::IGnssMeasurement follow.
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_1_1(
+            const sp<V1_1::IGnssMeasurementCallback>& callback, bool enableFullTracking) override;
+
+    // Methods from V2_0::IGnssMeasurement follow.
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_2_0(
+            const sp<V2_0::IGnssMeasurementCallback>& callback, bool enableFullTracking) override;
+
+    // Methods from V2_1::IGnssMeasurement follow.
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_2_1(
+            const sp<V2_1::IGnssMeasurementCallback>& callback, bool enableFullTracking) override;
+
+  private:
+    void start();
+    void stop();
+    void reportMeasurement(const GnssDataV2_0&);
+    void reportMeasurement(const GnssDataV2_1&);
+
+    // Guarded by mMutex
+    static sp<V2_1::IGnssMeasurementCallback> sCallback_2_1;
+
+    // Guarded by mMutex
+    static sp<V2_0::IGnssMeasurementCallback> sCallback_2_0;
+
+    std::atomic<long> mMinIntervalMillis;
+    std::atomic<bool> mIsActive;
+    std::thread mThread;
+
+    // Synchronization lock for sCallback_2_1 and sCallback_2_0
+    mutable std::mutex mMutex;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/2.1/default/GnssMeasurementCorrections.cpp
new file mode 100644
index 0000000..accf62b
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurementCorrections.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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 "GnssMeasurementCorrections"
+
+#include "GnssMeasurementCorrections.h"
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_1 {
+namespace implementation {
+
+// Methods from V1_0::IMeasurementCorrections follow.
+Return<bool> GnssMeasurementCorrections::setCorrections(
+        const V1_0::MeasurementCorrections& corrections) {
+    ALOGD("setCorrections");
+    ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, "
+          "satCorrections.size: %d",
+          corrections.latitudeDegrees, corrections.longitudeDegrees, corrections.altitudeMeters,
+          corrections.horizontalPositionUncertaintyMeters,
+          corrections.verticalPositionUncertaintyMeters,
+          static_cast<unsigned long long>(corrections.toaGpsNanosecondsOfWeek),
+          static_cast<int>(corrections.satCorrections.size()));
+    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.constellation),
+              static_cast<int>(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz,
+              singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
+              singleSatCorrection.excessPathLengthUncertaintyMeters);
+        ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
+              singleSatCorrection.reflectingPlane.latitudeDegrees,
+              singleSatCorrection.reflectingPlane.longitudeDegrees,
+              singleSatCorrection.reflectingPlane.altitudeMeters,
+              singleSatCorrection.reflectingPlane.azimuthDegrees);
+    }
+
+    return true;
+}
+
+Return<bool> GnssMeasurementCorrections::setCallback(
+        const sp<V1_0::IMeasurementCorrectionsCallback>& callback) {
+    using Capabilities = V1_0::IMeasurementCorrectionsCallback::Capabilities;
+    auto ret =
+            callback->setCapabilitiesCb(Capabilities::LOS_SATS | Capabilities::EXCESS_PATH_LENGTH |
+                                        Capabilities::REFLECTING_PLANE);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+        return false;
+    }
+    return true;
+}
+
+// Methods from V1_1::IMeasurementCorrections follow.
+Return<bool> GnssMeasurementCorrections::setCorrections_1_1(
+        const V1_1::MeasurementCorrections& corrections) {
+    ALOGD("setCorrections_1_1");
+    ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu,"
+          "satCorrections.size: %d, hasEnvironmentBearing: %d, environmentBearingDeg: %f,"
+          "environmentBearingUncDeg: %f",
+          corrections.v1_0.latitudeDegrees, corrections.v1_0.longitudeDegrees,
+          corrections.v1_0.altitudeMeters, corrections.v1_0.horizontalPositionUncertaintyMeters,
+          corrections.v1_0.verticalPositionUncertaintyMeters,
+          static_cast<unsigned long long>(corrections.v1_0.toaGpsNanosecondsOfWeek),
+          static_cast<int>(corrections.v1_0.satCorrections.size()),
+          corrections.hasEnvironmentBearing, corrections.environmentBearingDegrees,
+          corrections.environmentBearingUncertaintyDegrees);
+    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.v1_0.singleSatCorrectionFlags),
+              static_cast<int>(singleSatCorrection.constellation),
+              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.v1_0.reflectingPlane.latitudeDegrees,
+              singleSatCorrection.v1_0.reflectingPlane.longitudeDegrees,
+              singleSatCorrection.v1_0.reflectingPlane.altitudeMeters,
+              singleSatCorrection.v1_0.reflectingPlane.azimuthDegrees);
+    }
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace measurement_corrections
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.h b/gnss/2.1/default/GnssMeasurementCorrections.h
new file mode 100644
index 0000000..036e855
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurementCorrections.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_1 {
+namespace implementation {
+
+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 GnssMeasurementCorrections : public IMeasurementCorrections {
+    // Methods from V1_0::IMeasurementCorrections follow.
+    Return<bool> setCorrections(const V1_0::MeasurementCorrections& corrections) override;
+    Return<bool> setCallback(const sp<V1_0::IMeasurementCorrectionsCallback>& callback) override;
+
+    // Methods from V1_1::IMeasurementCorrections follow.
+    Return<bool> setCorrections_1_1(const V1_1::MeasurementCorrections& corrections) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace measurement_corrections
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gnss/2.1/default/OWNERS b/gnss/2.1/default/OWNERS
new file mode 100644
index 0000000..b7b4a2e
--- /dev/null
+++ b/gnss/2.1/default/OWNERS
@@ -0,0 +1,4 @@
+gomo@google.com
+smalkos@google.com
+wyattriley@google.com
+yuhany@google.com
diff --git a/gnss/2.1/default/android.hardware.gnss@2.1-service.rc b/gnss/2.1/default/android.hardware.gnss@2.1-service.rc
new file mode 100644
index 0000000..5926c77
--- /dev/null
+++ b/gnss/2.1/default/android.hardware.gnss@2.1-service.rc
@@ -0,0 +1,4 @@
+service vendor.gnss-2-1 /vendor/bin/hw/android.hardware.gnss@2.1-service
+    class hal
+    user system
+    group system
diff --git a/gnss/2.1/default/android.hardware.gnss@2.1-service.xml b/gnss/2.1/default/android.hardware.gnss@2.1-service.xml
new file mode 100644
index 0000000..12a1fdf
--- /dev/null
+++ b/gnss/2.1/default/android.hardware.gnss@2.1-service.xml
@@ -0,0 +1,12 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.gnss</name>
+        <transport>hwbinder</transport>
+        <version>2.1</version>
+        <version>1.1</version>
+        <interface>
+            <name>IGnss</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/gnss/2.1/default/service.cpp b/gnss/2.1/default/service.cpp
new file mode 100644
index 0000000..5e004d5
--- /dev/null
+++ b/gnss/2.1/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 "android.hardware.gnss@2.1-service"
+
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include "Gnss.h"
+
+using ::android::OK;
+using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::gnss::V2_1::IGnss;
+using ::android::hardware::gnss::V2_1::implementation::Gnss;
+
+int main(int /* argc */, char* /* argv */[]) {
+    sp<IGnss> gnss = new Gnss();
+    configureRpcThreadpool(1, true /* will join */);
+    if (gnss->registerAsService() != OK) {
+        ALOGE("Could not register gnss 2.1 service.");
+        return 1;
+    }
+    joinRpcThreadpool();
+
+    ALOGE("Service exited!");
+    return 1;
+}
\ No newline at end of file
diff --git a/gnss/2.1/types.hal b/gnss/2.1/types.hal
new file mode 100644
index 0000000..e4484c1
--- /dev/null
+++ b/gnss/2.1/types.hal
@@ -0,0 +1,46 @@
+/*
+ * 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.gnss@2.1;
+
+import @2.0::GnssConstellationType;
+
+/**
+ * Represents a GNSS signal type.
+ */
+struct GnssSignalType {
+    /**
+     * Constellation type of the SV that transmits the signal.
+     */
+    GnssConstellationType constellation;
+
+    /**
+     * Carrier frequency in Hz of the signal.
+     */
+    double carrierFrequencyHz;
+
+    /**
+     * The type of code of the GNSS signal.
+     *
+     * This is used to specify the observation descriptor defined in GNSS Observation Data File
+     * Header Section Description in the RINEX standard (Version 3.XX). In RINEX Version 3.03,
+     * in Appendix Table A2 Attributes are listed as uppercase letters (for instance, "A" for
+     * "A channel").
+     *
+     * See the comment of @2.0::IGnssMeasurementCallback.GnssMeasurement.codeType for more details.
+     */
+    string codeType;
+};
diff --git a/gnss/2.1/vts/OWNERS b/gnss/2.1/vts/OWNERS
new file mode 100644
index 0000000..b7b4a2e
--- /dev/null
+++ b/gnss/2.1/vts/OWNERS
@@ -0,0 +1,4 @@
+gomo@google.com
+smalkos@google.com
+wyattriley@google.com
+yuhany@google.com
diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..f008a26
--- /dev/null
+++ b/gnss/2.1/vts/functional/Android.bp
@@ -0,0 +1,39 @@
+//
+// 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: "VtsHalGnssV2_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "gnss_hal_test.cpp",
+        "gnss_hal_test_cases.cpp",
+        "VtsHalGnssV2_1TargetTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss.measurement_corrections@1.1",
+        "android.hardware.gnss.visibility_control@1.0",
+        "android.hardware.gnss@1.0",
+        "android.hardware.gnss@1.1",
+        "android.hardware.gnss@2.0",
+        "android.hardware.gnss@2.1",
+        "android.hardware.gnss@common-vts-lib",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp b/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp
new file mode 100644
index 0000000..e61d885
--- /dev/null
+++ b/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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 "VtsHalGnssV2_1TargetTest"
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "gnss_hal_test.h"
+
+using android::hardware::gnss::V2_1::IGnss;
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GnssHalTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp
new file mode 100644
index 0000000..da7a62b
--- /dev/null
+++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp
@@ -0,0 +1,278 @@
+/*
+ * 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 "GnssHalTest"
+
+#include <gnss_hal_test.h>
+#include <chrono>
+#include "Utils.h"
+
+#include <gtest/gtest.h>
+
+using ::android::hardware::gnss::common::Utils;
+
+// Implementations for the main test class for GNSS HAL
+void GnssHalTest::SetUp() {
+    gnss_hal_ = IGnss::getService(GetParam());
+    ASSERT_NE(gnss_hal_, nullptr);
+
+    SetUpGnssCallback();
+}
+
+void GnssHalTest::TearDown() {
+    if (gnss_hal_ != nullptr) {
+        gnss_hal_->cleanup();
+        gnss_hal_ = nullptr;
+    }
+
+    // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
+    gnss_cb_ = nullptr;
+}
+
+void GnssHalTest::SetUpGnssCallback() {
+    gnss_cb_ = new GnssCallback();
+    ASSERT_NE(gnss_cb_, nullptr);
+
+    auto result = gnss_hal_->setCallback_2_1(gnss_cb_);
+    if (!result.isOk()) {
+        ALOGE("result of failed setCallback %s", result.description().c_str());
+    }
+
+    ASSERT_TRUE(result.isOk());
+    ASSERT_TRUE(result);
+
+    /*
+     * All capabilities, name and systemInfo callbacks should trigger
+     */
+    EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC));
+    EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC));
+    EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC));
+
+    EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1);
+    EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1);
+    EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1);
+}
+
+void GnssHalTest::StopAndClearLocations() {
+    const auto result = gnss_hal_->stop();
+
+    EXPECT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    /*
+     * Clear notify/waiting counter, allowing up till the timeout after
+     * the last reply for final startup messages to arrive (esp. system
+     * info.)
+     */
+    while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) {
+    }
+    gnss_cb_->location_cbq_.reset();
+}
+
+void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
+    const int kPreferredAccuracy = 0;  // Ideally perfect (matches GnssLocationProvider)
+    const int kPreferredTimeMsec = 0;  // Ideally immediate
+
+    const auto result = gnss_hal_->setPositionMode_1_1(
+            IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
+            min_interval_msec, kPreferredAccuracy, kPreferredTimeMsec, low_power_mode);
+
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+bool GnssHalTest::StartAndCheckFirstLocation() {
+    const auto result = gnss_hal_->start();
+
+    EXPECT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    /*
+     * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
+     * so allow time to demodulate ephemeris over the air.
+     */
+    const int kFirstGnssLocationTimeoutSeconds = 75;
+
+    EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+                                                 kFirstGnssLocationTimeoutSeconds));
+    int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+    EXPECT_EQ(locationCalledCount, 1);
+
+    if (locationCalledCount > 0) {
+        // don't require speed on first fix
+        CheckLocation(gnss_cb_->last_location_, false);
+        return true;
+    }
+    return false;
+}
+
+void GnssHalTest::CheckLocation(const GnssLocation_2_0& location, bool check_speed) {
+    const bool check_more_accuracies =
+            (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017);
+
+    Utils::checkLocation(location.v1_0, check_speed, check_more_accuracies);
+}
+
+void GnssHalTest::StartAndCheckLocations(int count) {
+    const int kMinIntervalMsec = 500;
+    const int kLocationTimeoutSubsequentSec = 2;
+    const bool kLowPowerMode = false;
+
+    SetPositionMode(kMinIntervalMsec, kLowPowerMode);
+
+    EXPECT_TRUE(StartAndCheckFirstLocation());
+
+    for (int i = 1; i < count; i++) {
+        EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+                                                     kLocationTimeoutSubsequentSec));
+        int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+        EXPECT_EQ(locationCalledCount, i + 1);
+        // Don't cause confusion by checking details if no location yet
+        if (locationCalledCount > 0) {
+            // Should be more than 1 location by now, but if not, still don't check first fix speed
+            CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1);
+        }
+    }
+}
+
+GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
+        const int locations_to_await, const int gnss_sv_info_list_timeout) {
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(locations_to_await);
+    const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, locations_to_await);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, locations_to_await, location_called_count);
+
+    // Find first non-GPS constellation to blacklist
+    GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, gnss_sv_info_list_timeout);
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
+                (gnss_sv.v2_0.constellation != GnssConstellationType::UNKNOWN) &&
+                (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
+                // found a non-GPS constellation
+                constellation_to_blacklist = gnss_sv.v2_0.constellation;
+                break;
+            }
+        }
+        if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
+            break;
+        }
+    }
+
+    if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
+        ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+        // Proceed functionally to blacklist something.
+        constellation_to_blacklist = GnssConstellationType::GLONASS;
+    }
+
+    return constellation_to_blacklist;
+}
+
+GnssHalTest::GnssCallback::GnssCallback()
+    : info_cbq_("system_info"),
+      name_cbq_("name"),
+      capabilities_cbq_("capabilities"),
+      location_cbq_("location"),
+      sv_info_list_cbq_("sv_info") {}
+
+Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
+        const IGnssCallback_1_0::GnssSystemInfo& info) {
+    ALOGI("Info received, year %d", info.yearOfHw);
+    info_cbq_.store(info);
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
+    ALOGI("Capabilities received %d", capabilities);
+    capabilities_cbq_.store(capabilities);
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
+    ALOGI("Capabilities (v2.0) received %d", capabilities);
+    capabilities_cbq_.store(capabilities);
+    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);
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation_1_0& location) {
+    ALOGI("Location received");
+    GnssLocation_2_0 location_v2_0;
+    location_v2_0.v1_0 = location;
+    return gnssLocationCbImpl(location_v2_0);
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssLocationCb_2_0(const GnssLocation_2_0& location) {
+    ALOGI("Location (v2.0) received");
+    return gnssLocationCbImpl(location);
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssLocationCbImpl(const GnssLocation_2_0& location) {
+    location_cbq_.store(location);
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus&) {
+    ALOGI("gnssSvStatusCb");
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb_2_1(
+        const hidl_vec<IGnssCallback_2_1::GnssSvInfo>& svInfoList) {
+    ALOGI("gnssSvStatusCb_2_1. Size = %d", (int)svInfoList.size());
+    sv_info_list_cbq_.store(svInfoList);
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_1(
+        const IGnssMeasurementCallback_2_1::GnssData& data) {
+    ALOGD("GnssMeasurement v2.1 received. Size = %d", (int)data.measurements.size());
+    measurement_cbq_.store(data);
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb(
+        uint32_t capabilities) {
+    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
new file mode 100644
index 0000000..9e6e162
--- /dev/null
+++ b/gnss/2.1/vts/functional/gnss_hal_test.h
@@ -0,0 +1,234 @@
+/*
+ * 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 GNSS_HAL_TEST_H_
+#define GNSS_HAL_TEST_H_
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include "GnssCallbackEventQueue.h"
+
+#include <gtest/gtest.h>
+
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+
+using android::hardware::gnss::common::GnssCallbackEventQueue;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+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;
+
+using IGnssCallback_1_0 = android::hardware::gnss::V1_0::IGnssCallback;
+using IGnssCallback_2_0 = android::hardware::gnss::V2_0::IGnssCallback;
+using IGnssCallback_2_1 = android::hardware::gnss::V2_1::IGnssCallback;
+
+using IGnssMeasurementCallback_1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_2_1 = android::hardware::gnss::V2_1::IGnssMeasurementCallback;
+
+using android::sp;
+
+#define TIMEOUT_SEC 2  // for basic commands/responses
+
+// The main test class for GNSS HAL.
+class GnssHalTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override;
+
+    virtual void TearDown() override;
+
+    /* Callback class for data & Event. */
+    class GnssCallback : public IGnssCallback_2_1 {
+      public:
+        IGnssCallback_1_0::GnssSystemInfo last_info_;
+        android::hardware::hidl_string last_name_;
+        uint32_t last_capabilities_;
+        GnssLocation_2_0 last_location_;
+
+        GnssCallbackEventQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
+        GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
+        GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+        GnssCallbackEventQueue<GnssLocation_2_0> location_cbq_;
+        GnssCallbackEventQueue<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list_cbq_;
+
+        GnssCallback();
+        virtual ~GnssCallback() = default;
+
+        // Dummy callback handlers
+        Return<void> gnssStatusCb(const IGnssCallback_1_0::GnssStatusValue /* status */) override {
+            return Void();
+        }
+        Return<void> gnssNmeaCb(int64_t /* timestamp */,
+                                const android::hardware::hidl_string& /* nmea */) override {
+            return Void();
+        }
+        Return<void> gnssAcquireWakelockCb() override { return Void(); }
+        Return<void> gnssReleaseWakelockCb() override { return Void(); }
+        Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
+            return Void();
+        }
+        Return<void> gnssRequestTimeCb() override { return Void(); }
+        // Actual (test) callback handlers
+        Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+        Return<void> gnssLocationCb(const GnssLocation_1_0& location) override;
+        Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+        Return<void> gnssSetSystemInfoCb(const IGnssCallback_1_0::GnssSystemInfo& info) override;
+        Return<void> gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus& svStatus) override;
+
+        // New in v2.0
+        Return<void> gnssLocationCb_2_0(const GnssLocation_2_0& location) override;
+        Return<void> gnssRequestLocationCb_2_0(bool /* independentFromGnss */,
+                                               bool /* isUserEmergency */) override {
+            return Void();
+        }
+        Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
+        Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_2_0::GnssSvInfo>&) override {
+            return Void();
+        }
+
+        // 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);
+    };
+
+    /* Callback class for GnssMeasurement. */
+    class GnssMeasurementCallback : public IGnssMeasurementCallback_2_1 {
+      public:
+        GnssCallbackEventQueue<IGnssMeasurementCallback_2_1::GnssData> measurement_cbq_;
+
+        GnssMeasurementCallback() : measurement_cbq_("measurement"){};
+        virtual ~GnssMeasurementCallback() = default;
+
+        // Methods from V1_0::IGnssMeasurementCallback follow.
+        Return<void> GnssMeasurementCb(const IGnssMeasurementCallback_1_0::GnssData&) override {
+            return Void();
+        }
+
+        // Methods from V1_1::IGnssMeasurementCallback follow.
+        Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override {
+            return Void();
+        }
+
+        // Methods from V2_0::IGnssMeasurementCallback follow.
+        Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override {
+            return Void();
+        }
+
+        // Methods from V2_1::IGnssMeasurementCallback follow.
+        Return<void> gnssMeasurementCb_2_1(const IGnssMeasurementCallback_2_1::GnssData&) override;
+    };
+
+    /* Callback class for GnssMeasurementCorrections. */
+    class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
+      public:
+        uint32_t last_capabilities_;
+        GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+
+        GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
+        virtual ~GnssMeasurementCorrectionsCallback() = default;
+
+        // Methods from V1_0::IMeasurementCorrectionsCallback follow.
+        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.
+     */
+    void SetUpGnssCallback();
+
+    /*
+     * StartAndCheckFirstLocation:
+     *   Helper function to start location, and check the first one.
+     *
+     *   <p> Note this leaves the Location request active, to enable Stop call vs. other call
+     *   reordering tests.
+     *
+     * returns  true if a location was successfully generated
+     */
+    bool StartAndCheckFirstLocation();
+
+    /*
+     * CheckLocation:
+     *   Helper function to vet Location fields
+     *
+     *   check_speed: true if speed related fields are also verified.
+     */
+    void CheckLocation(const GnssLocation_2_0& location, const bool check_speed);
+
+    /*
+     * StartAndCheckLocations:
+     *   Helper function to collect, and check a number of
+     *   normal ~1Hz locations.
+     *
+     *   Note this leaves the Location request active, to enable Stop call vs. other call
+     *   reordering tests.
+     */
+    void StartAndCheckLocations(int count);
+
+    /*
+     * StopAndClearLocations:
+     * Helper function to stop locations, and clear any remaining notifications
+     */
+    void StopAndClearLocations();
+
+    /*
+     * SetPositionMode:
+     * Helper function to set positioning mode and verify output
+     */
+    void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
+
+    /*
+     * startLocationAndGetNonGpsConstellation:
+     * 1. Start location
+     * 2. Find and return first non-GPS constellation
+     *
+     * Note that location is not stopped in this method. The client should call
+     * StopAndClearLocations() after the call.
+     */
+    GnssConstellationType startLocationAndGetNonGpsConstellation(
+            const int locations_to_await, const int gnss_sv_info_list_timeout);
+
+    sp<IGnss> gnss_hal_;        // GNSS HAL to call into
+    sp<GnssCallback> gnss_cb_;  // Primary callback interface
+};
+
+#endif  // GNSS_HAL_TEST_H_
diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
new file mode 100644
index 0000000..a3d2956
--- /dev/null
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -0,0 +1,678 @@
+/*
+ * 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 "GnssHalTestCases"
+
+#include <gnss_hal_test.h>
+#include <cmath>
+#include "Utils.h"
+
+#include <gtest/gtest.h>
+
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+
+using android::hardware::gnss::common::Utils;
+
+using IGnssMeasurement_2_1 = android::hardware::gnss::V2_1::IGnssMeasurement;
+using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
+using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
+using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
+
+using IGnssConfiguration_2_1 = android::hardware::gnss::V2_1::IGnssConfiguration;
+using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
+using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
+using IGnssConfiguration_1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
+
+using android::hardware::gnss::V2_0::GnssConstellationType;
+using android::hardware::gnss::V2_1::IGnssConfiguration;
+
+using GnssMeasurementFlags = IGnssMeasurementCallback_2_1::GnssMeasurementFlags;
+using IMeasurementCorrections_1_1 =
+        android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections;
+
+/*
+ * SetupTeardownCreateCleanup:
+ * Requests the gnss HAL then calls cleanup
+ *
+ * Empty test fixture to verify basic Setup & Teardown
+ */
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
+
+/*
+ * TestGnssMeasurementExtension:
+ * Gets the GnssMeasurementExtension and verifies that it returns an actual extension.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementExtension) {
+    auto gnssMeasurement_2_1 = gnss_hal_->getExtensionGnssMeasurement_2_1();
+    auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0();
+    auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
+    auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
+    ASSERT_TRUE(gnssMeasurement_2_1.isOk() && gnssMeasurement_2_0.isOk() &&
+                gnssMeasurement_1_1.isOk() && gnssMeasurement_1_0.isOk());
+    sp<IGnssMeasurement_2_1> iGnssMeas_2_1 = gnssMeasurement_2_1;
+    sp<IGnssMeasurement_2_0> iGnssMeas_2_0 = gnssMeasurement_2_0;
+    sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
+    sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
+    // At least one interface is non-null.
+    int numNonNull = (int)(iGnssMeas_2_1 != nullptr) + (int)(iGnssMeas_2_0 != nullptr) +
+                     (int)(iGnssMeas_1_1 != nullptr) + (int)(iGnssMeas_1_0 != nullptr);
+    ASSERT_TRUE(numNonNull >= 1);
+}
+
+/*
+ * TestGnssConfigurationExtension:
+ * Gets the GnssConfigurationExtension and verifies that it returns an actual extension.
+ */
+TEST_P(GnssHalTest, TestGnssConfigurationExtension) {
+    auto gnssConfiguration_2_1 = gnss_hal_->getExtensionGnssConfiguration_2_1();
+    auto gnssConfiguration_2_0 = gnss_hal_->getExtensionGnssConfiguration_2_0();
+    auto gnssConfiguration_1_1 = gnss_hal_->getExtensionGnssConfiguration_1_1();
+    auto gnssConfiguration_1_0 = gnss_hal_->getExtensionGnssConfiguration();
+    ASSERT_TRUE(gnssConfiguration_2_1.isOk() && gnssConfiguration_2_0.isOk() &&
+                gnssConfiguration_1_1.isOk() && gnssConfiguration_1_0.isOk());
+    sp<IGnssConfiguration_2_1> iGnssConfig_2_1 = gnssConfiguration_2_1;
+    sp<IGnssConfiguration_2_0> iGnssConfig_2_0 = gnssConfiguration_2_0;
+    sp<IGnssConfiguration_1_1> iGnssConfig_1_1 = gnssConfiguration_1_1;
+    sp<IGnssConfiguration_1_0> iGnssConfig_1_0 = gnssConfiguration_1_0;
+    // At least one interface is non-null.
+    int numNonNull = (int)(iGnssConfig_2_1 != nullptr) + (int)(iGnssConfig_2_0 != nullptr) +
+                     (int)(iGnssConfig_1_1 != nullptr) + (int)(iGnssConfig_1_0 != nullptr);
+    ASSERT_TRUE(numNonNull >= 1);
+}
+
+/*
+ * TestGnssMeasurementFields:
+ * Sets a GnssMeasurementCallback, waits for a measurement, and verifies
+ * 1. basebandCN0DbHz is valid
+ * 2. ISB fields are valid
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementFields) {
+    const int kFirstGnssMeasurementTimeoutSeconds = 10;
+
+    auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_1();
+    ASSERT_TRUE(gnssMeasurement.isOk());
+
+    // Skip test if GnssMeasurement v2.1 is not supported
+    sp<IGnssMeasurement_2_1> iGnssMeasurement = gnssMeasurement;
+    if (iGnssMeasurement == nullptr) {
+        return;
+    }
+
+    sp<GnssMeasurementCallback> callback = new GnssMeasurementCallback();
+    auto result = iGnssMeasurement->setCallback_2_1(callback, /* enableFullTracking= */ true);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_EQ(result, IGnssMeasurement_1_0::GnssMeasurementStatus::SUCCESS);
+
+    IGnssMeasurementCallback_2_1::GnssData lastMeasurement;
+    ASSERT_TRUE(callback->measurement_cbq_.retrieve(lastMeasurement,
+                                                    kFirstGnssMeasurementTimeoutSeconds));
+    EXPECT_EQ(callback->measurement_cbq_.calledCount(), 1);
+    ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
+    for (auto measurement : lastMeasurement.measurements) {
+        // Verify basebandCn0DbHz is valid.
+        ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
+
+        if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_FULL_ISB) > 0) &&
+            ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
+            ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) > 0) &&
+            ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY) >
+             0)) {
+            GnssConstellationType referenceConstellation =
+                    lastMeasurement.clock.referenceSignalTypeForIsb.constellation;
+            double carrierFrequencyHz =
+                    lastMeasurement.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
+            std::string codeType = lastMeasurement.clock.referenceSignalTypeForIsb.codeType;
+
+            ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
+                        referenceConstellation <= GnssConstellationType::IRNSS);
+            ASSERT_TRUE(carrierFrequencyHz > 0);
+            ASSERT_TRUE(codeType != "");
+
+            ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
+            ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
+            ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
+            ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
+        }
+    }
+
+    iGnssMeasurement->close();
+}
+
+/*
+ * 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.
+ */
+TEST_P(GnssHalTest, TestGnssSvInfoFields) {
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckFirstLocation();
+    int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size, 0);
+    ALOGD("Observed %d GnssSvStatus, while awaiting one location (%d received)",
+          sv_info_list_cbq_size, location_called_count);
+
+    // Get the last sv_info_list
+    std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_vec_list;
+    gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size, 1);
+    hidl_vec<IGnssCallback_2_1::GnssSvInfo> last_sv_info_list = sv_info_vec_list.back();
+
+    bool nonZeroCn0Found = false;
+    for (auto sv_info : last_sv_info_list) {
+        ASSERT_TRUE(sv_info.basebandCN0DbHz >= 0.0 && sv_info.basebandCN0DbHz <= 65.0);
+        if (sv_info.basebandCN0DbHz > 0.0) {
+            nonZeroCn0Found = true;
+        }
+    }
+    // Assert at least one value is non-zero. Zero is ok in status as it's possibly
+    // reporting a searched but not found satellite.
+    ASSERT_TRUE(nonZeroCn0Found);
+    StopAndClearLocations();
+}
+
+/*
+ * FindStrongFrequentNonGpsSource:
+ *
+ * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
+ *
+ * returns the strongest source,
+ *         or a source with constellation == UNKNOWN if none are found sufficient times
+ * TODO(skz): create a template for this to reduce code duplication of v2.1 and v2.0 since both
+ * are using vectors.
+ */
+IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
+        const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list,
+        const int min_observations) {
+    struct ComparableBlacklistedSource {
+        IGnssConfiguration::BlacklistedSource id;
+
+        ComparableBlacklistedSource() {
+            id.constellation = GnssConstellationType::UNKNOWN;
+            id.svid = 0;
+        }
+
+        bool operator<(const ComparableBlacklistedSource& compare) const {
+            return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
+                                                    (id.constellation < compare.id.constellation)));
+        }
+    };
+
+    struct SignalCounts {
+        int observations;
+        float max_cn0_dbhz;
+    };
+
+    std::map<ComparableBlacklistedSource, SignalCounts> mapSignals;
+
+    for (const auto& sv_info_vec : sv_info_list) {
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
+                (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
+                ComparableBlacklistedSource source;
+                source.id.svid = gnss_sv.v2_0.v1_0.svid;
+                source.id.constellation = gnss_sv.v2_0.constellation;
+
+                const auto& itSignal = mapSignals.find(source);
+                if (itSignal == mapSignals.end()) {
+                    SignalCounts counts;
+                    counts.observations = 1;
+                    counts.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
+                    mapSignals.insert(
+                            std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
+                } else {
+                    itSignal->second.observations++;
+                    if (itSignal->second.max_cn0_dbhz < gnss_sv.v2_0.v1_0.cN0Dbhz) {
+                        itSignal->second.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
+                    }
+                }
+            }
+        }
+    }
+
+    float max_cn0_dbhz_with_sufficient_count = 0.;
+    int total_observation_count = 0;
+    int blacklisted_source_count_observation = 0;
+
+    ComparableBlacklistedSource source_to_blacklist;  // initializes to zero = UNKNOWN constellation
+    for (auto const& pairSignal : mapSignals) {
+        total_observation_count += pairSignal.second.observations;
+        if ((pairSignal.second.observations >= min_observations) &&
+            (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
+            source_to_blacklist = pairSignal.first;
+            blacklisted_source_count_observation = pairSignal.second.observations;
+            max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
+        }
+    }
+    ALOGD("Among %d observations, chose svid %d, constellation %d, "
+          "with %d observations at %.1f max CNo",
+          total_observation_count, source_to_blacklist.id.svid,
+          (int)source_to_blacklist.id.constellation, blacklisted_source_count_observation,
+          max_cn0_dbhz_with_sufficient_count);
+
+    return source_to_blacklist.id;
+}
+
+/*
+ * BlacklistIndividualSatellites:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for common satellites (strongest and one other.)
+ * 2a & b) Turns off location, and blacklists common satellites.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use those satellites.
+ * 4a & b) Turns off location, and send in empty blacklist.
+ * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does re-use at least the previously strongest satellite
+ * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
+ * formerly strongest satellite
+ */
+TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
+    const int kLocationsToAwait = 3;
+    const int kRetriesToUnBlacklist = 10;
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+    int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+
+    /*
+     * Identify strongest SV seen at least kLocationsToAwait -1 times
+     * Why -1?  To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
+     * observability (one epoch RF null)
+     */
+
+    const int kGnssSvInfoListTimeout = 2;
+    std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_vec_list;
+    int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size,
+                                                     kGnssSvInfoListTimeout);
+
+    ASSERT_EQ(count, sv_info_list_cbq_size);
+
+    IGnssConfiguration::BlacklistedSource source_to_blacklist =
+            FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
+
+    if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) {
+        // Cannot find a non-GPS satellite. Let the test pass.
+        ALOGD("Cannot find a non-GPS satellite. Letting the test pass.");
+        return;
+    }
+
+    // Stop locations, blacklist the common SV
+    StopAndClearLocations();
+
+    auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_1();
+    ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+    sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
+    sources.resize(1);
+    sources[0] = source_to_blacklist;
+
+    auto result = gnss_configuration_hal->setBlacklist_2_1(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    // retry and ensure satellite not used
+    gnss_cb_->sv_info_list_cbq_.reset();
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // early exit if test is being run with insufficient signal
+    location_called_count = gnss_cb_->location_cbq_.calledCount();
+    if (location_called_count == 0) {
+        ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+    }
+    ASSERT_TRUE(location_called_count > 0);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            EXPECT_FALSE((gnss_sv.v2_0.v1_0.svid == source_to_blacklist.svid) &&
+                         (gnss_sv.v2_0.constellation == source_to_blacklist.constellation) &&
+                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clear blacklist and restart - this time updating the blacklist while location is still on
+    sources.resize(0);
+
+    result = gnss_configuration_hal->setBlacklist_2_1(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    bool strongest_sv_is_reobserved = false;
+    // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
+    int unblacklist_loops_remaining = kRetriesToUnBlacklist;
+    while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
+        StopAndClearLocations();
+        gnss_cb_->sv_info_list_cbq_.reset();
+
+        gnss_cb_->location_cbq_.reset();
+        StartAndCheckLocations(kLocationsToAwait);
+
+        // early exit loop if test is being run with insufficient signal
+        location_called_count = gnss_cb_->location_cbq_.calledCount();
+        if (location_called_count == 0) {
+            ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+        }
+        ASSERT_TRUE(location_called_count > 0);
+
+        // Tolerate 1 less sv status to handle edge cases in reporting.
+        sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+        EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+        ALOGD("Clear blacklist, observed %d GnssSvInfo, while awaiting %d Locations"
+              ", tries remaining %d",
+              sv_info_list_cbq_size, kLocationsToAwait, unblacklist_loops_remaining);
+
+        for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+            hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+            gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+            for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+                const auto& gnss_sv = sv_info_vec[iSv];
+                if ((gnss_sv.v2_0.v1_0.svid == source_to_blacklist.svid) &&
+                    (gnss_sv.v2_0.constellation == source_to_blacklist.constellation) &&
+                    (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)) {
+                    strongest_sv_is_reobserved = true;
+                    break;
+                }
+            }
+            if (strongest_sv_is_reobserved) break;
+        }
+    }
+    EXPECT_TRUE(strongest_sv_is_reobserved);
+    StopAndClearLocations();
+}
+
+/*
+ * BlacklistConstellationLocationOff:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Turns off location, and blacklist first non-GPS constellations.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use any constellation but GPS.
+ * 4a & b) Clean up by turning off location, and send in empty blacklist.
+ */
+TEST_P(GnssHalTest, BlacklistConstellationLocationOff) {
+    const int kLocationsToAwait = 3;
+    const int kGnssSvInfoListTimeout = 2;
+
+    // Find first non-GPS constellation to blacklist
+    GnssConstellationType constellation_to_blacklist =
+            startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout);
+
+    // Turns off location
+    StopAndClearLocations();
+
+    IGnssConfiguration::BlacklistedSource source_to_blacklist_1;
+    source_to_blacklist_1.constellation = constellation_to_blacklist;
+    source_to_blacklist_1.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    // IRNSS was added in 2.0. Always attempt to blacklist IRNSS to verify that the new enum is
+    // supported.
+    IGnssConfiguration::BlacklistedSource source_to_blacklist_2;
+    source_to_blacklist_2.constellation = GnssConstellationType::IRNSS;
+    source_to_blacklist_2.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_1();
+    ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+    sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
+    sources.resize(2);
+    sources[0] = source_to_blacklist_1;
+    sources[1] = source_to_blacklist_2;
+
+    auto result = gnss_configuration_hal->setBlacklist_2_1(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    // retry and ensure constellation not used
+    gnss_cb_->sv_info_list_cbq_.reset();
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
+          kLocationsToAwait);
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_1.constellation) &&
+                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+            EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_2.constellation) &&
+                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clean up
+    StopAndClearLocations();
+    sources.resize(0);
+    result = gnss_configuration_hal->setBlacklist_2_1(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+/*
+ * BlacklistConstellationLocationOn:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Blacklist first non-GPS constellation, and turn off location.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use any constellation but GPS.
+ * 4a & b) Clean up by turning off location, and send in empty blacklist.
+ */
+TEST_P(GnssHalTest, BlacklistConstellationLocationOn) {
+    const int kLocationsToAwait = 3;
+    const int kGnssSvInfoListTimeout = 2;
+
+    // Find first non-GPS constellation to blacklist
+    GnssConstellationType constellation_to_blacklist =
+            startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout);
+
+    IGnssConfiguration::BlacklistedSource source_to_blacklist_1;
+    source_to_blacklist_1.constellation = constellation_to_blacklist;
+    source_to_blacklist_1.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    // IRNSS was added in 2.0. Always attempt to blacklist IRNSS to verify that the new enum is
+    // supported.
+    IGnssConfiguration::BlacklistedSource source_to_blacklist_2;
+    source_to_blacklist_2.constellation = GnssConstellationType::IRNSS;
+    source_to_blacklist_2.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_1();
+    ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+    sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
+    sources.resize(2);
+    sources[0] = source_to_blacklist_1;
+    sources[1] = source_to_blacklist_2;
+
+    auto result = gnss_configuration_hal->setBlacklist_2_1(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    // Turns off location
+    StopAndClearLocations();
+
+    // retry and ensure constellation not used
+    gnss_cb_->sv_info_list_cbq_.reset();
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
+          kLocationsToAwait);
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_1.constellation) &&
+                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+            EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_2.constellation) &&
+                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clean up
+    StopAndClearLocations();
+    sources.resize(0);
+    result = gnss_configuration_hal->setBlacklist_2_1(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+/*
+ * TestGnssMeasurementCorrections:
+ * If measurement corrections capability is supported, verifies that it supports the
+ * gnss.measurement_corrections@1.1::IMeasurementCorrections interface by invoking a method.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementCorrections) {
+    if (!(gnss_cb_->last_capabilities_ &
+          IGnssCallback_2_1::Capabilities::MEASUREMENT_CORRECTIONS)) {
+        return;
+    }
+
+    // Verify IMeasurementCorrections is supported.
+    auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections_1_1();
+    ASSERT_TRUE(measurementCorrections.isOk());
+    sp<IMeasurementCorrections_1_1> iMeasurementCorrections = measurementCorrections;
+    ASSERT_NE(iMeasurementCorrections, nullptr);
+
+    sp<GnssMeasurementCorrectionsCallback> callback = new GnssMeasurementCorrectionsCallback();
+    iMeasurementCorrections->setCallback(callback);
+
+    const int kMeasurementCorrectionsCapabilitiesTimeoutSeconds = 5;
+    callback->capabilities_cbq_.retrieve(callback->last_capabilities_,
+                                         kMeasurementCorrectionsCapabilitiesTimeoutSeconds);
+    ASSERT_TRUE(callback->capabilities_cbq_.calledCount() > 0);
+
+    // Set a mock MeasurementCorrections.
+    auto result =
+            iMeasurementCorrections->setCorrections_1_1(Utils::getMockMeasurementCorrections_1_1());
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp
index 4ea97fa..577f6ae 100644
--- a/gnss/common/utils/default/Android.bp
+++ b/gnss/common/utils/default/Android.bp
@@ -28,6 +28,10 @@
     ],
     export_include_dirs: ["include"],
     shared_libs: [
+        "libhidlbase",
+        "libutils",
         "android.hardware.gnss@1.0",
+        "android.hardware.gnss@2.0",
+        "android.hardware.gnss@2.1",
     ],
 }
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index b9a06e8..386090e 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -16,6 +16,7 @@
 
 #include <Constants.h>
 #include <Utils.h>
+#include <utils/SystemClock.h>
 
 namespace android {
 namespace hardware {
@@ -23,34 +24,269 @@
 namespace common {
 
 using GnssSvFlags = V1_0::IGnssCallback::GnssSvFlags;
+using GnssMeasurementFlagsV1_0 = V1_0::IGnssMeasurementCallback::GnssMeasurementFlags;
+using GnssMeasurementFlagsV2_1 = V2_1::IGnssMeasurementCallback::GnssMeasurementFlags;
+using GnssMeasurementStateV2_0 = V2_0::IGnssMeasurementCallback::GnssMeasurementState;
+using ElapsedRealtime = V2_0::ElapsedRealtime;
+using ElapsedRealtimeFlags = V2_0::ElapsedRealtimeFlags;
+using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType;
+using IGnssMeasurementCallbackV2_0 = V2_0::IGnssMeasurementCallback;
+using GnssSignalType = V2_1::GnssSignalType;
 
-GnssLocation Utils::getMockLocation() {
-    GnssLocation location = {.gnssLocationFlags = 0xFF,
-                             .latitudeDegrees = kMockLatitudeDegrees,
-                             .longitudeDegrees = kMockLongitudeDegrees,
-                             .altitudeMeters = kMockAltitudeMeters,
-                             .speedMetersPerSec = kMockSpeedMetersPerSec,
-                             .bearingDegrees = kMockBearingDegrees,
-                             .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
-                             .verticalAccuracyMeters = kMockVerticalAccuracyMeters,
-                             .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
-                             .bearingAccuracyDegrees = kMockBearingAccuracyDegrees,
-                             .timestamp = kMockTimestamp};
+GnssDataV2_1 Utils::getMockMeasurementV2_1() {
+    GnssDataV2_0 gnssDataV2_0 = Utils::getMockMeasurementV2_0();
+    V2_1::IGnssMeasurementCallback::GnssMeasurement gnssMeasurementV2_1 = {
+            .v2_0 = gnssDataV2_0.measurements[0],
+            .flags = (uint32_t)(GnssMeasurementFlagsV2_1::HAS_CARRIER_FREQUENCY |
+                                GnssMeasurementFlagsV2_1::HAS_CARRIER_PHASE |
+                                GnssMeasurementFlagsV2_1::HAS_FULL_ISB |
+                                GnssMeasurementFlagsV2_1::HAS_FULL_ISB_UNCERTAINTY |
+                                GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB |
+                                GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB_UNCERTAINTY),
+            .fullInterSignalBiasNs = 30.0,
+            .fullInterSignalBiasUncertaintyNs = 250.0,
+            .satelliteInterSignalBiasNs = 20.0,
+            .satelliteInterSignalBiasUncertaintyNs = 150.0,
+            .basebandCN0DbHz = 25.0,
+    };
+    GnssSignalType referenceSignalTypeForIsb = {
+            .constellation = GnssConstellationTypeV2_0::GPS,
+            .carrierFrequencyHz = 1.59975e+09,
+            .codeType = "C",
+    };
+    V2_1::IGnssMeasurementCallback::GnssClock gnssClockV2_1 = {
+            .v1_0 = gnssDataV2_0.clock,
+            .referenceSignalTypeForIsb = referenceSignalTypeForIsb,
+    };
+    hidl_vec<V2_1::IGnssMeasurementCallback::GnssMeasurement> measurements(1);
+    measurements[0] = gnssMeasurementV2_1;
+    GnssDataV2_1 gnssDataV2_1 = {
+            .measurements = measurements,
+            .clock = gnssClockV2_1,
+            .elapsedRealtime = gnssDataV2_0.elapsedRealtime,
+    };
+    return gnssDataV2_1;
+}
+
+GnssDataV2_0 Utils::getMockMeasurementV2_0() {
+    V1_0::IGnssMeasurementCallback::GnssMeasurement measurement_1_0 = {
+            .flags = (uint32_t)GnssMeasurementFlagsV1_0::HAS_CARRIER_FREQUENCY,
+            .svid = (int16_t)6,
+            .constellation = V1_0::GnssConstellationType::UNKNOWN,
+            .timeOffsetNs = 0.0,
+            .receivedSvTimeInNs = 8195997131077,
+            .receivedSvTimeUncertaintyInNs = 15,
+            .cN0DbHz = 30.0,
+            .pseudorangeRateMps = -484.13739013671875,
+            .pseudorangeRateUncertaintyMps = 1.0379999876022339,
+            .accumulatedDeltaRangeState = (uint32_t)V1_0::IGnssMeasurementCallback::
+                    GnssAccumulatedDeltaRangeState::ADR_STATE_UNKNOWN,
+            .accumulatedDeltaRangeM = 0.0,
+            .accumulatedDeltaRangeUncertaintyM = 0.0,
+            .carrierFrequencyHz = 1.59975e+09,
+            .multipathIndicator =
+                    V1_0::IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN};
+    V1_1::IGnssMeasurementCallback::GnssMeasurement measurement_1_1 = {.v1_0 = measurement_1_0};
+    V2_0::IGnssMeasurementCallback::GnssMeasurement measurement_2_0 = {
+            .v1_1 = measurement_1_1,
+            .codeType = "C",
+            .state = GnssMeasurementStateV2_0::STATE_CODE_LOCK |
+                     GnssMeasurementStateV2_0::STATE_BIT_SYNC |
+                     GnssMeasurementStateV2_0::STATE_SUBFRAME_SYNC |
+                     GnssMeasurementStateV2_0::STATE_TOW_DECODED |
+                     GnssMeasurementStateV2_0::STATE_GLO_STRING_SYNC |
+                     GnssMeasurementStateV2_0::STATE_GLO_TOD_DECODED,
+            .constellation = GnssConstellationTypeV2_0::GLONASS,
+    };
+
+    hidl_vec<IGnssMeasurementCallbackV2_0::GnssMeasurement> measurements(1);
+    measurements[0] = measurement_2_0;
+    V1_0::IGnssMeasurementCallback::GnssClock clock = {.timeNs = 2713545000000,
+                                                       .fullBiasNs = -1226701900521857520,
+                                                       .biasNs = 0.59689998626708984,
+                                                       .biasUncertaintyNs = 47514.989972114563,
+                                                       .driftNsps = -51.757811607455452,
+                                                       .driftUncertaintyNsps = 310.64968328491528,
+                                                       .hwClockDiscontinuityCount = 1};
+
+    ElapsedRealtime timestamp = {
+            .flags = ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
+                     ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
+            .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
+            // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
+            // In an actual implementation provide an estimate of the synchronization uncertainty
+            // or don't set the field.
+            .timeUncertaintyNs = 1000000};
+
+    GnssDataV2_0 gnssData = {
+            .measurements = measurements, .clock = clock, .elapsedRealtime = timestamp};
+    return gnssData;
+}
+
+V2_0::GnssLocation Utils::getMockLocationV2_0() {
+    const V2_0::ElapsedRealtime timestamp = {
+            .flags = V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
+                     V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
+            .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
+            // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
+            // In an actual implementation provide an estimate of the synchronization uncertainty
+            // or don't set the field.
+            .timeUncertaintyNs = 1000000};
+
+    V2_0::GnssLocation location = {.v1_0 = Utils::getMockLocationV1_0(),
+                                   .elapsedRealtime = timestamp};
     return location;
 }
 
-GnssSvInfo Utils::getSvInfo(int16_t svid, GnssConstellationType type, float cN0DbHz,
-                            float elevationDegrees, float azimuthDegrees) {
-    GnssSvInfo svInfo = {.svid = svid,
-                         .constellation = type,
-                         .cN0Dbhz = cN0DbHz,
-                         .elevationDegrees = elevationDegrees,
-                         .azimuthDegrees = azimuthDegrees,
-                         .svFlag = GnssSvFlags::USED_IN_FIX | GnssSvFlags::HAS_EPHEMERIS_DATA |
-                                   GnssSvFlags::HAS_ALMANAC_DATA};
+V1_0::GnssLocation Utils::getMockLocationV1_0() {
+    V1_0::GnssLocation location = {
+            .gnssLocationFlags = 0xFF,
+            .latitudeDegrees = kMockLatitudeDegrees,
+            .longitudeDegrees = kMockLongitudeDegrees,
+            .altitudeMeters = kMockAltitudeMeters,
+            .speedMetersPerSec = kMockSpeedMetersPerSec,
+            .bearingDegrees = kMockBearingDegrees,
+            .horizontalAccuracyMeters = kMockHorizontalAccuracyMeters,
+            .verticalAccuracyMeters = kMockVerticalAccuracyMeters,
+            .speedAccuracyMetersPerSecond = kMockSpeedAccuracyMetersPerSecond,
+            .bearingAccuracyDegrees = kMockBearingAccuracyDegrees,
+            .timestamp = kMockTimestamp};
+    return location;
+}
+
+hidl_vec<GnssSvInfoV2_1> Utils::getMockSvInfoListV2_1() {
+    GnssSvInfoV1_0 gnssSvInfoV1_0 =
+            Utils::getMockSvInfoV1_0(3, V1_0::GnssConstellationType::GPS, 32.5, 59.1, 166.5);
+    GnssSvInfoV2_0 gnssSvInfoV2_0 =
+            Utils::getMockSvInfoV2_0(gnssSvInfoV1_0, V2_0::GnssConstellationType::GPS);
+    hidl_vec<GnssSvInfoV2_1> gnssSvInfoList = {
+            Utils::getMockSvInfoV2_1(gnssSvInfoV2_0, 27.5),
+            getMockSvInfoV2_1(
+                    getMockSvInfoV2_0(getMockSvInfoV1_0(5, V1_0::GnssConstellationType::GPS, 27.0,
+                                                        29.0, 56.5),
+                                      V2_0::GnssConstellationType::GPS),
+                    22.0),
+            getMockSvInfoV2_1(
+                    getMockSvInfoV2_0(getMockSvInfoV1_0(17, V1_0::GnssConstellationType::GPS, 30.5,
+                                                        71.0, 77.0),
+                                      V2_0::GnssConstellationType::GPS),
+                    25.5),
+            getMockSvInfoV2_1(
+                    getMockSvInfoV2_0(getMockSvInfoV1_0(26, V1_0::GnssConstellationType::GPS, 24.1,
+                                                        28.0, 253.0),
+                                      V2_0::GnssConstellationType::GPS),
+                    19.1),
+            getMockSvInfoV2_1(
+                    getMockSvInfoV2_0(getMockSvInfoV1_0(5, V1_0::GnssConstellationType::GLONASS,
+                                                        20.5, 11.5, 116.0),
+                                      V2_0::GnssConstellationType::GLONASS),
+                    15.5),
+            getMockSvInfoV2_1(
+                    getMockSvInfoV2_0(getMockSvInfoV1_0(17, V1_0::GnssConstellationType::GLONASS,
+                                                        21.5, 28.5, 186.0),
+                                      V2_0::GnssConstellationType::GLONASS),
+                    16.5),
+            getMockSvInfoV2_1(
+                    getMockSvInfoV2_0(getMockSvInfoV1_0(18, V1_0::GnssConstellationType::GLONASS,
+                                                        28.3, 38.8, 69.0),
+                                      V2_0::GnssConstellationType::GLONASS),
+                    25.3),
+            getMockSvInfoV2_1(
+                    getMockSvInfoV2_0(getMockSvInfoV1_0(10, V1_0::GnssConstellationType::GLONASS,
+                                                        25.0, 66.0, 247.0),
+                                      V2_0::GnssConstellationType::GLONASS),
+                    20.0),
+            getMockSvInfoV2_1(
+                    getMockSvInfoV2_0(getMockSvInfoV1_0(3, V1_0::GnssConstellationType::UNKNOWN,
+                                                        22.0, 35.0, 112.0),
+                                      V2_0::GnssConstellationType::IRNSS),
+                    19.7),
+    };
+    return gnssSvInfoList;
+}
+
+GnssSvInfoV2_1 Utils::getMockSvInfoV2_1(GnssSvInfoV2_0 gnssSvInfoV2_0, float basebandCN0DbHz) {
+    GnssSvInfoV2_1 gnssSvInfoV2_1 = {
+            .v2_0 = gnssSvInfoV2_0,
+            .basebandCN0DbHz = basebandCN0DbHz,
+    };
+    return gnssSvInfoV2_1;
+}
+
+GnssSvInfoV2_0 Utils::getMockSvInfoV2_0(GnssSvInfoV1_0 gnssSvInfoV1_0,
+                                        V2_0::GnssConstellationType type) {
+    GnssSvInfoV2_0 gnssSvInfoV2_0 = {
+            .v1_0 = gnssSvInfoV1_0,
+            .constellation = type,
+    };
+    return gnssSvInfoV2_0;
+}
+
+GnssSvInfoV1_0 Utils::getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type,
+                                        float cN0DbHz, float elevationDegrees,
+                                        float azimuthDegrees) {
+    GnssSvInfoV1_0 svInfo = {.svid = svid,
+                             .constellation = type,
+                             .cN0Dbhz = cN0DbHz,
+                             .elevationDegrees = elevationDegrees,
+                             .azimuthDegrees = azimuthDegrees,
+                             .svFlag = GnssSvFlags::USED_IN_FIX | GnssSvFlags::HAS_EPHEMERIS_DATA |
+                                       GnssSvFlags::HAS_ALMANAC_DATA};
     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 47c8812..d9ad5a5 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -18,20 +18,38 @@
 #define android_hardware_gnss_common_default_Utils_H_
 
 #include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <android/hardware/gnss/2.1/IGnss.h>
 
-using GnssConstellationType = ::android::hardware::gnss::V1_0::GnssConstellationType;
-using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation;
-using GnssSvInfo = ::android::hardware::gnss::V1_0::IGnssCallback::GnssSvInfo;
+using ::android::hardware::hidl_vec;
 
 namespace android {
 namespace hardware {
 namespace gnss {
 namespace common {
 
+using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
+using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
+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 GnssLocation getMockLocation();
-    static GnssSvInfo getSvInfo(int16_t svid, GnssConstellationType type, float cN0DbHz,
-                                float elevationDegrees, float azimuthDegrees);
+    static GnssDataV2_0 getMockMeasurementV2_0();
+    static GnssDataV2_1 getMockMeasurementV2_1();
+    static V2_0::GnssLocation getMockLocationV2_0();
+    static V1_0::GnssLocation getMockLocationV1_0();
+    static hidl_vec<GnssSvInfoV2_1> getMockSvInfoListV2_1();
+    static GnssSvInfoV2_1 getMockSvInfoV2_1(GnssSvInfoV2_0 gnssSvInfoV2_0, float basebandCN0DbHz);
+    static GnssSvInfoV2_0 getMockSvInfoV2_0(GnssSvInfoV1_0 gnssSvInfoV1_0,
+                                            V2_0::GnssConstellationType type);
+    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/Android.bp b/gnss/common/utils/vts/Android.bp
index ed383fc..4c6d443 100644
--- a/gnss/common/utils/vts/Android.bp
+++ b/gnss/common/utils/vts/Android.bp
@@ -31,6 +31,7 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@2.0",
         "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss.measurement_corrections@1.1",
     ],
     static_libs: [
         "libgtest",
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 4e42f75..9bf68e6 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,
@@ -92,7 +94,7 @@
     EXPECT_GT(location.timestamp, 1.48e12);
 }
 
-const MeasurementCorrections Utils::getMockMeasurementCorrections() {
+const MeasurementCorrections_1_0 Utils::getMockMeasurementCorrections() {
     ReflectingPlane reflectingPlane = {
             .latitudeDegrees = 37.4220039,
             .longitudeDegrees = -122.0840991,
@@ -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,9 +127,9 @@
             .excessPathLengthUncertaintyMeters = 10.0,
     };
 
-    hidl_vec<SingleSatCorrection> singleSatCorrections = {singleSatCorrection1,
-                                                          singleSatCorrection2};
-    MeasurementCorrections mockCorrections = {
+    hidl_vec<SingleSatCorrection_V1_0> singleSatCorrections = {singleSatCorrection1,
+                                                               singleSatCorrection2};
+    MeasurementCorrections_1_0 mockCorrections = {
             .latitudeDegrees = 37.4219999,
             .longitudeDegrees = -122.0840575,
             .altitudeMeters = 30.60062531,
@@ -139,6 +141,34 @@
     return mockCorrections;
 }
 
+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;
+}
+
 /*
  * MapConstellationType:
  * Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
diff --git a/gnss/common/utils/vts/include/GnssCallbackEventQueue.h b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
new file mode 100644
index 0000000..3dc429b
--- /dev/null
+++ b/gnss/common/utils/vts/include/GnssCallbackEventQueue.h
@@ -0,0 +1,140 @@
+/*
+ * 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_gnss_common_vts_GnssCallbackEventQueue_H_
+#define android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_
+
+#include <log/log.h>
+
+#include <condition_variable>
+#include <deque>
+#include <list>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+/*
+ * Producer/consumer queue for storing/retrieving callback events from GNSS HAL.
+ */
+template <class T>
+class GnssCallbackEventQueue {
+  public:
+    GnssCallbackEventQueue(const std::string& name) : name_(name), called_count_(0){};
+    ~GnssCallbackEventQueue() { reset(); }
+
+    /* Adds callback event to the end of the queue. */
+    void store(const T& event);
+
+    /*
+     * Removes the callack event at the front of the queue, stores it in event parameter
+     * and returns true. Returns false on timeout and event is not populated.
+     */
+    bool retrieve(T& event, int timeout_seconds);
+
+    /*
+     * Removes parameter count number of callack events at the front of the queue, stores
+     * them in event_list parameter and returns the number of events retrieved. Waits up to
+     * timeout_seconds to retrieve each event. If timeout occurs, it returns the number of
+     * items retrieved which will be less than count.
+     */
+    int retrieve(std::list<T>& event_list, int count, int timeout_seconds);
+
+    /* Returns the number of events pending to be retrieved from the callback event queue. */
+    int size() const;
+
+    /* Returns the number of callback events received since last reset(). */
+    int calledCount() const;
+
+    /* Clears the callback event queue and resets the calledCount() to 0. */
+    void reset();
+
+  private:
+    GnssCallbackEventQueue(const GnssCallbackEventQueue&) = delete;
+    GnssCallbackEventQueue& operator=(const GnssCallbackEventQueue&) = delete;
+
+    std::string name_;
+    int called_count_;
+    mutable std::recursive_mutex mtx_;
+    std::condition_variable_any cv_;
+    std::deque<T> events_;
+};
+
+template <class T>
+void GnssCallbackEventQueue<T>::store(const T& event) {
+    std::unique_lock<std::recursive_mutex> lock(mtx_);
+    events_.push_back(event);
+    ++called_count_;
+    lock.unlock();
+    cv_.notify_all();
+}
+
+template <class T>
+bool GnssCallbackEventQueue<T>::retrieve(T& event, int timeout_seconds) {
+    std::unique_lock<std::recursive_mutex> lock(mtx_);
+    cv_.wait_for(lock, std::chrono::seconds(timeout_seconds), [&] { return !events_.empty(); });
+    if (events_.empty()) {
+        return false;
+    }
+    event = events_.front();
+    events_.pop_front();
+    return true;
+}
+
+template <class T>
+int GnssCallbackEventQueue<T>::retrieve(std::list<T>& event_list, int count, int timeout_seconds) {
+    for (int i = 0; i < count; ++i) {
+        T event;
+        if (!retrieve(event, timeout_seconds)) {
+            return i;
+        }
+        event_list.push_back(event);
+    }
+
+    return count;
+}
+
+template <class T>
+int GnssCallbackEventQueue<T>::size() const {
+    std::unique_lock<std::recursive_mutex> lock(mtx_);
+    return events_.size();
+}
+
+template <class T>
+int GnssCallbackEventQueue<T>::calledCount() const {
+    std::unique_lock<std::recursive_mutex> lock(mtx_);
+    return called_count_;
+}
+
+template <class T>
+void GnssCallbackEventQueue<T>::reset() {
+    std::unique_lock<std::recursive_mutex> lock(mtx_);
+    if (!events_.empty()) {
+        ALOGW("%u unprocessed events discarded in callback queue %s", (unsigned int)events_.size(),
+              name_.c_str());
+    }
+    events_.clear();
+    called_count_ = 0;
+}
+
+}  // namespace common
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_gnss_common_vts_GnssCallbackEventQueue_H_
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index b5f833b..9c838b2 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -20,12 +20,23 @@
 #include <android/hardware/gnss/1.0/IGnss.h>
 #include <android/hardware/gnss/2.0/IGnss.h>
 #include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
 
 using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
 using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
 using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation;
 using namespace android::hardware::gnss::measurement_corrections::V1_0;
 
+using MeasurementCorrections_1_0 =
+        android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
+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 {
@@ -34,7 +45,8 @@
 struct Utils {
     static void checkLocation(const GnssLocation& location, bool check_speed,
                               bool check_more_accuracies);
-    static const MeasurementCorrections getMockMeasurementCorrections();
+    static const MeasurementCorrections_1_0 getMockMeasurementCorrections();
+    static const MeasurementCorrections_1_1 getMockMeasurementCorrections_1_1();
 
     static GnssConstellationType_1_0 mapConstellationType(GnssConstellationType_2_0 constellation);
 };
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
new file mode 100644
index 0000000..9363848
--- /dev/null
+++ b/gnss/measurement_corrections/1.1/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.gnss.measurement_corrections@1.1",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IMeasurementCorrections.hal",
+    ],
+    interfaces: [
+        "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss@1.0",
+        "android.hardware.gnss@2.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal b/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal
new file mode 100644
index 0000000..9461a5e
--- /dev/null
+++ b/gnss/measurement_corrections/1.1/IMeasurementCorrections.hal
@@ -0,0 +1,40 @@
+/*
+ * 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.measurement_corrections@1.1;
+
+import @1.0::IMeasurementCorrections;
+
+/**
+ * Interface for measurement corrections support.
+ */
+interface IMeasurementCorrections extends @1.0::IMeasurementCorrections {
+    /**
+     * Injects measurement corrections to be used by the HAL to improve the GNSS location output.
+     *
+     * These are NOT to be used to adjust the IGnssMeasurementCallback output values -
+     * those remain raw, uncorrected measurements.
+     *
+     * In general, these are injected when conditions defined by the platform are met, such as when
+     * GNSS Location is being requested at a sufficiently high accuracy, based on the capabilities
+     * of the GNSS chipset as reported in the IGnssCallback.
+     *
+     * @param corrections The computed corrections to be used by the HAL.
+     *
+     * @return success Whether the HAL can accept & use these corrections.
+     */
+    setCorrections_1_1(MeasurementCorrections corrections) generates (bool success);
+};
\ No newline at end of file
diff --git a/gnss/measurement_corrections/1.1/types.hal b/gnss/measurement_corrections/1.1/types.hal
new file mode 100644
index 0000000..e98be13
--- /dev/null
+++ b/gnss/measurement_corrections/1.1/types.hal
@@ -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.
+ */
+
+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. The v1_0.satCorrections field is deprecated and is no longer used by
+ * framework.
+ */
+struct MeasurementCorrections {
+    @1.0::MeasurementCorrections v1_0;
+
+    /**
+     * Boolean indicating if environment bearing is available.
+     */
+    bool hasEnvironmentBearing;
+
+    /**
+     * Environment bearing in degrees clockwise from true North (0.0 to 360.0], in direction of
+     * user motion. Environment bearing is provided when it is known with high probability that
+     * velocity is aligned with an environment feature, such as a building or road.
+     *
+     * If user speed is zero, environmentBearingDegrees represents bearing of most recent speed
+     * that was > 0.
+     *
+     * As position approaches another road, environmentBearingUncertaintyDegrees will grow, and at
+     * some stage hasEnvironmentBearing = false.
+     *
+     * As position moves towards an open area, environmentBearingUncertaintyDegrees will grow, and
+     * at some stage hasEnvironmentBearing = false.
+     *
+     * 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;
+
+    /**
+     * 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;
+
+    /**
+     * 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/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal b/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal
index 5a582c2..5ee2923 100644
--- a/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal
+++ b/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal
@@ -82,6 +82,9 @@
         /**
          * Package name of the Android proxy application representing the non-framework
          * entity that requested location. Set to empty string if unknown.
+         *
+         * For user-initiated emergency use cases, this field must be set to empty string
+         * and the inEmergencyMode field must be set to true.
          */
         string proxyAppPackageName;
 
@@ -157,4 +160,4 @@
      * @return success True if the framework determines that the device is in emergency session.
      */
     isInEmergencySession() generates (bool success);
-};
\ No newline at end of file
+};
diff --git a/graphics/allocator/2.0/default/OWNERS b/graphics/allocator/2.0/default/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/allocator/2.0/default/OWNERS
+++ b/graphics/allocator/2.0/default/OWNERS
@@ -1,4 +1,4 @@
 # Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
 stoza@google.com
+vhau@google.com
diff --git a/graphics/allocator/2.0/utils/OWNERS b/graphics/allocator/2.0/utils/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/allocator/2.0/utils/OWNERS
+++ b/graphics/allocator/2.0/utils/OWNERS
@@ -1,4 +1,4 @@
 # Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
 stoza@google.com
+vhau@google.com
diff --git a/graphics/allocator/4.0/Android.bp b/graphics/allocator/4.0/Android.bp
new file mode 100644
index 0000000..f5f9458
--- /dev/null
+++ b/graphics/allocator/4.0/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.allocator@4.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IAllocator.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/graphics/allocator/4.0/IAllocator.hal b/graphics/allocator/4.0/IAllocator.hal
new file mode 100644
index 0000000..7934867
--- /dev/null
+++ b/graphics/allocator/4.0/IAllocator.hal
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package android.hardware.graphics.allocator@4.0;
+
+import android.hardware.graphics.mapper@4.0;
+
+interface IAllocator {
+    /**
+     * Allocates buffers with the properties specified by the descriptor.
+     *
+     * Allocations should be optimized for usage bits provided in the
+     * descriptor.
+     *
+     * @param descriptor Properties of the buffers to allocate. This must be
+     *     obtained from IMapper::createDescriptor().
+     * @param count The number of buffers to allocate.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_DESCRIPTOR` if the descriptor is invalid.
+     *     - `NO_RESOURCES` if the allocation cannot be fulfilled at this time.
+     *     - `UNSUPPORTED` if any of the properties encoded in the descriptor
+     *       are not supported.
+     * @return stride The number of pixels between two consecutive rows of
+     *     an allocated buffer, when the concept of consecutive rows is defined.
+     *     Otherwise, it has no meaning.
+     * @return buffers Array of raw handles to the allocated buffers.
+     */
+    allocate(BufferDescriptor descriptor, uint32_t count)
+        generates (Error error,
+                   uint32_t stride,
+                   vec<handle> buffers);
+};
+
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 601cabc..e594233 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -20,5 +20,13 @@
         cpp: {
             enabled: false,
         },
+        ndk: {
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.media.swcodec",
+            ],
+            min_sdk_version: "29",
+        },
     },
+    versions: ["1"],
 }
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/.hash b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/.hash
new file mode 100644
index 0000000..66b5d13
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/.hash
@@ -0,0 +1 @@
+f5bdf5724a941dc7e5e7d0ebe9dfe028f7bcc25f
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BlendMode.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BlendMode.aidl
new file mode 100644
index 0000000..deafdfa
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BlendMode.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="int") @VintfStability
+enum BlendMode {
+  INVALID = 0,
+  NONE = 1,
+  PREMULTIPLIED = 2,
+  COVERAGE = 3,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BufferUsage.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BufferUsage.aidl
new file mode 100644
index 0000000..58eefc4
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/BufferUsage.aidl
@@ -0,0 +1,47 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum BufferUsage {
+  CPU_READ_MASK = 15,
+  CPU_READ_NEVER = 0,
+  CPU_READ_RARELY = 2,
+  CPU_READ_OFTEN = 3,
+  CPU_WRITE_MASK = 240,
+  CPU_WRITE_NEVER = 0,
+  CPU_WRITE_RARELY = 32,
+  CPU_WRITE_OFTEN = 48,
+  GPU_TEXTURE = 256,
+  GPU_RENDER_TARGET = 512,
+  COMPOSER_OVERLAY = 2048,
+  COMPOSER_CLIENT_TARGET = 4096,
+  PROTECTED = 16384,
+  COMPOSER_CURSOR = 32768,
+  VIDEO_ENCODER = 65536,
+  CAMERA_OUTPUT = 131072,
+  CAMERA_INPUT = 262144,
+  RENDERSCRIPT = 1048576,
+  VIDEO_DECODER = 4194304,
+  SENSOR_DIRECT_DATA = 8388608,
+  GPU_CUBE_MAP = 33554432,
+  GPU_MIPMAP_COMPLETE = 67108864,
+  HW_IMAGE_ENCODER = 134217728,
+  GPU_DATA_BUFFER = 16777216,
+  VENDOR_MASK = -268435456,
+  VENDOR_MASK_HI = -281474976710656,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ChromaSiting.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ChromaSiting.aidl
new file mode 100644
index 0000000..7ca4dfa
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ChromaSiting.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum ChromaSiting {
+  NONE = 0,
+  UNKNOWN = 1,
+  SITED_INTERSTITIAL = 2,
+  COSITED_HORIZONTAL = 3,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Compression.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Compression.aidl
new file mode 100644
index 0000000..06e40a0
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Compression.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum Compression {
+  NONE = 0,
+  DISPLAY_STREAM_COMPRESSION = 1,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Cta861_3.aidl
new file mode 100644
index 0000000..d4af501
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Cta861_3.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable Cta861_3 {
+  float maxContentLightLevel;
+  float maxFrameAverageLightLevel;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Dataspace.aidl
new file mode 100644
index 0000000..43d7f84
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Dataspace.aidl
@@ -0,0 +1,81 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="int") @VintfStability
+enum Dataspace {
+  UNKNOWN = 0,
+  ARBITRARY = 1,
+  STANDARD_SHIFT = 16,
+  STANDARD_MASK = 4128768,
+  STANDARD_UNSPECIFIED = 0,
+  STANDARD_BT709 = 65536,
+  STANDARD_BT601_625 = 131072,
+  STANDARD_BT601_625_UNADJUSTED = 196608,
+  STANDARD_BT601_525 = 262144,
+  STANDARD_BT601_525_UNADJUSTED = 327680,
+  STANDARD_BT2020 = 393216,
+  STANDARD_BT2020_CONSTANT_LUMINANCE = 458752,
+  STANDARD_BT470M = 524288,
+  STANDARD_FILM = 589824,
+  STANDARD_DCI_P3 = 655360,
+  STANDARD_ADOBE_RGB = 720896,
+  TRANSFER_SHIFT = 22,
+  TRANSFER_MASK = 130023424,
+  TRANSFER_UNSPECIFIED = 0,
+  TRANSFER_LINEAR = 4194304,
+  TRANSFER_SRGB = 8388608,
+  TRANSFER_SMPTE_170M = 12582912,
+  TRANSFER_GAMMA2_2 = 16777216,
+  TRANSFER_GAMMA2_6 = 20971520,
+  TRANSFER_GAMMA2_8 = 25165824,
+  TRANSFER_ST2084 = 29360128,
+  TRANSFER_HLG = 33554432,
+  RANGE_SHIFT = 27,
+  RANGE_MASK = 939524096,
+  RANGE_UNSPECIFIED = 0,
+  RANGE_FULL = 134217728,
+  RANGE_LIMITED = 268435456,
+  RANGE_EXTENDED = 402653184,
+  SRGB_LINEAR = 138477568,
+  SCRGB_LINEAR = 406913024,
+  SRGB = 142671872,
+  SCRGB = 411107328,
+  JFIF = 146931712,
+  BT601_625 = 281149440,
+  BT601_525 = 281280512,
+  BT709 = 281083904,
+  DCI_P3_LINEAR = 139067392,
+  DCI_P3 = 155844608,
+  DISPLAY_P3_LINEAR = 139067392,
+  DISPLAY_P3 = 143261696,
+  ADOBE_RGB = 151715840,
+  BT2020_LINEAR = 138805248,
+  BT2020 = 147193856,
+  BT2020_PQ = 163971072,
+  DEPTH = 4096,
+  SENSOR = 4097,
+  BT2020_ITU = 281411584,
+  BT2020_ITU_PQ = 298188800,
+  BT2020_ITU_HLG = 302383104,
+  BT2020_HLG = 168165376,
+  DISPLAY_BT2020 = 142999552,
+  DYNAMIC_DEPTH = 4098,
+  JPEG_APP_SEGMENTS = 4099,
+  HEIF = 4100,
+  BT709_FULL_RANGE = 146866176,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ExtendableType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ExtendableType.aidl
new file mode 100644
index 0000000..6fcb794
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/ExtendableType.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable ExtendableType {
+  @utf8InCpp String name;
+  long value = 0;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBuffer.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBuffer.aidl
new file mode 100644
index 0000000..72222e1
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBuffer.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable HardwareBuffer {
+  android.hardware.graphics.common.HardwareBufferDescription description;
+  android.hardware.common.NativeHandle handle;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBufferDescription.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBufferDescription.aidl
new file mode 100644
index 0000000..8b12169
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/HardwareBufferDescription.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable HardwareBufferDescription {
+  int width;
+  int height;
+  int layers;
+  android.hardware.graphics.common.PixelFormat format;
+  android.hardware.graphics.common.BufferUsage usage;
+  int stride;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Interlaced.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Interlaced.aidl
new file mode 100644
index 0000000..26674c9
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Interlaced.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum Interlaced {
+  NONE = 0,
+  TOP_BOTTOM = 1,
+  RIGHT_LEFT = 2,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PixelFormat.aidl
new file mode 100644
index 0000000..e5f0470
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PixelFormat.aidl
@@ -0,0 +1,50 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="int") @VintfStability
+enum PixelFormat {
+  UNSPECIFIED = 0,
+  RGBA_8888 = 1,
+  RGBX_8888 = 2,
+  RGB_888 = 3,
+  RGB_565 = 4,
+  BGRA_8888 = 5,
+  YCBCR_422_SP = 16,
+  YCRCB_420_SP = 17,
+  YCBCR_422_I = 20,
+  RGBA_FP16 = 22,
+  RAW16 = 32,
+  BLOB = 33,
+  IMPLEMENTATION_DEFINED = 34,
+  YCBCR_420_888 = 35,
+  RAW_OPAQUE = 36,
+  RAW10 = 37,
+  RAW12 = 38,
+  RGBA_1010102 = 43,
+  Y8 = 538982489,
+  Y16 = 540422489,
+  YV12 = 842094169,
+  DEPTH_16 = 48,
+  DEPTH_24 = 49,
+  DEPTH_24_STENCIL_8 = 50,
+  DEPTH_32F = 51,
+  DEPTH_32F_STENCIL_8 = 52,
+  STENCIL_8 = 53,
+  YCBCR_P010 = 54,
+  HSV_888 = 55,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayout.aidl
new file mode 100644
index 0000000..8bca42f
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayout.aidl
@@ -0,0 +1,30 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable PlaneLayout {
+  android.hardware.graphics.common.PlaneLayoutComponent[] components;
+  long offsetInBytes;
+  long sampleIncrementInBits;
+  long strideInBytes;
+  long widthInSamples;
+  long heightInSamples;
+  long totalSizeInBytes;
+  long horizontalSubsampling;
+  long verticalSubsampling;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponent.aidl
new file mode 100644
index 0000000..f5a649c
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponent.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable PlaneLayoutComponent {
+  android.hardware.graphics.common.ExtendableType type;
+  long offsetInBits;
+  long sizeInBits;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponentType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
new file mode 100644
index 0000000..7ff8d76
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum PlaneLayoutComponentType {
+  Y = 1,
+  CB = 2,
+  CR = 4,
+  R = 1024,
+  G = 2048,
+  B = 4096,
+  RAW = 1048576,
+  A = 1073741824,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Rect.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Rect.aidl
new file mode 100644
index 0000000..e0ba69b
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Rect.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable Rect {
+  int left;
+  int top;
+  int right;
+  int bottom;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Smpte2086.aidl
new file mode 100644
index 0000000..5da36f6
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/Smpte2086.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable Smpte2086 {
+  android.hardware.graphics.common.XyColor primaryRed;
+  android.hardware.graphics.common.XyColor primaryGreen;
+  android.hardware.graphics.common.XyColor primaryBlue;
+  android.hardware.graphics.common.XyColor whitePoint;
+  float maxLuminance;
+  float minLuminance;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/StandardMetadataType.aidl
new file mode 100644
index 0000000..34b53a2
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -0,0 +1,43 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum StandardMetadataType {
+  INVALID = 0,
+  BUFFER_ID = 1,
+  NAME = 2,
+  WIDTH = 3,
+  HEIGHT = 4,
+  LAYER_COUNT = 5,
+  PIXEL_FORMAT_REQUESTED = 6,
+  PIXEL_FORMAT_FOURCC = 7,
+  PIXEL_FORMAT_MODIFIER = 8,
+  USAGE = 9,
+  ALLOCATION_SIZE = 10,
+  PROTECTED_CONTENT = 11,
+  COMPRESSION = 12,
+  INTERLACED = 13,
+  CHROMA_SITING = 14,
+  PLANE_LAYOUTS = 15,
+  CROP = 16,
+  DATASPACE = 17,
+  BLEND_MODE = 18,
+  SMPTE2086 = 19,
+  CTA861_3 = 20,
+  SMPTE2094_40 = 21,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/XyColor.aidl
new file mode 100644
index 0000000..d96d0ac
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/1/android/hardware/graphics/common/XyColor.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable XyColor {
+  float x;
+  float y;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BlendMode.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BlendMode.aidl
new file mode 100644
index 0000000..deafdfa
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/BlendMode.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="int") @VintfStability
+enum BlendMode {
+  INVALID = 0,
+  NONE = 1,
+  PREMULTIPLIED = 2,
+  COVERAGE = 3,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl
new file mode 100644
index 0000000..7ca4dfa
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ChromaSiting.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum ChromaSiting {
+  NONE = 0,
+  UNKNOWN = 1,
+  SITED_INTERSTITIAL = 2,
+  COSITED_HORIZONTAL = 3,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Compression.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Compression.aidl
new file mode 100644
index 0000000..06e40a0
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Compression.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum Compression {
+  NONE = 0,
+  DISPLAY_STREAM_COMPRESSION = 1,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Cta861_3.aidl
new file mode 100644
index 0000000..d4af501
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Cta861_3.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable Cta861_3 {
+  float maxContentLightLevel;
+  float maxFrameAverageLightLevel;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
new file mode 100644
index 0000000..43d7f84
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
@@ -0,0 +1,81 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="int") @VintfStability
+enum Dataspace {
+  UNKNOWN = 0,
+  ARBITRARY = 1,
+  STANDARD_SHIFT = 16,
+  STANDARD_MASK = 4128768,
+  STANDARD_UNSPECIFIED = 0,
+  STANDARD_BT709 = 65536,
+  STANDARD_BT601_625 = 131072,
+  STANDARD_BT601_625_UNADJUSTED = 196608,
+  STANDARD_BT601_525 = 262144,
+  STANDARD_BT601_525_UNADJUSTED = 327680,
+  STANDARD_BT2020 = 393216,
+  STANDARD_BT2020_CONSTANT_LUMINANCE = 458752,
+  STANDARD_BT470M = 524288,
+  STANDARD_FILM = 589824,
+  STANDARD_DCI_P3 = 655360,
+  STANDARD_ADOBE_RGB = 720896,
+  TRANSFER_SHIFT = 22,
+  TRANSFER_MASK = 130023424,
+  TRANSFER_UNSPECIFIED = 0,
+  TRANSFER_LINEAR = 4194304,
+  TRANSFER_SRGB = 8388608,
+  TRANSFER_SMPTE_170M = 12582912,
+  TRANSFER_GAMMA2_2 = 16777216,
+  TRANSFER_GAMMA2_6 = 20971520,
+  TRANSFER_GAMMA2_8 = 25165824,
+  TRANSFER_ST2084 = 29360128,
+  TRANSFER_HLG = 33554432,
+  RANGE_SHIFT = 27,
+  RANGE_MASK = 939524096,
+  RANGE_UNSPECIFIED = 0,
+  RANGE_FULL = 134217728,
+  RANGE_LIMITED = 268435456,
+  RANGE_EXTENDED = 402653184,
+  SRGB_LINEAR = 138477568,
+  SCRGB_LINEAR = 406913024,
+  SRGB = 142671872,
+  SCRGB = 411107328,
+  JFIF = 146931712,
+  BT601_625 = 281149440,
+  BT601_525 = 281280512,
+  BT709 = 281083904,
+  DCI_P3_LINEAR = 139067392,
+  DCI_P3 = 155844608,
+  DISPLAY_P3_LINEAR = 139067392,
+  DISPLAY_P3 = 143261696,
+  ADOBE_RGB = 151715840,
+  BT2020_LINEAR = 138805248,
+  BT2020 = 147193856,
+  BT2020_PQ = 163971072,
+  DEPTH = 4096,
+  SENSOR = 4097,
+  BT2020_ITU = 281411584,
+  BT2020_ITU_PQ = 298188800,
+  BT2020_ITU_HLG = 302383104,
+  BT2020_HLG = 168165376,
+  DISPLAY_BT2020 = 142999552,
+  DYNAMIC_DEPTH = 4098,
+  JPEG_APP_SEGMENTS = 4099,
+  HEIF = 4100,
+  BT709_FULL_RANGE = 146866176,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ExtendableType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ExtendableType.aidl
new file mode 100644
index 0000000..6fcb794
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/ExtendableType.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable ExtendableType {
+  @utf8InCpp String name;
+  long value = 0;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Interlaced.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Interlaced.aidl
new file mode 100644
index 0000000..26674c9
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Interlaced.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum Interlaced {
+  NONE = 0,
+  TOP_BOTTOM = 1,
+  RIGHT_LEFT = 2,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayout.aidl
new file mode 100644
index 0000000..8bca42f
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayout.aidl
@@ -0,0 +1,30 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable PlaneLayout {
+  android.hardware.graphics.common.PlaneLayoutComponent[] components;
+  long offsetInBytes;
+  long sampleIncrementInBits;
+  long strideInBytes;
+  long widthInSamples;
+  long heightInSamples;
+  long totalSizeInBytes;
+  long horizontalSubsampling;
+  long verticalSubsampling;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponent.aidl
new file mode 100644
index 0000000..f5a649c
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponent.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable PlaneLayoutComponent {
+  android.hardware.graphics.common.ExtendableType type;
+  long offsetInBits;
+  long sizeInBits;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
new file mode 100644
index 0000000..7ff8d76
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum PlaneLayoutComponentType {
+  Y = 1,
+  CB = 2,
+  CR = 4,
+  R = 1024,
+  G = 2048,
+  B = 4096,
+  RAW = 1048576,
+  A = 1073741824,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Rect.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Rect.aidl
new file mode 100644
index 0000000..e0ba69b
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Rect.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable Rect {
+  int left;
+  int top;
+  int right;
+  int bottom;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Smpte2086.aidl
new file mode 100644
index 0000000..5da36f6
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Smpte2086.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable Smpte2086 {
+  android.hardware.graphics.common.XyColor primaryRed;
+  android.hardware.graphics.common.XyColor primaryGreen;
+  android.hardware.graphics.common.XyColor primaryBlue;
+  android.hardware.graphics.common.XyColor whitePoint;
+  float maxLuminance;
+  float minLuminance;
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
new file mode 100644
index 0000000..34b53a2
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -0,0 +1,43 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@Backing(type="long") @VintfStability
+enum StandardMetadataType {
+  INVALID = 0,
+  BUFFER_ID = 1,
+  NAME = 2,
+  WIDTH = 3,
+  HEIGHT = 4,
+  LAYER_COUNT = 5,
+  PIXEL_FORMAT_REQUESTED = 6,
+  PIXEL_FORMAT_FOURCC = 7,
+  PIXEL_FORMAT_MODIFIER = 8,
+  USAGE = 9,
+  ALLOCATION_SIZE = 10,
+  PROTECTED_CONTENT = 11,
+  COMPRESSION = 12,
+  INTERLACED = 13,
+  CHROMA_SITING = 14,
+  PLANE_LAYOUTS = 15,
+  CROP = 16,
+  DATASPACE = 17,
+  BLEND_MODE = 18,
+  SMPTE2086 = 19,
+  CTA861_3 = 20,
+  SMPTE2094_40 = 21,
+}
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/XyColor.aidl
new file mode 100644
index 0000000..d96d0ac
--- /dev/null
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/XyColor.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.common;
+@VintfStability
+parcelable XyColor {
+  float x;
+  float y;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl b/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl
new file mode 100644
index 0000000..2428135
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl
@@ -0,0 +1,35 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * Blend modes, settable per layer.
+ */
+@VintfStability
+@Backing(type="int")
+enum BlendMode {
+    INVALID = 0,
+
+    /** colorOut = colorSrc */
+    NONE = 1,
+
+    /** colorOut = colorSrc + colorDst * (1 - alphaSrc) */
+    PREMULTIPLIED = 2,
+
+    /** colorOut = colorSrc * alphaSrc + colorDst * (1 - alphaSrc) */
+    COVERAGE = 3,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl b/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl
new file mode 100644
index 0000000..562a664
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/ChromaSiting.aidl
@@ -0,0 +1,39 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard chroma siting
+ */
+@VintfStability
+@Backing(type="long")
+enum ChromaSiting {
+    /* This format does not have chroma siting. */
+    NONE = 0,
+
+    /* This format has chroma siting but the type being used is unknown. */
+    UNKNOWN = 1,
+
+    /* Cb and Cr are sited interstitially, halfway between alternate luma samples.
+     * This is used by 4:2:0 for JPEG/JFIF, H.261, MPEG-1. */
+    SITED_INTERSTITIAL = 2,
+
+    /* Cb and Cr are horizontally sited coincident with a luma sample.
+     * Cb and Cr are vertically sited interstitially.
+     * This is used by 4:2:0 for MPEG-2 frame pictures. */
+    COSITED_HORIZONTAL = 3,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl b/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl
new file mode 100644
index 0000000..4cca1ba
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Compression.aidl
@@ -0,0 +1,30 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard compression strategies
+ */
+@VintfStability
+@Backing(type="long")
+enum Compression {
+    /* Represents all uncompressed buffers */
+    NONE = 0,
+
+    /* VESA Display Stream Compression (DSC) */
+    DISPLAY_STREAM_COMPRESSION = 1,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl
new file mode 100644
index 0000000..4fbc6b2
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl
@@ -0,0 +1,34 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * HDR static metadata extension as specified by CTA-861.3.
+ *
+ * This is an AIDL counterpart of the NDK struct `AHdrMetadata_cta861_3`.
+ */
+@VintfStability
+parcelable Cta861_3 {
+    /**
+     * Maximum content light level.
+     */
+    float maxContentLightLevel;
+    /**
+     * Maximum frame average light level.
+     */
+    float maxFrameAverageLightLevel;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
new file mode 100644
index 0000000..42cdd81
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
@@ -0,0 +1,677 @@
+/**
+ * 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.graphics.common;
+
+@VintfStability
+@Backing(type="int")
+enum Dataspace {
+    /**
+     * Default-assumption data space, when not explicitly specified.
+     *
+     * It is safest to assume the buffer is an image with sRGB primaries and
+     * encoding ranges, but the consumer and/or the producer of the data may
+     * simply be using defaults. No automatic gamma transform should be
+     * expected, except for a possible display gamma transform when drawn to a
+     * screen.
+     */
+    UNKNOWN = 0x0,
+
+    /**
+     * Arbitrary dataspace with manually defined characteristics.  Definition
+     * for colorspaces or other meaning must be communicated separately.
+     *
+     * This is used when specifying primaries, transfer characteristics,
+     * etc. separately.
+     *
+     * A typical use case is in video encoding parameters (e.g. for H.264),
+     * where a colorspace can have separately defined primaries, transfer
+     * characteristics, etc.
+     */
+    ARBITRARY = 0x1,
+
+    /**
+     * Color-description aspects
+     *
+     * The following aspects define various characteristics of the color
+     * specification. These represent bitfields, so that a data space value
+     * can specify each of them independently.
+     */
+
+    STANDARD_SHIFT = 16,
+
+    /**
+     * Standard aspect
+     *
+     * Defines the chromaticity coordinates of the source primaries in terms of
+     * the CIE 1931 definition of x and y specified in ISO 11664-1.
+     */
+    STANDARD_MASK = 63 << 16, // 63 << STANDARD_SHIFT = 0x3F
+
+    /**
+     * Chromacity coordinates are unknown or are determined by the application.
+     * Implementations shall use the following suggested standards:
+     *
+     * All YCbCr formats: BT709 if size is 720p or larger (since most video
+     *                    content is letterboxed this corresponds to width is
+     *                    1280 or greater, or height is 720 or greater).
+     *                    BT601_625 if size is smaller than 720p or is JPEG.
+     * All RGB formats:   BT709.
+     *
+     * For all other formats standard is undefined, and implementations should use
+     * an appropriate standard for the data represented.
+     */
+    STANDARD_UNSPECIFIED = 0 << 16, // STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.300   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT709 = 1 << 16,  // 1 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+     *  for RGB conversion from the one purely determined by the primaries
+     *  to minimize the color shift into RGB space that uses BT.709
+     *  primaries.
+     */
+    STANDARD_BT601_625 = 2 << 16, // 2 << STANDARD_SHIFT,
+
+    /**
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT601_625_UNADJUSTED = 3 << 16, // 3 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.310   0.595
+     *  blue            0.155   0.070
+     *  red             0.630   0.340
+     *  white (D65)     0.3127  0.3290
+     *
+     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+     *  for RGB conversion from the one purely determined by the primaries
+     *  to minimize the color shift into RGB space that uses BT.709
+     *  primaries.
+     */
+    STANDARD_BT601_525 = 4 << 16, // 4 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.310   0.595
+     *  blue            0.155   0.070
+     *  red             0.630   0.340
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+     * for RGB conversion (as in SMPTE 240M).
+     */
+    STANDARD_BT601_525_UNADJUSTED = 5 << 16, // 5 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.170   0.797
+     *  blue            0.131   0.046
+     *  red             0.708   0.292
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT2020 = 6 << 16, // 6 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.170   0.797
+     *  blue            0.131   0.046
+     *  red             0.708   0.292
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+     * for RGB conversion using the linear domain.
+     */
+    STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16, // 7 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x      y
+     *  green           0.21   0.71
+     *  blue            0.14   0.08
+     *  red             0.67   0.33
+     *  white (C)       0.310  0.316
+     *
+     * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT470M = 8 << 16, // 8 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.243   0.692
+     *  blue            0.145   0.049
+     *  red             0.681   0.319
+     *  white (C)       0.310   0.316
+     *
+     * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_FILM = 9 << 16, // 9 << STANDARD_SHIFT
+
+    /**
+     * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3)
+     * Primaries:       x       y
+     *  green           0.265   0.690
+     *  blue            0.150   0.060
+     *  red             0.680   0.320
+     *  white (D65)     0.3127  0.3290
+     */
+    STANDARD_DCI_P3 = 10 << 16, // 10 << STANDARD_SHIFT
+
+    /**
+     * Adobe RGB
+     * Primaries:       x       y
+     *  green           0.210   0.710
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     */
+    STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT
+
+    TRANSFER_SHIFT = 22,
+
+    /**
+     * Transfer aspect
+     *
+     * Transfer characteristics are the opto-electronic transfer characteristic
+     * at the source as a function of linear optical intensity (luminance).
+     *
+     * For digital signals, E corresponds to the recorded value. Normally, the
+     * transfer function is applied in RGB space to each of the R, G and B
+     * components independently. This may result in color shift that can be
+     * minized by applying the transfer function in Lab space only for the L
+     * component. Implementation may apply the transfer function in RGB space
+     * for all pixel formats if desired.
+     */
+
+    TRANSFER_MASK = 31 << 22, // 31 << TRANSFER_SHIFT = 0x1F
+
+    /**
+     * Transfer characteristics are unknown or are determined by the
+     * application.
+     *
+     * Implementations should use the following transfer functions:
+     *
+     * For YCbCr formats: use TRANSFER_SMPTE_170M
+     * For RGB formats: use TRANSFER_SRGB
+     *
+     * For all other formats transfer function is undefined, and implementations
+     * should use an appropriate standard for the data represented.
+     */
+    TRANSFER_UNSPECIFIED = 0 << 22, // 0 << TRANSFER_SHIFT
+
+    /**
+     * Transfer characteristic curve:
+     *  E = L
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_LINEAR = 1 << 22, // 1 << TRANSFER_SHIFT
+
+    /**
+     * Transfer characteristic curve:
+     *
+     * E = 1.055 * L^(1/2.4) - 0.055  for 0.0031308 <= L <= 1
+     *   = 12.92 * L                  for 0 <= L < 0.0031308
+     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *     E - corresponding electrical signal
+     */
+    TRANSFER_SRGB = 2 << 22, // 2 << TRANSFER_SHIFT
+
+    /**
+     * BT.601 525, BT.601 625, BT.709, BT.2020
+     *
+     * Transfer characteristic curve:
+     *  E = 1.099 * L ^ 0.45 - 0.099  for 0.018 <= L <= 1
+     *    = 4.500 * L                 for 0 <= L < 0.018
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_SMPTE_170M = 3 << 22, // 3 << TRANSFER_SHIFT
+
+    /**
+     * Assumed display gamma 2.2.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.2)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_GAMMA2_2 = 4 << 22, // 4 << TRANSFER_SHIFT
+
+    /**
+     *  display gamma 2.6.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.6)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_GAMMA2_6 = 5 << 22, // 5 << TRANSFER_SHIFT
+
+    /**
+     *  display gamma 2.8.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.8)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_GAMMA2_8 = 6 << 22, // 6 << TRANSFER_SHIFT
+
+    /**
+     * SMPTE ST 2084 (Dolby Perceptual Quantizer)
+     *
+     * Transfer characteristic curve:
+     *  E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
+     *  c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
+     *  c2 = 32 * 2413 / 4096 = 18.8515625
+     *  c3 = 32 * 2392 / 4096 = 18.6875
+     *  m = 128 * 2523 / 4096 = 78.84375
+     *  n = 0.25 * 2610 / 4096 = 0.1593017578125
+     *      L - luminance of image 0 <= L <= 1 for HDR colorimetry.
+     *          L = 1 corresponds to 10000 cd/m2
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_ST2084 = 7 << 22, // 7 << TRANSFER_SHIFT
+
+    /**
+     * ARIB STD-B67 Hybrid Log Gamma
+     *
+     * Transfer characteristic curve:
+     *  E = r * L^0.5                 for 0 <= L <= 1
+     *    = a * ln(L - b) + c         for 1 < L
+     *  a = 0.17883277
+     *  b = 0.28466892
+     *  c = 0.55991073
+     *  r = 0.5
+     *      L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
+     *          to reference white level of 100 cd/m2
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_HLG = 8 << 22, // 8 << TRANSFER_SHIFT
+
+    RANGE_SHIFT = 27,
+
+    /**
+     * Range aspect
+     *
+     * Defines the range of values corresponding to the unit range of 0-1.
+     * This is defined for YCbCr only, but can be expanded to RGB space.
+     */
+    RANGE_MASK = 7 << 27, // 7 << RANGE_SHIFT = 0x7
+
+    /**
+     * Range is unknown or are determined by the application.  Implementations
+     * shall use the following suggested ranges:
+     *
+     * All YCbCr formats: limited range.
+     * All RGB or RGBA formats (including RAW and Bayer): full range.
+     * All Y formats: full range
+     *
+     * For all other formats range is undefined, and implementations should use
+     * an appropriate range for the data represented.
+     */
+    RANGE_UNSPECIFIED = 0 << 27, // 0 << RANGE_SHIFT = 0x0
+
+    /**
+     * Full range uses all values for Y, Cb and Cr from
+     * 0 to 2^b-1, where b is the bit depth of the color format.
+     */
+    RANGE_FULL = 1 << 27, // 1 << RANGE_SHIFT = 0x8000000
+
+    /**
+     * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
+     * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
+     * the color format.
+     *
+     * E.g. For 8-bit-depth formats:
+     * Luma (Y) samples should range from 16 to 235, inclusive
+     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+     *
+     * For 10-bit-depth formats:
+     * Luma (Y) samples should range from 64 to 940, inclusive
+     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+     */
+    RANGE_LIMITED = 2 << 27, // 2 << RANGE_SHIFT = 0x10000000
+
+    /**
+     * Extended range is used for scRGB. Intended for use with
+     * floating point pixel formats. [0.0 - 1.0] is the standard
+     * sRGB space. Values outside the range 0.0 - 1.0 can encode
+     * color outside the sRGB gamut.
+     * Used to blend / merge multiple dataspaces on a single display.
+     */
+    RANGE_EXTENDED = 3 << 27, // 3 << RANGE_SHIFT = 0x18000000
+
+    /**
+     * sRGB linear encoding:
+     *
+     * The red, green, and blue components are stored in sRGB space, but
+     * are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are encoded using the full range ([0,255] for 8-bit) for all
+     * components.
+     */
+    SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
+
+
+    /**
+     * scRGB linear encoding:
+     *
+     * The red, green, and blue components are stored in extended sRGB space,
+     * but are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are floating point.
+     * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+     * Values beyond the range [0.0 - 1.0] would correspond to other colors
+     * spaces and/or HDR content.
+     */
+    SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
+
+
+    /**
+     * sRGB gamma encoding:
+     *
+     * The red, green and blue components are stored in sRGB space, and
+     * converted to linear space when read, using the SRGB transfer function
+     * for each of the R, G and B components. When written, the inverse
+     * transformation is performed.
+     *
+     * The alpha component, if present, is always stored in linear space and
+     * is left unmodified when read or written.
+     *
+     * Use full range and BT.709 standard.
+     */
+    SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
+
+
+    /**
+     * scRGB:
+     *
+     * The red, green, and blue components are stored in extended sRGB space,
+     * but are linear, not gamma-encoded.
+     * The RGB primaries and the white point are the same as BT.709.
+     *
+     * The values are floating point.
+     * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
+     * Values beyond the range [0.0 - 1.0] would correspond to other colors
+     * spaces and/or HDR content.
+     */
+    SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
+
+    /**
+     * YCbCr Colorspaces
+     * -----------------
+     *
+     * Primaries are given using (x,y) coordinates in the CIE 1931 definition
+     * of x and y specified by ISO 11664-1.
+     *
+     * Transfer characteristics are the opto-electronic transfer characteristic
+     * at the source as a function of linear optical intensity (luminance).
+     */
+
+    /**
+     * JPEG File Interchange Format (JFIF)
+     *
+     * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
+     *
+     * Use full range, SMPTE 170M transfer and BT.601_625 standard.
+     */
+    JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
+
+    /**
+     * ITU-R Recommendation 601 (BT.601) - 625-line
+     *
+     * Standard-definition television, 625 Lines (PAL)
+     *
+     * Use limited range, SMPTE 170M transfer and BT.601_625 standard.
+     */
+    BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+
+    /**
+     * ITU-R Recommendation 601 (BT.601) - 525-line
+     *
+     * Standard-definition television, 525 Lines (NTSC)
+     *
+     * Use limited range, SMPTE 170M transfer and BT.601_525 standard.
+     */
+    BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+    /**
+     * ITU-R Recommendation 709 (BT.709)
+     *
+     * High-definition television
+     *
+     * Use limited range, SMPTE 170M transfer and BT.709 standard.
+     */
+    BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+
+    /**
+     * SMPTE EG 432-1 and SMPTE RP 431-2.
+     *
+     * Digital Cinema DCI-P3
+     *
+     * Use full range, linear transfer and D65 DCI-P3 standard
+     */
+    DCI_P3_LINEAR = 10 << 16 | 1 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL
+
+
+    /**
+     * SMPTE EG 432-1 and SMPTE RP 431-2.
+     *
+     * Digital Cinema DCI-P3
+     *
+     * Use full range, gamma 2.6 transfer and D65 DCI-P3 standard
+     * Note: Application is responsible for gamma encoding the data as
+     * a 2.6 gamma encoding is not supported in HW.
+     */
+    DCI_P3 = 10 << 16 | 5 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_GAMMA2_6 | RANGE_FULL
+
+
+    /**
+     * Display P3
+     *
+     * Display P3 uses same primaries and white-point as DCI-P3
+     * linear transfer function makes this the same as DCI_P3_LINEAR.
+     */
+    DISPLAY_P3_LINEAR = 10 << 16 | 1 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL
+
+
+    /**
+     * Display P3
+     *
+     * Use same primaries and white-point as DCI-P3
+     * but sRGB transfer function.
+     */
+    DISPLAY_P3 = 10 << 16 | 2 << 22 | 1 << 27, // STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL
+
+
+    /**
+     * Adobe RGB
+     *
+     * Use full range, gamma 2.2 transfer and Adobe RGB primaries
+     * Note: Application is responsible for gamma encoding the data as
+     * a 2.2 gamma encoding is not supported in HW.
+     */
+    ADOBE_RGB = 11 << 16 | 4 << 22 | 1 << 27, // STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL
+
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, linear transfer and BT2020 standard
+     */
+    BT2020_LINEAR = 6 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_LINEAR | RANGE_FULL
+
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, SMPTE 170M transfer and BT2020 standard
+     */
+    BT2020 = 6 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard
+     */
+    BT2020_PQ = 6 << 16 | 7 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL
+
+
+    /**
+     * Data spaces for non-color formats
+     */
+
+    /**
+     * The buffer contains depth ranging measurements from a depth camera.
+     * This value is valid with formats:
+     *    HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement
+     *       and an associated confidence value. The 3 MSBs of the sample make
+     *       up the confidence value, and the low 13 LSBs of the sample make up
+     *       the depth measurement.
+     *       For the confidence section, 0 means 100% confidence, 1 means 0%
+     *       confidence. The mapping to a linear float confidence value between
+     *       0.f and 1.f can be obtained with
+     *         float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f;
+     *       The depth measurement can be extracted simply with
+     *         uint16_t range = (depthSample & 0x1FFF);
+     *    HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as
+     *       a variable-length float (x,y,z, confidence) coordinate point list.
+     *       The point cloud will be represented with the android_depth_points
+     *       structure.
+     */
+    DEPTH = 0x1000,
+
+    /**
+     * The buffer contains sensor events from sensor direct report.
+     * This value is valid with formats:
+     *    HAL_PIXEL_FORMAT_BLOB: an array of sensor event structure that forms
+     *       a lock free queue. Format of sensor event structure is specified
+     *       in Sensors HAL.
+     */
+    SENSOR = 0x1001,
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use limited range, SMPTE 170M transfer and BT2020 standard
+     */
+    BT2020_ITU = 6 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+    /**
+     * ITU-R Recommendation 2100 (BT.2100)
+     *
+     * High dynamic range television
+     *
+     * Use limited/full range, PQ/HLG transfer, and BT2020 standard
+     * limited range is the preferred / normative definition for BT.2100
+     */
+    BT2020_ITU_PQ = 6 << 16 | 7 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED
+    BT2020_ITU_HLG = 6 << 16 | 8 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED
+    BT2020_HLG = 6 << 16 | 8 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_FULL
+
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, sRGB transfer and BT2020 standard
+     */
+    DISPLAY_BT2020 = 6 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SRGB | RANGE_FULL
+
+    /**
+     * ISO 16684-1:2011(E)
+     *
+     * Embedded depth metadata following the dynamic depth specification.
+     */
+    DYNAMIC_DEPTH = 0x1002,
+
+    /**
+     * JPEG APP segments format as specified by JEIDA spec
+     *
+     * The buffer must only contain APP1 (Application Marker) segment followed
+     * by zero or more APPn segments, as is specified by JEITA CP-3451C section 4.5.4.
+     * The APP1 segment optionally contains a thumbnail. The buffer will not
+     * contain main compressed image.
+     *
+     * This value is valid with formats:
+     *    HAL_PIXEL_FORMAT_BLOB: JPEG APP segments optionally containing thumbnail image
+     * in APP1. BLOB buffer with this dataspace is output by HAL, and used by
+     * camera framework to encode into a HEIC image.
+     */
+    JPEG_APP_SEGMENTS = 0x1003,
+
+    /**
+     * ISO/IEC 23008-12
+     *
+     * High Efficiency Image File Format (HEIF)
+     *
+     * This value is valid with formats:
+     *    HAL_PIXEL_FORMAT_BLOB: A HEIC image encoded by HEIC or HEVC encoder
+     * according to ISO/IEC 23008-12.
+     */
+    HEIF = 0x1004,
+
+    /**
+     * ITU-R Recommendation 709 (BT.709)
+     *
+     * High-definition television
+     *
+     * Use full range, SMPTE 170M transfer and BT.709 standard.
+     */
+    BT709_FULL_RANGE = 1 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_FULL
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl
new file mode 100644
index 0000000..495693c
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/ExtendableType.aidl
@@ -0,0 +1,52 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * This struct is used for types that are commonly extended by vendors. For example, buffer
+ * compression is typically SoC specific. It is not possible for Android to define every possible
+ * proprietary vendor compression strategy. Instead, compression is represented using this
+ * ExtendableType that can support standard compression strategies while still allowing
+ * every vendor to easily add their own non-standard definitions.
+ */
+@VintfStability
+parcelable ExtendableType {
+    /**
+     * Name of the stable aidl interface whose value is stored in this structure.
+     *
+     * For standard types, the "name" field will be set to the stable aidl name of the type such as
+     * "android.hardware.graphics.common.Compression".
+     *
+     * For custom vendor types, the "name" field will be set to the name of the custom
+     * @VendorStability vendor AIDL interface such as
+     * "vendor.mycompanyname.graphics.common.Compression". The name of the vendor extension should
+     * contain the name of the owner of the extension. Including the company
+     * name in the "name" field prevents type collisions between different vendors.
+     */
+    @utf8InCpp String name;
+
+    /**
+     * Enum value of the from the stable aidl interface
+     *
+     * For standard types, the "value" field will be set to an enum value from that stable aidl
+     * type such as "NONE".
+     *
+     * For vendor types, the "value" field should be set to the enum value from the custom
+     * @VendorStability vendor AIDL interface extended type such as "MY_COMPRESSION_TYPE1".
+     */
+    long value = 0;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl b/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl
new file mode 100644
index 0000000..a3f1baa
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Interlaced.aidl
@@ -0,0 +1,35 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard interlaced strategies
+ */
+@VintfStability
+@Backing(type="long")
+enum Interlaced {
+    /* The buffer is not interlaced. */
+    NONE = 0,
+
+    /* The buffer's planes are interlaced horizontally. The height of each interlaced plane is
+     * 1/2 the height of the buffer's height. */
+    TOP_BOTTOM = 1,
+
+    /* The buffer's planes are interlaced vertically. The width of each interlaced plane is
+     * 1/2 the width of the buffer's width. */
+    RIGHT_LEFT = 2,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
index 4942462..4e0c5ef 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
@@ -403,10 +403,6 @@
      *   cr_offset = y_size
      *   cb_offset = y_size + c_size
      *
-     * This range is reserved for vendor extensions. Formats in this range
-     * must support BufferUsage::GPU_TEXTURE. Clients must assume they do not
-     * have an alpha component.
-     *
      * This format must be accepted by the allocator when used with the
      * following usage flags:
      *
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
new file mode 100644
index 0000000..b329cb2
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
@@ -0,0 +1,111 @@
+/**
+ * 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.graphics.common;
+
+import android.hardware.graphics.common.PlaneLayoutComponent;
+import android.hardware.graphics.common.Rect;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe the plane layout of a buffer.
+ *
+ * PlaneLayout uses the following definitions:
+ *
+ * - Component - a component is one channel of a pixel. For example, an RGBA format has
+ *      four components: R, G, B and A.
+ * - Sample - a sample is comprised of all the components in a given plane. For example,
+ *      a buffer with one Y plane and one CbCr plane has one plane with a sample of Y
+ *      and one plane with a sample of CbCr.
+ * - Pixel - a pixel is comprised of all the (non-metadata/raw) components in buffer across
+ *      all planes. For example, a buffer with a plane of Y and a plane of CbCr has a pixel
+ *      of YCbCr.
+ */
+
+@VintfStability
+parcelable PlaneLayout {
+    /**
+     * An list of plane layout components. This list of components should include
+     * every component in this plane. For example, a CbCr plane should return a
+     * vector of size two with one PlaneLayoutComponent for Cb and one for Cr.
+     */
+    PlaneLayoutComponent[] components;
+
+    /**
+     * Offset to the first byte of the plane (in bytes), from the start of the allocation.
+     */
+    long offsetInBytes;
+
+    /**
+     * Bits per sample increment (aka column increment): describes the distance
+     * in bits from one sample to the next sample (to the right) on the same row for the
+     * the component plane.
+     *
+     * The default value is 0. Return the default value if the increment is undefined, unknown,
+     * or variable.
+     *
+     * This can be negative. A negative increment indicates that the samples are read from
+     * right to left.
+     */
+    long sampleIncrementInBits;
+
+    /**
+     * Horizontal stride: number of bytes between two vertically adjacent
+     * samples in given plane. This can be mathematically described by:
+     *
+     * strideInBytes = ALIGN(widthInSamples * bps / 8, alignment)
+     *
+     * where,
+     *
+     * bps: average bits per sample
+     * alignment (in bytes): dependent upon pixel format and usage
+     *
+     * strideInBytes can contain additional padding beyond the widthInSamples.
+     *
+     * The default value is 0. Return the default value if the stride is undefined, unknown,
+     * or variable.
+     *
+     * This can be negative. A negative stride indicates that the rows are read from
+     * bottom to top.
+     */
+    long strideInBytes;
+
+    /**
+     * Dimensions of plane (in samples).
+     *
+     * This is the number of samples in the plane, even if subsampled.
+     *
+     * See 'strideInBytes' for relationship between strideInBytes and widthInSamples.
+     */
+    long widthInSamples;
+    long heightInSamples;
+
+    /**
+     * Can be used to get the total size in bytes of any memory used by the plane
+     * including extra padding. This should not include any extra metadata used to describe the
+     * plane.
+     */
+    long totalSizeInBytes;
+
+    /**
+     * Horizontal and vertical subsampling. Must be a positive power of 2. A value of 1
+     * indicates no subsampling.
+     *
+     * These fields indicate the number of horizontally or vertically adjacent pixels that use
+     * the same pixel data.
+     */
+    long horizontalSubsampling;
+    long verticalSubsampling;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
new file mode 100644
index 0000000..c04cef0
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
@@ -0,0 +1,67 @@
+/**
+ * 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.graphics.common;
+
+import android.hardware.graphics.common.ExtendableType;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe the type and location of a component in a
+ * buffer's plane.
+ *
+ * PlaneLayoutComponent uses the following definitions:
+ *
+ * - Component - a component is one channel of a pixel. For example, an RGBA format has
+ *      four components: R, G, B and A.
+ * - Sample - a sample is comprised of all the components in a given plane. For example,
+ *      a buffer with one Y plane and one CbCr plane has one plane with a sample of Y
+ *      and one plane with a sample of CbCr.
+ * - Pixel - a pixel is comprised of all the (non-metadata/raw) components in buffer across
+ *      all planes. For example, a buffer with a plane of Y and a plane of CbCr has a pixel
+ *      of YCbCr.
+ */
+
+@VintfStability
+parcelable PlaneLayoutComponent {
+    /**
+     * The type of this plane layout component.
+     *
+     * android.hardware.graphics.common.PlaneLayoutComponentType defines the standard
+     * plane layout component types. Vendors may extend this type to include any
+     * non-standard plane layout component types. For instructions on how to
+     * create a vendor extension, refer to ExtendableType.aidl.
+     */
+    ExtendableType type;
+
+    /**
+     * Offset in bits to the first instance of this component in the plane.
+     * This is relative to the plane's offset (PlaneLayout::offset).
+     *
+     * If the offset cannot be described using a int64_t, this should be set to -1.
+     * For example, if the plane is compressed and the offset is not defined or
+     * relevant, return -1.
+     */
+    long offsetInBits;
+
+    /**
+     * The number of bits used per component in the plane.
+     *
+     * If the plane layout component cannot be described using componentSizeInBits, this
+     * should be set to -1. For example, if the component varies in size throughout
+     * the plane, return -1.
+     */
+    long sizeInBits;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
new file mode 100644
index 0000000..ce08396
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
@@ -0,0 +1,49 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard plane layout component types
+ *
+ * The enum values have been taken directly from gralloc1's android_flex_component for compatiblity
+ * reasons. However, unlike gralloc1's android_flex_component, this field is NOT a bit field.
+ * A plane's components should NOT be expressed by bitwise OR-ing different
+ * PlaneLayoutComponentTypes together.
+ */
+@VintfStability
+@Backing(type="long")
+enum PlaneLayoutComponentType {
+    /* Luma */
+    Y = 1 << 0,
+    /* Chroma blue */
+    CB = 1 << 1,
+    /* Chroma red */
+    CR = 1 << 2,
+
+    /* Red */
+    R = 1 << 10,
+    /* Green */
+    G = 1 << 11,
+    /* Blue */
+    B = 1 << 12,
+
+    /* Raw */
+    RAW = 1 << 20,
+
+    /* Alpha */
+    A = 1 << 30,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl b/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
new file mode 100644
index 0000000..1a3bc11
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl
@@ -0,0 +1,29 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * General purpose definition of a rectangle.
+ */
+
+@VintfStability
+parcelable Rect {
+    int left;
+    int top;
+    int right;
+    int bottom;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl
new file mode 100644
index 0000000..60614cd
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl
@@ -0,0 +1,51 @@
+/**
+ * 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.graphics.common;
+import android.hardware.graphics.common.XyColor;
+
+/**
+ * Mastering display metadata as specified by SMPTE ST 2086.
+ *
+ * This is an AIDL counterpart of the NDK struct `AHdrMetadata_smpte2086`.
+ */
+@VintfStability
+parcelable Smpte2086 {
+    /**
+     * CIE XYZ chromaticity for red in the RGB primaries.
+     */
+    XyColor primaryRed;
+    /**
+     * CIE XYZ chromaticity for green in the RGB primaries.
+     */
+    XyColor primaryGreen;
+    /**
+     * CIE XYZ chromaticity for blue in the RGB primaries.
+     */
+    XyColor primaryBlue;
+    /**
+     * CIE XYZ chromaticity for the white point.
+     */
+    XyColor whitePoint;
+    /**
+     * Maximum luminance in candelas per square meter.
+     */
+    float maxLuminance;
+    /**
+     * Minimum luminance in candelas per square meter.
+     */
+    float minLuminance;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
new file mode 100644
index 0000000..af6045e
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -0,0 +1,356 @@
+/**
+ * Copyright (c) 2019,libgralloctypes_helper The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.graphics.common;
+
+/**
+ * Used by IAllocator/IMapper (gralloc) to describe standard metadata types.
+ *
+ * This is an enum that defines the common types of gralloc 4 buffer metadata. The comments for
+ * each enum include a description of the metadata that is associated with the type.
+ *
+ * IMapper@4.x must support getting the following standard buffer metadata types. IMapper@4.x may
+ * support setting these standard buffer metadata types as well.
+ *
+ * When encoding these StandardMetadataTypes into a byte stream, the associated MetadataType is
+ * is first encoded followed by the StandardMetadataType value. The MetadataType is encoded by
+ * writing the length of MetadataType.name using 8 bytes in little endian, followed by a char
+ * array of MetadataType.name's characters. The char array is not null terminated. Finally,
+ * MetadataType.value is represented by 8 bytes written in little endian.
+ *
+ * The StandardMetadataType encode/decode support library can be found in:
+ * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
+ */
+@VintfStability
+@Backing(type="long")
+enum StandardMetadataType {
+    INVALID = 0,
+
+    /**
+     * Can be used to get the random ID of the buffer. This ID should be psuedorandom with
+     * sufficient entropy.
+     *
+     * This ID should only be used for debugging purposes. It cannot be used as a basis for any
+     * control flows.
+     *
+     * The buffer ID is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The buffer ID is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    BUFFER_ID = 1,
+
+    /**
+     * Can be used to get the name passed in by the client at allocation time in the
+     * BufferDescriptorInfo.
+     *
+     * The buffer name is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The buffer name is a string.
+     *
+     * When it is encoded into a byte stream, the length of the string is written using 8 bytes in
+     * little endian. It is followed by a char array of the string's
+     * characters. The array is not null-terminated.
+     */
+    NAME = 2,
+
+    /**
+     * Can be used to get the number of elements per buffer row requested at allocation time in
+     * the BufferDescriptorInfo.
+     *
+     * The width is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The width is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    WIDTH = 3,
+
+    /**
+     * Can be used to get the number of elements per buffer column requested at allocation time in
+     * the BufferDescriptorInfo.
+     *
+     * The height is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The height is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    HEIGHT = 4,
+
+    /**
+     * Can be used to get the number of layers requested at allocation time in the
+     * BufferDescriptorInfo.
+     *
+     * The layer count is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The layer count is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    LAYER_COUNT = 5,
+
+    /**
+     * Can be used to get the buffer format requested at allocation time in the
+     * BufferDescriptorInfo.
+     *
+     * The requested pixel format is determined at allocation time and should not change during
+     * the lifetime of the buffer.
+     *
+     * The requested pixel format is a android.hardware.graphics.common@1.2::PixelFormat.
+     *
+     * 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.
+     */
+    PIXEL_FORMAT_REQUESTED = 6,
+
+    /**
+     * Can be used to get the fourcc code for the format. Fourcc codes are standard across all
+     * devices of the same kernel version. Fourcc codes must follow the Linux definition of a
+     * fourcc format found in: include/uapi/drm/drm_fourcc.h.
+     *
+     * The pixel format fourcc code is represented by a uint32_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 4 bytes written in little endian.
+     */
+    PIXEL_FORMAT_FOURCC = 7,
+
+    /**
+     * Can be used to get the modifier for the format. Together fourcc and modifier describe the
+     * real pixel format. Each fourcc and modifier pair is unique and must fully define the format
+     * and layout of the buffer. Modifiers can change any property of the buffer. Modifiers must
+     * follow the Linux definition of a modifier found in: include/uapi/drm/drm_fourcc.h.
+     *
+     * The pixel format modifier is represented by a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    PIXEL_FORMAT_MODIFIER = 8,
+
+    /**
+     * Can be used to get the usage requested at allocation time in the BufferDescriptorInfo.
+     *
+     * The usage is determined at allocation time and should not change during the lifetime
+     * of the buffer.
+     *
+     * The usage is a uint64_t bit field of android.hardware.graphics.common@1.2::BufferUsage's.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    USAGE = 9,
+
+    /**
+     * Can be used to get the total size in bytes of any memory used by the buffer including its
+     * metadata and extra padding. This is the total number of bytes used by the buffer allocation.
+     *
+     * The allocation size is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    ALLOCATION_SIZE = 10,
+
+    /**
+     * Can be used to get if a buffer has protected content. If the buffer does not have protected
+     * content, this should return 0. If a buffer has protected content, this should return 1.
+     *
+     * In future versions, this field will be extended to expose more information about the type
+     * of protected content in the buffer.
+     *
+     * The protected content is a uint64_t.
+     *
+     * When it is encoded into a byte stream, it is represented by 8 bytes written in little endian.
+     */
+    PROTECTED_CONTENT = 11,
+
+    /**
+     * Can be used to get the compression strategy of the buffer. If the device has more than one
+     * compression strategy, it should have different unique values for each compression
+     * strategy.
+     *
+     * Compression is a stable aidl android.hardware.graphics.common.ExtendableType.
+     *
+     * android.hardware.graphics.common.Compression defines the standard compression
+     * strategies. Vendors may extend this type to include any compression strategies.
+     *
+     * When it is encoded into a byte stream, the length of the name field string is written using
+     * 8 bytes in little endian. It is followed by a char array of the string's
+     * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+     * in little endian.
+     */
+    COMPRESSION = 12,
+
+    /**
+     * Can be used to get how the buffer's planes are interlaced.
+     *
+     * Interlaced is a stable aidl android.hardware.graphics.common.ExtendableType.
+     *
+     * android.hardware.graphics.common.Interlaced defines the standard interlaced
+     * strategies. Vendors may extend this type to include any non-standard interlaced
+     * strategies.
+     *
+     * When it is encoded into a byte stream, the length of the name field string is written using
+     * 8 bytes in little endian. It is followed by a char array of the string's
+     * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+     * in little endian.
+     */
+    INTERLACED = 13,
+
+    /**
+     * Can be used to get the chroma siting of a buffer.
+     *
+     * Chroma siting is a stable aidl android.hardware.graphics.common.ExtendableType.
+     *
+     * android.hardware.graphics.common.ChromaSiting defines the standard chroma
+     * sitings. Vendors may extend this type to include any non-standard chroma sitings.
+     *
+     * When it is encoded into a byte stream, the length of the name field string is written using
+     * 8 bytes in little endian. It is followed by a char array of the string's
+     * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+     * in little endian.
+     */
+    CHROMA_SITING = 14,
+
+    /**
+     * Can be used to get the PlaneLayout(s) of the buffer. There should be one PlaneLayout per
+     * plane in the buffer. For example if the buffer only has one plane, only one PlaneLayout
+     * should be returned.
+     *
+     * If the buffer has planes interlaced through time, the returned PlaneLayout structs should be
+     * ordered by time. The nth PlaneLayout should be from the same time or earlier than the
+     * n+1 PlaneLayout.
+     *
+     * The plane layout is a list of stable aidl android.hardware.graphics.common.PlaneLayout's.
+     *
+     * When it is encoded into a byte stream, the total number of PlaneLayouts is written using
+     * 8 bytes in little endian. It is followed by each PlaneLayout.
+     *
+     * To encode a PlaneLayout, write the length of its PlaneLayoutComponent[] components
+     * field as 8 bytes in little endian and then encode each of its components. Finally, write the
+     * following fields in this order each as 8 bytes in little endian: offsetInBytes,
+     * sampleIncrementInBits, strideInBytes, widthInSamples, totalSizeInBytes,
+     * horizontalSubsampling, verticalSubsampling.
+     *
+     * To encode a PlaneLayoutComponent, encode its PlaneLayoutComponentType type field. Next
+     * encode offsetInBits followed by sizeInBits each as 8 bytes in little endian.
+     *
+     * To encode a PlaneLayoutComponentType, write the length of the name field string as
+     * 8 bytes in little endian. It is followed by a char array of the string's
+     * characters. The array is not null-terminated. Finally the value field is written as 8 bytes
+     * in little endian.
+     */
+    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.
+     *
+     * The default dataspace is Dataspace::UNKNOWN. If this dataspace is set to any valid value
+     * other than Dataspace::UNKNOWN, this dataspace overrides all other dataspaces. For example,
+     * if the buffer has Dataspace::DISPLAY_P3 and it is being displayed on a composer Layer that
+     * is Dataspace::sRGB, the buffer should be treated as a DISPLAY_P3 buffer.
+     *
+     * The dataspace is a stable aidl android.hardware.graphics.common.Dataspace.
+     *
+     * 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 = 17,
+
+    /**
+     * Can be used to get or set the BlendMode. The framework may attempt to set this value.
+     *
+     * The default blend mode is INVALID. If the BlendMode is set to any
+     * valid value other than INVALID, this BlendMode overrides all other
+     * blend modes. For a longer description of this behavior see MetadataType::DATASPACE.
+     *
+     * The blend mode is a stable aidl android.hardware.graphics.common.BlendMode.
+     *
+     * 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 = 18,
+
+    /**
+     * Can be used to get or set static HDR metadata specified by SMPTE ST 2086.
+     *
+     * This metadata is a stable aidl android.hardware.graphics.common.Smpte2086.
+     *
+     * This is not used in tone mapping until it has been set for the first time.
+     *
+     * When it is encoded into a byte stream, each float member is represented by 4 bytes written in
+     * 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 = 19,
+
+    /**
+     * Can be used to get or set static HDR metadata specified by CTA 861.3.
+     *
+     * This metadata is a stable aidl android.hardware.graphics.common.Cta861_3.
+     *
+     * This is not used in tone mapping until it has been set for the first time.
+     *
+     * When it is encoded into a byte stream, each float member is represented by 4 bytes written in
+     * 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 = 20,
+
+    /**
+     * Can be used to get or set dynamic HDR metadata specified by SMPTE ST 2094-40:2016.
+     *
+     * This metadata is uint8_t byte array.
+     *
+     * This is not used in tone mapping until it has been set for the first time.
+     *
+     * When it is encoded into a byte stream, the length of the HDR metadata byte array is written
+     * 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 = 21,
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl
new file mode 100644
index 0000000..9571273
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl
@@ -0,0 +1,30 @@
+/**
+ * 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.graphics.common;
+
+/**
+ * Chromaticity based on 2 parameters.
+ *
+ * This is an AIDL counterpart of the NDK struct `AColor_xy`.
+ *
+ * @note This can be used to represent any 2-dimensional chromaticity.
+ */
+@VintfStability
+parcelable XyColor {
+    float x;
+    float y;
+}
diff --git a/graphics/composer/2.1/default/Android.bp b/graphics/composer/2.1/default/Android.bp
index 6157719..533687b 100644
--- a/graphics/composer/2.1/default/Android.bp
+++ b/graphics/composer/2.1/default/Android.bp
@@ -9,8 +9,7 @@
     ],
     shared_libs: [
         "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.composer@2.1-resources",
         "libbase",
         "libcutils",
         "libfmq",
diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
index ebac2e0..499d3b9 100644
--- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
+++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
@@ -403,6 +403,11 @@
     }
 
    protected:
+     template <typename T>
+     void beginCommand(T command, uint16_t length) {
+         beginCommandBase(static_cast<IComposerClient::Command>(command), length);
+     }
+
     void setClientTargetInternal(uint32_t slot, const native_handle_t* target, int acquireFence,
                                  int32_t dataspace,
                                  const std::vector<IComposerClient::Rect>& damage) {
@@ -429,7 +434,7 @@
         endCommand();
     }
 
-    void beginCommand(IComposerClient::Command command, uint16_t length) {
+    void beginCommandBase(IComposerClient::Command command, uint16_t length) {
         if (mCommandEnd) {
             LOG_FATAL("endCommand was not called before command 0x%x", command);
         }
@@ -621,9 +626,15 @@
     }
 
    protected:
+     template <typename T>
+     bool beginCommand(T* outCommand, uint16_t* outLength) {
+         return beginCommandBase(reinterpret_cast<IComposerClient::Command*>(outCommand),
+                                 outLength);
+     }
+
     bool isEmpty() const { return (mDataRead >= mDataSize); }
 
-    bool beginCommand(IComposerClient::Command* outCommand, uint16_t* outLength) {
+    bool beginCommandBase(IComposerClient::Command* outCommand, uint16_t* outLength) {
         if (mCommandEnd) {
             LOG_FATAL("endCommand was not called for last command");
         }
diff --git a/graphics/composer/2.1/utils/hal/Android.bp b/graphics/composer/2.1/utils/hal/Android.bp
index 7a501fc..ea3666d 100644
--- a/graphics/composer/2.1/utils/hal/Android.bp
+++ b/graphics/composer/2.1/utils/hal/Android.bp
@@ -19,14 +19,12 @@
     vendor_available: true,
     shared_libs: [
         "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.composer@2.1-resources",
         "libhardware", // TODO remove hwcomposer2.h dependency
     ],
     export_shared_lib_headers: [
         "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.composer@2.1-resources",
         "libhardware",
     ],
     header_libs: [
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
index 90d9b98..4b8c6bb 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
@@ -67,6 +67,14 @@
             }
         }
 
+        // we do not have HWC2_CAPABILITY_SKIP_VALIDATE defined in
+        // IComposer::Capability.  However, this is defined in hwcomposer2.h,
+        // so if the device returns it, add it manually to be returned to the
+        // client
+        if (mHal->hasCapability(HWC2_CAPABILITY_SKIP_VALIDATE)) {
+            caps.push_back(static_cast<IComposer::Capability>(HWC2_CAPABILITY_SKIP_VALIDATE));
+        }
+
         hidl_vec<IComposer::Capability> caps_reply;
         caps_reply.setToExternal(caps.data(), caps.size());
         hidl_cb(caps_reply);
@@ -80,8 +88,7 @@
 
     Return<void> createClient(IComposer::createClient_cb hidl_cb) override {
         std::unique_lock<std::mutex> lock(mClientMutex);
-        bool destroyed = waitForClientDestroyedLocked(lock);
-        if (!destroyed) {
+        if (!waitForClientDestroyedLocked(lock)) {
             hidl_cb(Error::NO_RESOURCES, nullptr);
             return Void();
         }
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
index 095189f..47ead41 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
@@ -27,7 +27,7 @@
 #include <android/hardware/graphics/composer/2.1/IComposerClient.h>
 #include <composer-hal/2.1/ComposerCommandEngine.h>
 #include <composer-hal/2.1/ComposerHal.h>
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
 #include <log/log.h>
 
 namespace android {
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
index d87110a..ab67eb1 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
@@ -24,7 +24,7 @@
 
 #include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
 #include <composer-hal/2.1/ComposerHal.h>
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
 // TODO remove hwcomposer_defs.h dependency
 #include <hardware/hwcomposer_defs.h>
 #include <log/log.h>
@@ -39,8 +39,10 @@
 // TODO own a CommandReaderBase rather than subclassing
 class ComposerCommandEngine : protected CommandReaderBase {
    public:
-    ComposerCommandEngine(ComposerHal* hal, ComposerResources* resources)
-        : mHal(hal), mResources(resources) {}
+     ComposerCommandEngine(ComposerHal* hal, ComposerResources* resources)
+         : mHal(hal), mResources(resources) {
+         mWriter = createCommandWriter(kWriterInitialSize);
+     }
 
     virtual ~ComposerCommandEngine() = default;
 
@@ -74,16 +76,16 @@
             return Error::BAD_PARAMETER;
         }
 
-        return mWriter.writeQueue(outQueueChanged, outCommandLength, outCommandHandles)
-                   ? Error::NONE
-                   : Error::NO_RESOURCES;
+        return mWriter->writeQueue(outQueueChanged, outCommandLength, outCommandHandles)
+                       ? Error::NONE
+                       : Error::NO_RESOURCES;
     }
 
-    const MQDescriptorSync<uint32_t>* getOutputMQDescriptor() { return mWriter.getMQDescriptor(); }
+    const MQDescriptorSync<uint32_t>* getOutputMQDescriptor() { return mWriter->getMQDescriptor(); }
 
     void reset() {
         CommandReaderBase::reset();
-        mWriter.reset();
+        mWriter->reset();
     }
 
    protected:
@@ -140,13 +142,36 @@
         }
     }
 
+    virtual std::unique_ptr<CommandWriterBase> createCommandWriter(size_t writerInitialSize) {
+        return std::make_unique<CommandWriterBase>(writerInitialSize);
+    }
+
+    virtual Error executeValidateDisplayInternal() {
+        std::vector<Layer> changedLayers;
+        std::vector<IComposerClient::Composition> compositionTypes;
+        uint32_t displayRequestMask = 0x0;
+        std::vector<Layer> requestedLayers;
+        std::vector<uint32_t> requestMasks;
+
+        auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
+                                         &displayRequestMask, &requestedLayers, &requestMasks);
+        mResources->setDisplayMustValidateState(mCurrentDisplay, false);
+        if (err == Error::NONE) {
+            mWriter->setChangedCompositionTypes(changedLayers, compositionTypes);
+            mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
+        } else {
+            mWriter->setError(getCommandLoc(), err);
+        }
+        return err;
+    }
+
     bool executeSelectDisplay(uint16_t length) {
         if (length != CommandWriterBase::kSelectDisplayLength) {
             return false;
         }
 
         mCurrentDisplay = read64();
-        mWriter.selectDisplay(mCurrentDisplay);
+        mWriter->selectDisplay(mCurrentDisplay);
 
         return true;
     }
@@ -174,7 +199,7 @@
 
         auto err = mHal->setColorTransform(mCurrentDisplay, matrix, transform);
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -195,7 +220,7 @@
         bool closeFence = true;
 
         const native_handle_t* clientTarget;
-        ComposerResources::ReplacedBufferHandle replacedClientTarget;
+        ComposerResources::ReplacedHandle replacedClientTarget(true);
         auto err = mResources->getDisplayClientTarget(mCurrentDisplay, slot, useCache, rawHandle,
                                                       &clientTarget, &replacedClientTarget);
         if (err == Error::NONE) {
@@ -208,7 +233,7 @@
             close(fence);
         }
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -226,7 +251,7 @@
         bool closeFence = true;
 
         const native_handle_t* outputBuffer;
-        ComposerResources::ReplacedBufferHandle replacedOutputBuffer;
+        ComposerResources::ReplacedHandle replacedOutputBuffer(true);
         auto err = mResources->getDisplayOutputBuffer(mCurrentDisplay, slot, useCache, rawhandle,
                                                       &outputBuffer, &replacedOutputBuffer);
         if (err == Error::NONE) {
@@ -239,7 +264,7 @@
             close(fence);
         }
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -249,23 +274,7 @@
         if (length != CommandWriterBase::kValidateDisplayLength) {
             return false;
         }
-
-        std::vector<Layer> changedLayers;
-        std::vector<IComposerClient::Composition> compositionTypes;
-        uint32_t displayRequestMask = 0x0;
-        std::vector<Layer> requestedLayers;
-        std::vector<uint32_t> requestMasks;
-
-        auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
-                                         &displayRequestMask, &requestedLayers, &requestMasks);
-        mResources->setDisplayMustValidateState(mCurrentDisplay, false);
-        if (err == Error::NONE) {
-            mWriter.setChangedCompositionTypes(changedLayers, compositionTypes);
-            mWriter.setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
-        } else {
-            mWriter.setError(getCommandLoc(), err);
-        }
-
+        executeValidateDisplayInternal();
         return true;
     }
 
@@ -283,29 +292,17 @@
                            ? Error::NOT_VALIDATED
                            : mHal->presentDisplay(mCurrentDisplay, &presentFence, &layers, &fences);
             if (err == Error::NONE) {
-                mWriter.setPresentOrValidateResult(1);
-                mWriter.setPresentFence(presentFence);
-                mWriter.setReleaseFences(layers, fences);
+                mWriter->setPresentOrValidateResult(1);
+                mWriter->setPresentFence(presentFence);
+                mWriter->setReleaseFences(layers, fences);
                 return true;
             }
         }
 
         // Present has failed. We need to fallback to validate
-        std::vector<Layer> changedLayers;
-        std::vector<IComposerClient::Composition> compositionTypes;
-        uint32_t displayRequestMask = 0x0;
-        std::vector<Layer> requestedLayers;
-        std::vector<uint32_t> requestMasks;
-
-        auto err = mHal->validateDisplay(mCurrentDisplay, &changedLayers, &compositionTypes,
-                                         &displayRequestMask, &requestedLayers, &requestMasks);
-        mResources->setDisplayMustValidateState(mCurrentDisplay, false);
+        auto err = executeValidateDisplayInternal();
         if (err == Error::NONE) {
-            mWriter.setPresentOrValidateResult(0);
-            mWriter.setChangedCompositionTypes(changedLayers, compositionTypes);
-            mWriter.setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
-        } else {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setPresentOrValidateResult(0);
         }
 
         return true;
@@ -318,7 +315,7 @@
 
         auto err = mHal->acceptDisplayChanges(mCurrentDisplay);
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -334,10 +331,10 @@
         std::vector<int> fences;
         auto err = mHal->presentDisplay(mCurrentDisplay, &presentFence, &layers, &fences);
         if (err == Error::NONE) {
-            mWriter.setPresentFence(presentFence);
-            mWriter.setReleaseFences(layers, fences);
+            mWriter->setPresentFence(presentFence);
+            mWriter->setReleaseFences(layers, fences);
         } else {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -351,7 +348,7 @@
         auto err = mHal->setLayerCursorPosition(mCurrentDisplay, mCurrentLayer, readSigned(),
                                                 readSigned());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -369,7 +366,7 @@
         bool closeFence = true;
 
         const native_handle_t* buffer;
-        ComposerResources::ReplacedBufferHandle replacedBuffer;
+        ComposerResources::ReplacedHandle replacedBuffer(true);
         auto err = mResources->getLayerBuffer(mCurrentDisplay, mCurrentLayer, slot, useCache,
                                               rawHandle, &buffer, &replacedBuffer);
         if (err == Error::NONE) {
@@ -382,7 +379,7 @@
             close(fence);
         }
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -397,7 +394,7 @@
         auto damage = readRegion(length / 4);
         auto err = mHal->setLayerSurfaceDamage(mCurrentDisplay, mCurrentLayer, damage);
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -410,7 +407,7 @@
 
         auto err = mHal->setLayerBlendMode(mCurrentDisplay, mCurrentLayer, readSigned());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -423,7 +420,7 @@
 
         auto err = mHal->setLayerColor(mCurrentDisplay, mCurrentLayer, readColor());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -436,7 +433,7 @@
 
         auto err = mHal->setLayerCompositionType(mCurrentDisplay, mCurrentLayer, readSigned());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -449,7 +446,7 @@
 
         auto err = mHal->setLayerDataspace(mCurrentDisplay, mCurrentLayer, readSigned());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -462,7 +459,7 @@
 
         auto err = mHal->setLayerDisplayFrame(mCurrentDisplay, mCurrentLayer, readRect());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -475,7 +472,7 @@
 
         auto err = mHal->setLayerPlaneAlpha(mCurrentDisplay, mCurrentLayer, readFloat());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -489,14 +486,14 @@
         auto rawHandle = readHandle();
 
         const native_handle_t* stream;
-        ComposerResources::ReplacedStreamHandle replacedStream;
+        ComposerResources::ReplacedHandle replacedStream(false);
         auto err = mResources->getLayerSidebandStream(mCurrentDisplay, mCurrentLayer, rawHandle,
                                                       &stream, &replacedStream);
         if (err == Error::NONE) {
             err = mHal->setLayerSidebandStream(mCurrentDisplay, mCurrentLayer, stream);
         }
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -509,7 +506,7 @@
 
         auto err = mHal->setLayerSourceCrop(mCurrentDisplay, mCurrentLayer, readFRect());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -522,7 +519,7 @@
 
         auto err = mHal->setLayerTransform(mCurrentDisplay, mCurrentLayer, readSigned());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -537,7 +534,7 @@
         auto region = readRegion(length / 4);
         auto err = mHal->setLayerVisibleRegion(mCurrentDisplay, mCurrentLayer, region);
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -550,7 +547,7 @@
 
         auto err = mHal->setLayerZOrder(mCurrentDisplay, mCurrentLayer, read());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -579,12 +576,12 @@
         };
     }
 
-    ComposerHal* mHal;
-    ComposerResources* mResources;
-
     // 64KiB minus a small space for metadata such as read/write pointers
     static constexpr size_t kWriterInitialSize = 64 * 1024 / sizeof(uint32_t) - 16;
-    CommandWriterBase mWriter{kWriterInitialSize};
+
+    ComposerHal* mHal;
+    ComposerResources* mResources;
+    std::unique_ptr<CommandWriterBase> mWriter;
 
     Display mCurrentDisplay = 0;
     Layer mCurrentLayer = 0;
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
deleted file mode 100644
index 18d184e..0000000
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
+++ /dev/null
@@ -1,592 +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.
- */
-
-#pragma once
-
-#ifndef LOG_TAG
-#warning "ComposerResources.h included without LOG_TAG"
-#endif
-
-#include <memory>
-#include <mutex>
-#include <unordered_map>
-#include <vector>
-
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace hal {
-
-// wrapper for IMapper to import buffers and sideband streams
-class ComposerHandleImporter {
-   public:
-    bool init() {
-        mMapper3 = mapper::V3_0::IMapper::getService();
-        if (mMapper3) {
-            return true;
-        }
-        ALOGD_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0");
-
-        mMapper2 = mapper::V2_0::IMapper::getService();
-        ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service");
-
-        return mMapper2 != nullptr;
-    }
-
-    Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle) {
-        if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) {
-            *outBufferHandle = nullptr;
-            return Error::NONE;
-        }
-
-        const native_handle_t* bufferHandle;
-        if (mMapper2) {
-            mapper::V2_0::Error error;
-            mMapper2->importBuffer(
-                rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
-                    error = tmpError;
-                    bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
-                });
-            if (error != mapper::V2_0::Error::NONE) {
-                return Error::NO_RESOURCES;
-            }
-        }
-        if (mMapper3) {
-            mapper::V3_0::Error error;
-            mMapper3->importBuffer(
-                rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
-                    error = tmpError;
-                    bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
-                });
-            if (error != mapper::V3_0::Error::NONE) {
-                return Error::NO_RESOURCES;
-            }
-        }
-
-        *outBufferHandle = bufferHandle;
-        return Error::NONE;
-    }
-
-    void freeBuffer(const native_handle_t* bufferHandle) {
-        if (bufferHandle) {
-            if (mMapper2) {
-                mMapper2->freeBuffer(
-                    static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
-            } else if (mMapper3) {
-                mMapper3->freeBuffer(
-                    static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
-            }
-        }
-    }
-
-    Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle) {
-        const native_handle_t* streamHandle = nullptr;
-        if (rawHandle) {
-            streamHandle = native_handle_clone(rawHandle);
-            if (!streamHandle) {
-                return Error::NO_RESOURCES;
-            }
-        }
-
-        *outStreamHandle = streamHandle;
-        return Error::NONE;
-    }
-
-    void freeStream(const native_handle_t* streamHandle) {
-        if (streamHandle) {
-            native_handle_close(streamHandle);
-            native_handle_delete(const_cast<native_handle_t*>(streamHandle));
-        }
-    }
-
-   private:
-    sp<mapper::V2_0::IMapper> mMapper2;
-    sp<mapper::V3_0::IMapper> mMapper3;
-};
-
-class ComposerHandleCache {
-   public:
-    enum class HandleType {
-        INVALID,
-        BUFFER,
-        STREAM,
-    };
-
-    ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize)
-        : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {}
-
-    // must be initialized later with initCache
-    ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {}
-
-    ~ComposerHandleCache() {
-        switch (mHandleType) {
-            case HandleType::BUFFER:
-                for (auto handle : mHandles) {
-                    mImporter.freeBuffer(handle);
-                }
-                break;
-            case HandleType::STREAM:
-                for (auto handle : mHandles) {
-                    mImporter.freeStream(handle);
-                }
-                break;
-            default:
-                break;
-        }
-    }
-
-    ComposerHandleCache(const ComposerHandleCache&) = delete;
-    ComposerHandleCache& operator=(const ComposerHandleCache&) = delete;
-
-    bool initCache(HandleType type, uint32_t cacheSize) {
-        // already initialized
-        if (mHandleType != HandleType::INVALID) {
-            return false;
-        }
-
-        mHandleType = type;
-        mHandles.resize(cacheSize, nullptr);
-
-        return true;
-    }
-
-    Error lookupCache(uint32_t slot, const native_handle_t** outHandle) {
-        if (slot >= 0 && slot < mHandles.size()) {
-            *outHandle = mHandles[slot];
-            return Error::NONE;
-        } else {
-            return Error::BAD_PARAMETER;
-        }
-    }
-
-    Error updateCache(uint32_t slot, const native_handle_t* handle,
-                      const native_handle** outReplacedHandle) {
-        if (slot >= 0 && slot < mHandles.size()) {
-            auto& cachedHandle = mHandles[slot];
-            *outReplacedHandle = cachedHandle;
-            cachedHandle = handle;
-            return Error::NONE;
-        } else {
-            return Error::BAD_PARAMETER;
-        }
-    }
-
-    // when fromCache is true, look up in the cache; otherwise, update the cache
-    Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
-                    const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
-        if (fromCache) {
-            *outReplacedHandle = nullptr;
-            return lookupCache(slot, outHandle);
-        } else {
-            *outHandle = inHandle;
-            return updateCache(slot, inHandle, outReplacedHandle);
-        }
-    }
-
-   private:
-    ComposerHandleImporter& mImporter;
-    HandleType mHandleType = HandleType::INVALID;
-    std::vector<const native_handle_t*> mHandles;
-};
-
-// layer resource
-class ComposerLayerResource {
-   public:
-    ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize)
-        : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize),
-          mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {}
-
-    virtual ~ComposerLayerResource() = default;
-
-    Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
-                    const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
-        return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
-    }
-
-    Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
-                            const native_handle_t** outHandle,
-                            const native_handle** outReplacedHandle) {
-        return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle,
-                                              outReplacedHandle);
-    }
-
-   protected:
-    ComposerHandleCache mBufferCache;
-    ComposerHandleCache mSidebandStreamCache;
-};
-
-// display resource
-class ComposerDisplayResource {
-   public:
-    enum class DisplayType {
-        PHYSICAL,
-        VIRTUAL,
-    };
-
-    virtual ~ComposerDisplayResource() = default;
-
-    ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
-                            uint32_t outputBufferCacheSize)
-        : mType(type),
-          mClientTargetCache(importer),
-          mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER,
-                             outputBufferCacheSize),
-          mMustValidate(true) {}
-
-    bool initClientTargetCache(uint32_t cacheSize) {
-        return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize);
-    }
-
-    bool isVirtual() const { return mType == DisplayType::VIRTUAL; }
-
-    Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
-                          const native_handle_t** outHandle,
-                          const native_handle** outReplacedHandle) {
-        return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle,
-                                            outReplacedHandle);
-    }
-
-    Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
-                          const native_handle_t** outHandle,
-                          const native_handle** outReplacedHandle) {
-        return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle,
-                                            outReplacedHandle);
-    }
-
-    bool addLayer(Layer layer, std::unique_ptr<ComposerLayerResource> layerResource) {
-        auto result = mLayerResources.emplace(layer, std::move(layerResource));
-        return result.second;
-    }
-
-    bool removeLayer(Layer layer) { return mLayerResources.erase(layer) > 0; }
-
-    ComposerLayerResource* findLayerResource(Layer layer) {
-        auto layerIter = mLayerResources.find(layer);
-        if (layerIter == mLayerResources.end()) {
-            return nullptr;
-        }
-
-        return layerIter->second.get();
-    }
-
-    std::vector<Layer> getLayers() const {
-        std::vector<Layer> layers;
-        layers.reserve(mLayerResources.size());
-        for (const auto& layerKey : mLayerResources) {
-            layers.push_back(layerKey.first);
-        }
-        return layers;
-    }
-
-    void setMustValidateState(bool mustValidate) { mMustValidate = mustValidate; }
-
-    bool mustValidate() const { return mMustValidate; }
-
-   protected:
-    const DisplayType mType;
-    ComposerHandleCache mClientTargetCache;
-    ComposerHandleCache mOutputBufferCache;
-    bool mMustValidate;
-
-    std::unordered_map<Layer, std::unique_ptr<ComposerLayerResource>> mLayerResources;
-};
-
-class ComposerResources {
-   private:
-    template <bool isBuffer>
-    class ReplacedHandle;
-
-   public:
-    static std::unique_ptr<ComposerResources> create() {
-        auto resources = std::make_unique<ComposerResources>();
-        return resources->init() ? std::move(resources) : nullptr;
-    }
-
-    ComposerResources() = default;
-    virtual ~ComposerResources() = default;
-
-    bool init() { return mImporter.init(); }
-
-    using RemoveDisplay =
-        std::function<void(Display display, bool isVirtual, const std::vector<Layer>& layers)>;
-    void clear(RemoveDisplay removeDisplay) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        for (const auto& displayKey : mDisplayResources) {
-            Display display = displayKey.first;
-            const ComposerDisplayResource& displayResource = *displayKey.second;
-            removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers());
-        }
-        mDisplayResources.clear();
-    }
-
-    Error addPhysicalDisplay(Display display) {
-        auto displayResource =
-            createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
-
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        auto result = mDisplayResources.emplace(display, std::move(displayResource));
-        return result.second ? Error::NONE : Error::BAD_DISPLAY;
-    }
-
-    Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) {
-        auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL,
-                                                     outputBufferCacheSize);
-
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        auto result = mDisplayResources.emplace(display, std::move(displayResource));
-        return result.second ? Error::NONE : Error::BAD_DISPLAY;
-    }
-
-    Error removeDisplay(Display display) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY;
-    }
-
-    Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
-        if (!displayResource) {
-            return Error::BAD_DISPLAY;
-        }
-
-        return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE
-                                                                             : Error::BAD_PARAMETER;
-    }
-
-    Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize) {
-        auto layerResource = createLayerResource(bufferCacheSize);
-
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
-        if (!displayResource) {
-            return Error::BAD_DISPLAY;
-        }
-
-        return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE
-                                                                          : Error::BAD_LAYER;
-    }
-
-    Error removeLayer(Display display, Layer layer) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
-        if (!displayResource) {
-            return Error::BAD_DISPLAY;
-        }
-
-        return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER;
-    }
-
-    using ReplacedBufferHandle = ReplacedHandle<true>;
-    using ReplacedStreamHandle = ReplacedHandle<false>;
-
-    Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
-                                 const native_handle_t* rawHandle,
-                                 const native_handle_t** outBufferHandle,
-                                 ReplacedBufferHandle* outReplacedBuffer) {
-        return getHandle<Cache::CLIENT_TARGET>(display, 0, slot, fromCache, rawHandle,
-                                               outBufferHandle, outReplacedBuffer);
-    }
-
-    Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
-                                 const native_handle_t* rawHandle,
-                                 const native_handle_t** outBufferHandle,
-                                 ReplacedBufferHandle* outReplacedBuffer) {
-        return getHandle<Cache::OUTPUT_BUFFER>(display, 0, slot, fromCache, rawHandle,
-                                               outBufferHandle, outReplacedBuffer);
-    }
-
-    Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
-                         const native_handle_t* rawHandle, const native_handle_t** outBufferHandle,
-                         ReplacedBufferHandle* outReplacedBuffer) {
-        return getHandle<Cache::LAYER_BUFFER>(display, layer, slot, fromCache, rawHandle,
-                                              outBufferHandle, outReplacedBuffer);
-    }
-
-    Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle,
-                                 const native_handle_t** outStreamHandle,
-                                 ReplacedStreamHandle* outReplacedStream) {
-        return getHandle<Cache::LAYER_SIDEBAND_STREAM>(display, layer, 0, false, rawHandle,
-                                                       outStreamHandle, outReplacedStream);
-    }
-
-    void setDisplayMustValidateState(Display display, bool mustValidate) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        auto* displayResource = findDisplayResourceLocked(display);
-        if (displayResource) {
-            displayResource->setMustValidateState(mustValidate);
-        }
-    }
-
-    bool mustValidateDisplay(Display display) {
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-        auto* displayResource = findDisplayResourceLocked(display);
-        if (displayResource) {
-            return displayResource->mustValidate();
-        }
-        return false;
-    }
-
-   protected:
-    virtual std::unique_ptr<ComposerDisplayResource> createDisplayResource(
-        ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
-        return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
-    }
-
-    virtual std::unique_ptr<ComposerLayerResource> createLayerResource(uint32_t bufferCacheSize) {
-        return std::make_unique<ComposerLayerResource>(mImporter, bufferCacheSize);
-    }
-
-    ComposerDisplayResource* findDisplayResourceLocked(Display display) {
-        auto iter = mDisplayResources.find(display);
-        if (iter == mDisplayResources.end()) {
-            return nullptr;
-        }
-        return iter->second.get();
-    }
-
-    ComposerHandleImporter mImporter;
-
-    std::mutex mDisplayResourcesMutex;
-    std::unordered_map<Display, std::unique_ptr<ComposerDisplayResource>> mDisplayResources;
-
-   private:
-    enum class Cache {
-        CLIENT_TARGET,
-        OUTPUT_BUFFER,
-        LAYER_BUFFER,
-        LAYER_SIDEBAND_STREAM,
-    };
-
-    // When a buffer in the cache is replaced by a new one, we must keep it
-    // alive until it has been replaced in ComposerHal.
-    template <bool isBuffer>
-    class ReplacedHandle {
-       public:
-        ReplacedHandle() = default;
-        ReplacedHandle(const ReplacedHandle&) = delete;
-        ReplacedHandle& operator=(const ReplacedHandle&) = delete;
-
-        ~ReplacedHandle() { reset(); }
-
-        void reset(ComposerHandleImporter* importer = nullptr,
-                   const native_handle_t* handle = nullptr) {
-            if (mHandle) {
-                if (isBuffer) {
-                    mImporter->freeBuffer(mHandle);
-                } else {
-                    mImporter->freeStream(mHandle);
-                }
-            }
-
-            mImporter = importer;
-            mHandle = handle;
-        }
-
-       private:
-        ComposerHandleImporter* mImporter = nullptr;
-        const native_handle_t* mHandle = nullptr;
-    };
-
-    template <Cache cache, bool isBuffer>
-    Error getHandle(Display display, Layer layer, uint32_t slot, bool fromCache,
-                    const native_handle_t* rawHandle, const native_handle_t** outHandle,
-                    ReplacedHandle<isBuffer>* outReplacedHandle) {
-        Error error;
-
-        // import the raw handle (or ignore raw handle when fromCache is true)
-        const native_handle_t* importedHandle = nullptr;
-        if (!fromCache) {
-            error = (isBuffer) ? mImporter.importBuffer(rawHandle, &importedHandle)
-                               : mImporter.importStream(rawHandle, &importedHandle);
-            if (error != Error::NONE) {
-                return error;
-            }
-        }
-
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-
-        // find display/layer resource
-        const bool needLayerResource =
-            (cache == Cache::LAYER_BUFFER || cache == Cache::LAYER_SIDEBAND_STREAM);
-        ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
-        ComposerLayerResource* layerResource = (displayResource && needLayerResource)
-                                                   ? displayResource->findLayerResource(layer)
-                                                   : nullptr;
-
-        // lookup or update cache
-        const native_handle_t* replacedHandle = nullptr;
-        if (displayResource && (!needLayerResource || layerResource)) {
-            switch (cache) {
-                case Cache::CLIENT_TARGET:
-                    error = displayResource->getClientTarget(slot, fromCache, importedHandle,
-                                                             outHandle, &replacedHandle);
-                    break;
-                case Cache::OUTPUT_BUFFER:
-                    error = displayResource->getOutputBuffer(slot, fromCache, importedHandle,
-                                                             outHandle, &replacedHandle);
-                    break;
-                case Cache::LAYER_BUFFER:
-                    error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle,
-                                                     &replacedHandle);
-                    break;
-                case Cache::LAYER_SIDEBAND_STREAM:
-                    error = layerResource->getSidebandStream(slot, fromCache, importedHandle,
-                                                             outHandle, &replacedHandle);
-                    break;
-                default:
-                    error = Error::BAD_PARAMETER;
-                    break;
-            }
-
-            if (error != Error::NONE) {
-                ALOGW("invalid cache %d slot %d", int(cache), int(slot));
-            }
-        } else if (!displayResource) {
-            error = Error::BAD_DISPLAY;
-        } else {
-            error = Error::BAD_LAYER;
-        }
-
-        // clean up on errors
-        if (error != Error::NONE) {
-            if (!fromCache) {
-                if (isBuffer) {
-                    mImporter.freeBuffer(importedHandle);
-                } else {
-                    mImporter.freeStream(importedHandle);
-                }
-            }
-            return error;
-        }
-
-        outReplacedHandle->reset(&mImporter, replacedHandle);
-
-        return Error::NONE;
-    }
-};
-
-}  // namespace hal
-}  // namespace V2_1
-}  // namespace composer
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/composer/2.1/utils/resources/Android.bp b/graphics/composer/2.1/utils/resources/Android.bp
new file mode 100644
index 0000000..ed827fe
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/Android.bp
@@ -0,0 +1,51 @@
+//
+// 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_library_shared {
+    name: "android.hardware.graphics.composer@2.1-resources",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "libcutils",
+        "libhardware", // TODO remove hwcomposer2.h dependency
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
+    export_include_dirs: ["include"],
+    srcs: [
+        "ComposerResources.cpp",
+    ],
+}
diff --git a/graphics/composer/2.1/utils/resources/ComposerResources.cpp b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
new file mode 100644
index 0000000..21f6035
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
@@ -0,0 +1,503 @@
+/*
+ * 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 "ComposerResources"
+
+#include "composer-resources/2.1/ComposerResources.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+bool ComposerHandleImporter::init() {
+    mMapper4 = mapper::V4_0::IMapper::getService();
+    if (mMapper4) {
+        return true;
+    }
+    ALOGI_IF(!mMapper4, "failed to get mapper 4.0 service, falling back to mapper 3.0");
+
+    mMapper3 = mapper::V3_0::IMapper::getService();
+    if (mMapper3) {
+        return true;
+    }
+    ALOGI_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0");
+
+    mMapper2 = mapper::V2_0::IMapper::getService();
+    ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service");
+
+    return mMapper2 != nullptr;
+}
+
+Error ComposerHandleImporter::importBuffer(const native_handle_t* rawHandle,
+                                           const native_handle_t** outBufferHandle) {
+    if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) {
+        *outBufferHandle = nullptr;
+        return Error::NONE;
+    }
+
+    const native_handle_t* bufferHandle;
+    if (mMapper2) {
+        mapper::V2_0::Error error;
+        mMapper2->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+            error = tmpError;
+            bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+        });
+        if (error != mapper::V2_0::Error::NONE) {
+            return Error::NO_RESOURCES;
+        }
+    }
+    if (mMapper3) {
+        mapper::V3_0::Error error;
+        mMapper3->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+            error = tmpError;
+            bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+        });
+        if (error != mapper::V3_0::Error::NONE) {
+            return Error::NO_RESOURCES;
+        }
+    }
+    if (mMapper4) {
+        mapper::V4_0::Error error;
+        mMapper4->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+            error = tmpError;
+            bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+        });
+        if (error != mapper::V4_0::Error::NONE) {
+            return Error::NO_RESOURCES;
+        }
+    }
+
+    *outBufferHandle = bufferHandle;
+    return Error::NONE;
+}
+
+void ComposerHandleImporter::freeBuffer(const native_handle_t* bufferHandle) {
+    if (bufferHandle) {
+        if (mMapper2) {
+            mMapper2->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+        } else if (mMapper3) {
+            mMapper3->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+        } else if (mMapper4) {
+            mMapper4->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+        }
+    }
+}
+
+Error ComposerHandleImporter::importStream(const native_handle_t* rawHandle,
+                                           const native_handle_t** outStreamHandle) {
+    const native_handle_t* streamHandle = nullptr;
+    if (rawHandle) {
+        streamHandle = native_handle_clone(rawHandle);
+        if (!streamHandle) {
+            return Error::NO_RESOURCES;
+        }
+    }
+
+    *outStreamHandle = streamHandle;
+    return Error::NONE;
+}
+
+void ComposerHandleImporter::freeStream(const native_handle_t* streamHandle) {
+    if (streamHandle) {
+        native_handle_close(streamHandle);
+        native_handle_delete(const_cast<native_handle_t*>(streamHandle));
+    }
+}
+
+ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer, HandleType type,
+                                         uint32_t cacheSize)
+    : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {}
+
+// must be initialized later with initCache
+ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {}
+
+ComposerHandleCache::~ComposerHandleCache() {
+    switch (mHandleType) {
+        case HandleType::BUFFER:
+            for (auto handle : mHandles) {
+                mImporter.freeBuffer(handle);
+            }
+            break;
+        case HandleType::STREAM:
+            for (auto handle : mHandles) {
+                mImporter.freeStream(handle);
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+bool ComposerHandleCache::initCache(HandleType type, uint32_t cacheSize) {
+    // already initialized
+    if (mHandleType != HandleType::INVALID) {
+        return false;
+    }
+
+    mHandleType = type;
+    mHandles.resize(cacheSize, nullptr);
+
+    return true;
+}
+
+Error ComposerHandleCache::lookupCache(uint32_t slot, const native_handle_t** outHandle) {
+    if (slot >= 0 && slot < mHandles.size()) {
+        *outHandle = mHandles[slot];
+        return Error::NONE;
+    } else {
+        return Error::BAD_PARAMETER;
+    }
+}
+
+Error ComposerHandleCache::updateCache(uint32_t slot, const native_handle_t* handle,
+                                       const native_handle** outReplacedHandle) {
+    if (slot >= 0 && slot < mHandles.size()) {
+        auto& cachedHandle = mHandles[slot];
+        *outReplacedHandle = cachedHandle;
+        cachedHandle = handle;
+        return Error::NONE;
+    } else {
+        return Error::BAD_PARAMETER;
+    }
+}
+
+// when fromCache is true, look up in the cache; otherwise, update the cache
+Error ComposerHandleCache::getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                                     const native_handle_t** outHandle,
+                                     const native_handle** outReplacedHandle) {
+    if (fromCache) {
+        *outReplacedHandle = nullptr;
+        return lookupCache(slot, outHandle);
+    } else {
+        *outHandle = inHandle;
+        return updateCache(slot, inHandle, outReplacedHandle);
+    }
+}
+
+ComposerLayerResource::ComposerLayerResource(ComposerHandleImporter& importer,
+                                             uint32_t bufferCacheSize)
+    : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize),
+      mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {}
+
+Error ComposerLayerResource::getBuffer(uint32_t slot, bool fromCache,
+                                       const native_handle_t* inHandle,
+                                       const native_handle_t** outHandle,
+                                       const native_handle** outReplacedHandle) {
+    return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+Error ComposerLayerResource::getSidebandStream(uint32_t slot, bool fromCache,
+                                               const native_handle_t* inHandle,
+                                               const native_handle_t** outHandle,
+                                               const native_handle** outReplacedHandle) {
+    return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+ComposerDisplayResource::ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+                                                 uint32_t outputBufferCacheSize)
+    : mType(type),
+      mClientTargetCache(importer),
+      mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, outputBufferCacheSize),
+      mMustValidate(true) {}
+
+bool ComposerDisplayResource::initClientTargetCache(uint32_t cacheSize) {
+    return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize);
+}
+
+bool ComposerDisplayResource::isVirtual() const {
+    return mType == DisplayType::VIRTUAL;
+}
+
+Error ComposerDisplayResource::getClientTarget(uint32_t slot, bool fromCache,
+                                               const native_handle_t* inHandle,
+                                               const native_handle_t** outHandle,
+                                               const native_handle** outReplacedHandle) {
+    return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+Error ComposerDisplayResource::getOutputBuffer(uint32_t slot, bool fromCache,
+                                               const native_handle_t* inHandle,
+                                               const native_handle_t** outHandle,
+                                               const native_handle** outReplacedHandle) {
+    return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+bool ComposerDisplayResource::addLayer(Layer layer,
+                                       std::unique_ptr<ComposerLayerResource> layerResource) {
+    auto result = mLayerResources.emplace(layer, std::move(layerResource));
+    return result.second;
+}
+
+bool ComposerDisplayResource::removeLayer(Layer layer) {
+    return mLayerResources.erase(layer) > 0;
+}
+
+ComposerLayerResource* ComposerDisplayResource::findLayerResource(Layer layer) {
+    auto layerIter = mLayerResources.find(layer);
+    if (layerIter == mLayerResources.end()) {
+        return nullptr;
+    }
+
+    return layerIter->second.get();
+}
+
+std::vector<Layer> ComposerDisplayResource::getLayers() const {
+    std::vector<Layer> layers;
+    layers.reserve(mLayerResources.size());
+    for (const auto& layerKey : mLayerResources) {
+        layers.push_back(layerKey.first);
+    }
+    return layers;
+}
+
+void ComposerDisplayResource::setMustValidateState(bool mustValidate) {
+    mMustValidate = mustValidate;
+}
+
+bool ComposerDisplayResource::mustValidate() const {
+    return mMustValidate;
+}
+
+std::unique_ptr<ComposerResources> ComposerResources::create() {
+    auto resources = std::make_unique<ComposerResources>();
+    return resources->init() ? std::move(resources) : nullptr;
+}
+
+bool ComposerResources::init() {
+    return mImporter.init();
+}
+
+void ComposerResources::clear(RemoveDisplay removeDisplay) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    for (const auto& displayKey : mDisplayResources) {
+        Display display = displayKey.first;
+        const ComposerDisplayResource& displayResource = *displayKey.second;
+        removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers());
+    }
+    mDisplayResources.clear();
+}
+
+Error ComposerResources::addPhysicalDisplay(Display display) {
+    auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
+
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    auto result = mDisplayResources.emplace(display, std::move(displayResource));
+    return result.second ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) {
+    auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL,
+                                                 outputBufferCacheSize);
+
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    auto result = mDisplayResources.emplace(display, std::move(displayResource));
+    return result.second ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::removeDisplay(Display display) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::setDisplayClientTargetCacheSize(Display display,
+                                                         uint32_t clientTargetCacheSize) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+    if (!displayResource) {
+        return Error::BAD_DISPLAY;
+    }
+
+    return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE
+                                                                         : Error::BAD_PARAMETER;
+}
+
+Error ComposerResources::addLayer(Display display, Layer layer, uint32_t bufferCacheSize) {
+    auto layerResource = createLayerResource(bufferCacheSize);
+
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+    if (!displayResource) {
+        return Error::BAD_DISPLAY;
+    }
+
+    return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE
+                                                                      : Error::BAD_LAYER;
+}
+
+Error ComposerResources::removeLayer(Display display, Layer layer) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+    if (!displayResource) {
+        return Error::BAD_DISPLAY;
+    }
+
+    return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER;
+}
+
+Error ComposerResources::getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
+                                                const native_handle_t* rawHandle,
+                                                const native_handle_t** outBufferHandle,
+                                                ReplacedHandle* outReplacedBuffer) {
+    return getHandle(display, 0, slot, Cache::CLIENT_TARGET, fromCache, rawHandle, outBufferHandle,
+                     outReplacedBuffer);
+}
+
+Error ComposerResources::getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
+                                                const native_handle_t* rawHandle,
+                                                const native_handle_t** outBufferHandle,
+                                                ReplacedHandle* outReplacedBuffer) {
+    return getHandle(display, 0, slot, Cache::OUTPUT_BUFFER, fromCache, rawHandle, outBufferHandle,
+                     outReplacedBuffer);
+}
+
+Error ComposerResources::getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
+                                        const native_handle_t* rawHandle,
+                                        const native_handle_t** outBufferHandle,
+                                        ReplacedHandle* outReplacedBuffer) {
+    return getHandle(display, layer, slot, Cache::LAYER_BUFFER, fromCache, rawHandle,
+                     outBufferHandle, outReplacedBuffer);
+}
+
+Error ComposerResources::getLayerSidebandStream(Display display, Layer layer,
+                                                const native_handle_t* rawHandle,
+                                                const native_handle_t** outStreamHandle,
+                                                ReplacedHandle* outReplacedStream) {
+    return getHandle(display, layer, 0, Cache::LAYER_SIDEBAND_STREAM, false, rawHandle,
+                     outStreamHandle, outReplacedStream);
+}
+
+void ComposerResources::setDisplayMustValidateState(Display display, bool mustValidate) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    auto* displayResource = findDisplayResourceLocked(display);
+    if (displayResource) {
+        displayResource->setMustValidateState(mustValidate);
+    }
+}
+
+bool ComposerResources::mustValidateDisplay(Display display) {
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+    auto* displayResource = findDisplayResourceLocked(display);
+    if (displayResource) {
+        return displayResource->mustValidate();
+    }
+    return false;
+}
+
+std::unique_ptr<ComposerDisplayResource> ComposerResources::createDisplayResource(
+        ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
+    return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
+}
+
+std::unique_ptr<ComposerLayerResource> ComposerResources::createLayerResource(
+        uint32_t bufferCacheSize) {
+    return std::make_unique<ComposerLayerResource>(mImporter, bufferCacheSize);
+}
+
+ComposerDisplayResource* ComposerResources::findDisplayResourceLocked(Display display) {
+    auto iter = mDisplayResources.find(display);
+    if (iter == mDisplayResources.end()) {
+        return nullptr;
+    }
+    return iter->second.get();
+}
+
+Error ComposerResources::getHandle(Display display, Layer layer, uint32_t slot, Cache cache,
+                                   bool fromCache, const native_handle_t* rawHandle,
+                                   const native_handle_t** outHandle,
+                                   ReplacedHandle* outReplacedHandle) {
+    Error error;
+
+    // import the raw handle (or ignore raw handle when fromCache is true)
+    const native_handle_t* importedHandle = nullptr;
+    if (!fromCache) {
+        error = (outReplacedHandle->isBuffer())
+                        ? mImporter.importBuffer(rawHandle, &importedHandle)
+                        : mImporter.importStream(rawHandle, &importedHandle);
+        if (error != Error::NONE) {
+            return error;
+        }
+    }
+
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+    // find display/layer resource
+    const bool needLayerResource = (cache == ComposerResources::Cache::LAYER_BUFFER ||
+                                    cache == ComposerResources::Cache::LAYER_SIDEBAND_STREAM);
+    ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+    ComposerLayerResource* layerResource = (displayResource && needLayerResource)
+                                                   ? displayResource->findLayerResource(layer)
+                                                   : nullptr;
+
+    // lookup or update cache
+    const native_handle_t* replacedHandle = nullptr;
+    if (displayResource && (!needLayerResource || layerResource)) {
+        switch (cache) {
+            case ComposerResources::Cache::CLIENT_TARGET:
+                error = displayResource->getClientTarget(slot, fromCache, importedHandle, outHandle,
+                                                         &replacedHandle);
+                break;
+            case ComposerResources::Cache::OUTPUT_BUFFER:
+                error = displayResource->getOutputBuffer(slot, fromCache, importedHandle, outHandle,
+                                                         &replacedHandle);
+                break;
+            case ComposerResources::Cache::LAYER_BUFFER:
+                error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle,
+                                                 &replacedHandle);
+                break;
+            case ComposerResources::Cache::LAYER_SIDEBAND_STREAM:
+                error = layerResource->getSidebandStream(slot, fromCache, importedHandle, outHandle,
+                                                         &replacedHandle);
+                break;
+            default:
+                error = Error::BAD_PARAMETER;
+                break;
+        }
+
+        if (error != Error::NONE) {
+            ALOGW("invalid cache %d slot %d", int(cache), int(slot));
+        }
+    } else if (!displayResource) {
+        error = Error::BAD_DISPLAY;
+    } else {
+        error = Error::BAD_LAYER;
+    }
+
+    // clean up on errors
+    if (error != Error::NONE) {
+        if (!fromCache) {
+            if (outReplacedHandle->isBuffer()) {
+                mImporter.freeBuffer(importedHandle);
+            } else {
+                mImporter.freeStream(importedHandle);
+            }
+        }
+        return error;
+    }
+
+    outReplacedHandle->reset(&mImporter, replacedHandle);
+
+    return Error::NONE;
+}
+
+}  // namespace hal
+}  // namespace V2_1
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
new file mode 100644
index 0000000..3738278
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerResources.h included without LOG_TAG"
+#endif
+
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/types.h>
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+// wrapper for IMapper to import buffers and sideband streams
+class ComposerHandleImporter {
+  public:
+    bool init();
+
+    Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle);
+    void freeBuffer(const native_handle_t* bufferHandle);
+    Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle);
+    void freeStream(const native_handle_t* streamHandle);
+
+  private:
+    sp<mapper::V2_0::IMapper> mMapper2;
+    sp<mapper::V3_0::IMapper> mMapper3;
+    sp<mapper::V4_0::IMapper> mMapper4;
+};
+
+class ComposerHandleCache {
+  public:
+    enum class HandleType {
+        INVALID,
+        BUFFER,
+        STREAM,
+    };
+
+    ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize);
+
+    // must be initialized later with initCache
+    ComposerHandleCache(ComposerHandleImporter& importer);
+
+    ~ComposerHandleCache();
+
+    ComposerHandleCache(const ComposerHandleCache&) = delete;
+    ComposerHandleCache& operator=(const ComposerHandleCache&) = delete;
+
+    bool initCache(HandleType type, uint32_t cacheSize);
+    Error lookupCache(uint32_t slot, const native_handle_t** outHandle);
+    Error updateCache(uint32_t slot, const native_handle_t* handle,
+                      const native_handle** outReplacedHandle);
+
+    // when fromCache is true, look up in the cache; otherwise, update the cache
+    Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                    const native_handle_t** outHandle, const native_handle** outReplacedHandle);
+
+  private:
+    ComposerHandleImporter& mImporter;
+    HandleType mHandleType = HandleType::INVALID;
+    std::vector<const native_handle_t*> mHandles;
+};
+
+// layer resource
+class ComposerLayerResource {
+  public:
+    ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize);
+
+    virtual ~ComposerLayerResource() = default;
+
+    Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                    const native_handle_t** outHandle, const native_handle** outReplacedHandle);
+    Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                            const native_handle_t** outHandle,
+                            const native_handle** outReplacedHandle);
+
+  protected:
+    ComposerHandleCache mBufferCache;
+    ComposerHandleCache mSidebandStreamCache;
+};
+
+// display resource
+class ComposerDisplayResource {
+  public:
+    enum class DisplayType {
+        PHYSICAL,
+        VIRTUAL,
+    };
+
+    virtual ~ComposerDisplayResource() = default;
+
+    ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+                            uint32_t outputBufferCacheSize);
+
+    bool initClientTargetCache(uint32_t cacheSize);
+
+    bool isVirtual() const;
+
+    Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                          const native_handle_t** outHandle,
+                          const native_handle** outReplacedHandle);
+
+    Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+                          const native_handle_t** outHandle,
+                          const native_handle** outReplacedHandle);
+
+    bool addLayer(Layer layer, std::unique_ptr<ComposerLayerResource> layerResource);
+    bool removeLayer(Layer layer);
+    ComposerLayerResource* findLayerResource(Layer layer);
+    std::vector<Layer> getLayers() const;
+
+    void setMustValidateState(bool mustValidate);
+
+    bool mustValidate() const;
+
+  protected:
+    const DisplayType mType;
+    ComposerHandleCache mClientTargetCache;
+    ComposerHandleCache mOutputBufferCache;
+    bool mMustValidate;
+
+    std::unordered_map<Layer, std::unique_ptr<ComposerLayerResource>> mLayerResources;
+};
+
+class ComposerResources {
+  public:
+    static std::unique_ptr<ComposerResources> create();
+
+    ComposerResources() = default;
+    virtual ~ComposerResources() = default;
+
+    bool init();
+
+    using RemoveDisplay =
+            std::function<void(Display display, bool isVirtual, const std::vector<Layer>& layers)>;
+    void clear(RemoveDisplay removeDisplay);
+
+    Error addPhysicalDisplay(Display display);
+    Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize);
+
+    Error removeDisplay(Display display);
+
+    Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize);
+
+    Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize);
+    Error removeLayer(Display display, Layer layer);
+
+    void setDisplayMustValidateState(Display display, bool mustValidate);
+
+    bool mustValidateDisplay(Display display);
+
+    // When a buffer in the cache is replaced by a new one, we must keep it
+    // alive until it has been replaced in ComposerHal.
+    class ReplacedHandle {
+      public:
+        explicit ReplacedHandle(bool isBuffer) : mIsBuffer(isBuffer) {}
+        ReplacedHandle(const ReplacedHandle&) = delete;
+        ReplacedHandle& operator=(const ReplacedHandle&) = delete;
+
+        ~ReplacedHandle() { reset(); }
+
+        bool isBuffer() { return mIsBuffer; }
+
+        void reset(ComposerHandleImporter* importer = nullptr,
+                   const native_handle_t* handle = nullptr) {
+            if (mHandle) {
+                if (mIsBuffer) {
+                    mImporter->freeBuffer(mHandle);
+                } else {
+                    mImporter->freeStream(mHandle);
+                }
+            }
+
+            mImporter = importer;
+            mHandle = handle;
+        }
+
+      private:
+        bool mIsBuffer;
+        ComposerHandleImporter* mImporter = nullptr;
+        const native_handle_t* mHandle = nullptr;
+    };
+
+    Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
+                                 const native_handle_t* rawHandle,
+                                 const native_handle_t** outBufferHandle,
+                                 ReplacedHandle* outReplacedBuffer);
+
+    Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
+                                 const native_handle_t* rawHandle,
+                                 const native_handle_t** outBufferHandle,
+                                 ReplacedHandle* outReplacedBuffer);
+
+    Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
+                         const native_handle_t* rawHandle, const native_handle_t** outBufferHandle,
+                         ReplacedHandle* outReplacedBuffer);
+
+    Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle,
+                                 const native_handle_t** outStreamHandle,
+                                 ReplacedHandle* outReplacedStream);
+
+  protected:
+    virtual std::unique_ptr<ComposerDisplayResource> createDisplayResource(
+            ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize);
+
+    virtual std::unique_ptr<ComposerLayerResource> createLayerResource(uint32_t bufferCacheSize);
+
+    ComposerDisplayResource* findDisplayResourceLocked(Display display);
+
+    ComposerHandleImporter mImporter;
+
+    std::mutex mDisplayResourcesMutex;
+    std::unordered_map<Display, std::unique_ptr<ComposerDisplayResource>> mDisplayResources;
+
+  private:
+    enum class Cache {
+        CLIENT_TARGET,
+        OUTPUT_BUFFER,
+        LAYER_BUFFER,
+        LAYER_SIDEBAND_STREAM,
+    };
+
+    Error getHandle(Display display, Layer layer, uint32_t slot, Cache cache, bool fromCache,
+                    const native_handle_t* rawHandle, const native_handle_t** outHandle,
+                    ReplacedHandle* outReplacedHandle);
+};
+
+}  // namespace hal
+}  // namespace V2_1
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index fcb327f..3b0911f 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -23,14 +23,24 @@
         "TestCommandReader.cpp",
     ],
     static_libs: [
-        "VtsHalHidlTargetTestBase",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0-vts",
+        "libgtest",
+    ],
+    export_static_lib_headers: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0-vts",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
     ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
     cflags: [
         "-O0",
         "-g",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index c5d5823..4b6b7c8 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
 
 #include <composer-vts/2.1/ComposerVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -25,11 +23,6 @@
 namespace V2_1 {
 namespace vts {
 
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
-    : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
 Composer::Composer(const sp<IComposer>& composer) : mComposer(composer) {
     // ASSERT_* can only be used in functions returning void.
     [this] {
@@ -317,11 +310,16 @@
 
 Gralloc::Gralloc() {
     [this] {
-        ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+        ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
                                                                        /*errOnFailure=*/false));
-        if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
-            mGralloc3 = nullptr;
-            ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+        if (mGralloc4->getAllocator() == nullptr || mGralloc4->getMapper() == nullptr) {
+            mGralloc4 = nullptr;
+            ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+                                                                           /*errOnFailure=*/false));
+            if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
+                mGralloc3 = nullptr;
+                ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+            }
         }
     }();
 }
@@ -329,7 +327,15 @@
 const native_handle_t* Gralloc::allocate(uint32_t width, uint32_t height, uint32_t layerCount,
                                          PixelFormat format, uint64_t usage, bool import,
                                          uint32_t* outStride) {
-    if (mGralloc3) {
+    if (mGralloc4) {
+        IMapper4::BufferDescriptorInfo info{};
+        info.width = width;
+        info.height = height;
+        info.layerCount = layerCount;
+        info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+        info.usage = usage;
+        return mGralloc4->allocate(info, import, outStride);
+    } else if (mGralloc3) {
         IMapper3::BufferDescriptorInfo info{};
         info.width = width;
         info.height = height;
@@ -350,7 +356,14 @@
 
 void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
                     const AccessRegion& accessRegionRect, int acquireFence) {
-    if (mGralloc3) {
+    if (mGralloc4) {
+        IMapper4::Rect accessRegion;
+        accessRegion.left = accessRegionRect.left;
+        accessRegion.top = accessRegionRect.top;
+        accessRegion.width = accessRegionRect.width;
+        accessRegion.height = accessRegionRect.height;
+        return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence);
+    } else if (mGralloc3) {
         IMapper3::Rect accessRegion;
         accessRegion.left = accessRegionRect.left;
         accessRegion.top = accessRegionRect.top;
@@ -371,7 +384,9 @@
 }
 
 int Gralloc::unlock(const native_handle_t* bufferHandle) {
-    if (mGralloc3) {
+    if (mGralloc4) {
+        return mGralloc4->unlock(bufferHandle);
+    } else if (mGralloc3) {
         return mGralloc3->unlock(bufferHandle);
     } else {
         return mGralloc2->unlock(bufferHandle);
@@ -379,7 +394,9 @@
 }
 
 void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
-    if (mGralloc3) {
+    if (mGralloc4) {
+        mGralloc4->freeBuffer(bufferHandle);
+    } else if (mGralloc3) {
         mGralloc3->freeBuffer(bufferHandle);
     } else {
         mGralloc2->freeBuffer(bufferHandle);
diff --git a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
index 454a89c..0506f3a 100644
--- a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
+++ b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
@@ -29,63 +29,68 @@
     mErrors.clear();
     mCompositionChanges.clear();
     while (!isEmpty()) {
-        IComposerClient::Command command;
+        int32_t command;
         uint16_t length;
         ASSERT_TRUE(beginCommand(&command, &length));
 
-        switch (command) {
-            case IComposerClient::Command::SELECT_DISPLAY:
-                ASSERT_EQ(2, length);
-                read64();  // display
-                break;
-            case IComposerClient::Command::SET_ERROR: {
-                ASSERT_EQ(2, length);
-                auto loc = read();
-                auto err = readSigned();
-                std::pair<uint32_t, uint32_t> error(loc, err);
-                mErrors.push_back(error);
-            } break;
-            case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
-                ASSERT_EQ(0, length % 3);
-                for (uint16_t count = 0; count < length / 3; ++count) {
-                    uint64_t layerId = read64();
-                    uint32_t composition = read();
-
-                    std::pair<uint64_t, uint32_t> compositionChange(layerId, composition);
-                    mCompositionChanges.push_back(compositionChange);
-                }
-                break;
-            case IComposerClient::Command::SET_DISPLAY_REQUESTS:
-                ASSERT_EQ(1, length % 3);
-                read();  // displayRequests, ignored for now
-                for (uint16_t count = 0; count < (length - 1) / 3; ++count) {
-                    read64();  // layer
-                    // silently eat requests to clear the client target, since we won't be testing
-                    // client composition anyway
-                    ASSERT_EQ(1u, read());
-                }
-                break;
-            case IComposerClient::Command::SET_PRESENT_FENCE:
-                ASSERT_EQ(1, length);
-                close(readFence());
-                break;
-            case IComposerClient::Command::SET_RELEASE_FENCES:
-                ASSERT_EQ(0, length % 3);
-                for (uint16_t count = 0; count < length / 3; ++count) {
-                    read64();
-                    close(readFence());
-                }
-                break;
-            default:
-                GTEST_FAIL() << "unexpected return command " << std::hex
-                             << static_cast<int>(command);
-                break;
-        }
+        parseSingleCommand(command, length);
 
         endCommand();
     }
 }
 
+void TestCommandReader::parseSingleCommand(int32_t commandRaw, uint16_t length) {
+    IComposerClient::Command command = static_cast<IComposerClient::Command>(commandRaw);
+
+    switch (command) {
+        case IComposerClient::Command::SELECT_DISPLAY:
+            ASSERT_EQ(2, length);
+            read64();  // display
+            break;
+        case IComposerClient::Command::SET_ERROR: {
+            ASSERT_EQ(2, length);
+            auto loc = read();
+            auto err = readSigned();
+            std::pair<uint32_t, uint32_t> error(loc, err);
+            mErrors.push_back(error);
+        } break;
+        case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
+            ASSERT_EQ(0, length % 3);
+            for (uint16_t count = 0; count < length / 3; ++count) {
+                uint64_t layerId = read64();
+                uint32_t composition = read();
+
+                std::pair<uint64_t, uint32_t> compositionChange(layerId, composition);
+                mCompositionChanges.push_back(compositionChange);
+            }
+            break;
+        case IComposerClient::Command::SET_DISPLAY_REQUESTS:
+            ASSERT_EQ(1, length % 3);
+            read();  // displayRequests, ignored for now
+            for (uint16_t count = 0; count < (length - 1) / 3; ++count) {
+                read64();  // layer
+                // silently eat requests to clear the client target, since we won't be testing
+                // client composition anyway
+                ASSERT_EQ(1u, read());
+            }
+            break;
+        case IComposerClient::Command::SET_PRESENT_FENCE:
+            ASSERT_EQ(1, length);
+            close(readFence());
+            break;
+        case IComposerClient::Command::SET_RELEASE_FENCES:
+            ASSERT_EQ(0, length % 3);
+            for (uint16_t count = 0; count < length / 3; ++count) {
+                read64();
+                close(readFence());
+            }
+            break;
+        default:
+            GTEST_FAIL() << "unexpected return command " << std::hex << static_cast<int>(command);
+            break;
+    }
+}
+
 }  // namespace vts
 }  // namespace V2_1
 }  // namespace composer
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
index 7811048..63aa713 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
@@ -27,6 +27,7 @@
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <mapper-vts/2.0/MapperVts.h>
 #include <mapper-vts/3.0/MapperVts.h>
+#include <mapper-vts/4.0/MapperVts.h>
 #include <utils/StrongPointer.h>
 
 #include "gtest/gtest.h"
@@ -44,8 +45,10 @@
 using android::hardware::graphics::common::V1_0::PixelFormat;
 using IMapper2 = android::hardware::graphics::mapper::V2_0::IMapper;
 using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
 using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
 using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
+using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
 
 class ComposerClient;
 
@@ -54,6 +57,7 @@
    public:
     Composer();
     explicit Composer(const std::string& name);
+    explicit Composer(const sp<IComposer>& composer);
 
     sp<IComposer> getRaw() const;
 
@@ -64,9 +68,6 @@
     std::string dumpDebugInfo();
     std::unique_ptr<ComposerClient> createClient();
 
-   protected:
-    explicit Composer(const sp<IComposer>& composer);
-
    private:
     const sp<IComposer> mComposer;
 
@@ -153,6 +154,7 @@
   protected:
     std::shared_ptr<Gralloc2> mGralloc2 = nullptr;
     std::shared_ptr<Gralloc3> mGralloc3 = nullptr;
+    std::shared_ptr<Gralloc4> mGralloc4 = nullptr;
 };
 
 }  // namespace vts
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
index c12debe..40d347a 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
@@ -29,12 +29,16 @@
 // returned.
 class TestCommandReader : public CommandReaderBase {
    public:
-    // Parse all commands in the return command queue.  Call GTEST_FAIL() for
-    // unexpected errors or commands.
-    void parse();
+     virtual ~TestCommandReader() = default;
+     // Parse all commands in the return command queue.  Call GTEST_FAIL() for
+     // unexpected errors or commands.
+     void parse();
 
-    std::vector<std::pair<uint32_t, uint32_t>> mErrors;
-    std::vector<std::pair<uint64_t, uint32_t>> mCompositionChanges;
+     std::vector<std::pair<uint32_t, uint32_t>> mErrors;
+     std::vector<std::pair<uint64_t, uint32_t>> mCompositionChanges;
+
+   protected:
+     virtual void parseSingleCommand(int32_t commandRaw, uint16_t length);
 };
 
 }  // namespace vts
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index d54da60..3678a04 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -23,19 +23,25 @@
     shared_libs: [
         "libfmq",
         "libsync",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
-        "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.0-vts",
-        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0-vts",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
     ],
-    test_suites: ["general-tests"],
+    disable_framework: true,
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index fa5ace6..b92279d 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -20,11 +20,14 @@
 #include <composer-vts/2.1/ComposerVts.h>
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
 #include <composer-vts/2.1/TestCommandReader.h>
+#include <gtest/gtest.h>
+#include <hardware/hwcomposer2.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <mapper-vts/2.0/MapperVts.h>
 #include <mapper-vts/3.0/MapperVts.h>
+#include <mapper-vts/4.0/MapperVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <unistd.h>
 
 #include <algorithm>
@@ -50,30 +53,11 @@
 using android::hardware::graphics::common::V1_0::Transform;
 using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
 
-// Test environment for graphics.composer
-class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static GraphicsComposerHidlEnvironment* Instance() {
-        static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IComposer>(); }
-
-   private:
-    GraphicsComposerHidlEnvironment() {}
-
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
-};
-
-class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
+  protected:
     void SetUp() override {
-        VtsHalHidlTargetTestBase::SetUp();
         ASSERT_NO_FATAL_FAILURE(
-            mComposer = std::make_unique<Composer>(
-                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+                mComposer = std::make_unique<Composer>(IComposer::getService(GetParam())));
         ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
 
         mComposerCallback = new GraphicsComposerCallback;
@@ -100,7 +84,6 @@
             EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
             EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
         }
-        VtsHalHidlTargetTestBase::TearDown();
     }
 
     // returns an invalid display id (one that has not been registered to a
@@ -149,7 +132,7 @@
  *
  * Test that IComposer::getCapabilities returns no invalid capabilities.
  */
-TEST_F(GraphicsComposerHidlTest, GetCapabilities) {
+TEST_P(GraphicsComposerHidlTest, GetCapabilities) {
     auto capabilities = mComposer->getCapabilities();
     ASSERT_EQ(capabilities.end(),
               std::find(capabilities.begin(), capabilities.end(), IComposer::Capability::INVALID));
@@ -158,7 +141,7 @@
 /**
  * Test IComposer::dumpDebugInfo.
  */
-TEST_F(GraphicsComposerHidlTest, DumpDebugInfo) {
+TEST_P(GraphicsComposerHidlTest, DumpDebugInfo) {
     mComposer->dumpDebugInfo();
 }
 
@@ -167,7 +150,7 @@
  *
  * Test that IComposerClient is a singleton.
  */
-TEST_F(GraphicsComposerHidlTest, CreateClientSingleton) {
+TEST_P(GraphicsComposerHidlTest, CreateClientSingleton) {
     mComposer->getRaw()->createClient(
         [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::NO_RESOURCES, tmpError); });
 }
@@ -178,7 +161,7 @@
  *
  * Test that virtual displays can be created and has the correct display type.
  */
-TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay) {
+TEST_P(GraphicsComposerHidlTest, CreateVirtualDisplay) {
     if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
         GTEST_SUCCEED() << "no virtual display support";
         return;
@@ -203,7 +186,7 @@
  * Test that passing a bad display handle to destroyVirtualDisplay
  * returns a BAD_DISPLAY error
  */
-TEST_F(GraphicsComposerHidlTest, DestroyVirtualDisplayBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, DestroyVirtualDisplayBadDisplay) {
     if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
         GTEST_SUCCEED() << "no virtual display support";
         return;
@@ -218,7 +201,7 @@
  *
  * Test that layers can be created and destroyed.
  */
-TEST_F(GraphicsComposerHidlTest, CreateLayer) {
+TEST_P(GraphicsComposerHidlTest, CreateLayer) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -232,7 +215,7 @@
  * Test that passing in an invalid display handle to createLayer returns
  * BAD_DISPLAY.
  */
-TEST_F(GraphicsComposerHidlTest, CreateLayerBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, CreateLayerBadDisplay) {
     Error error;
     mComposerClient->getRaw()->createLayer(
         mInvalidDisplayId, kBufferSlotCount,
@@ -246,7 +229,7 @@
  * Test that passing in an invalid display handle to destroyLayer returns
  * BAD_DISPLAY
  */
-TEST_F(GraphicsComposerHidlTest, DestroyLayerBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, DestroyLayerBadDisplay) {
     Error error;
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
@@ -265,7 +248,7 @@
  * Test that passing in an invalid layer handle to destroyLayer returns
  * BAD_LAYER
  */
-TEST_F(GraphicsComposerHidlTest, DestroyLayerBadLayerError) {
+TEST_P(GraphicsComposerHidlTest, DestroyLayerBadLayerError) {
     // We haven't created any layers yet, so any id should be invalid
     Error error = mComposerClient->getRaw()->destroyLayer(mPrimaryDisplay, 1);
 
@@ -278,7 +261,7 @@
  * Test that passing in a bad display handle to getActiveConfig generates a
  * BAD_DISPLAY error
  */
-TEST_F(GraphicsComposerHidlTest, GetActiveConfigBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetActiveConfigBadDisplay) {
     Error error;
     mComposerClient->getRaw()->getActiveConfig(
         mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; });
@@ -291,7 +274,7 @@
  * Test IComposerClient::getDisplayConfigs returns no error
  * when passed in a valid display
  */
-TEST_F(GraphicsComposerHidlTest, GetDisplayConfig) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayConfig) {
     std::vector<Config> configs;
     ASSERT_NO_FATAL_FAILURE(configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay));
 }
@@ -302,7 +285,7 @@
  * Test IComposerClient::getDisplayConfigs returns BAD_DISPLAY
  * when passed in an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, GetDisplayConfigBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayConfigBadDisplay) {
     Error error;
     mComposerClient->getRaw()->getDisplayConfigs(
         mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; });
@@ -312,7 +295,7 @@
 /**
  * Test IComposerClient::getDisplayName.
  */
-TEST_F(GraphicsComposerHidlTest, GetDisplayName) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayName) {
     mComposerClient->getDisplayName(mPrimaryDisplay);
 }
 
@@ -322,7 +305,7 @@
  * Test that IComposerClient::getDisplayType returns the correct display type
  * for the primary display.
  */
-TEST_F(GraphicsComposerHidlTest, GetDisplayType) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayType) {
     ASSERT_EQ(IComposerClient::DisplayType::PHYSICAL,
               mComposerClient->getDisplayType(mPrimaryDisplay));
 }
@@ -333,7 +316,7 @@
  * Test that IComposerClient::getClientTargetSupport returns true for the
  * required client targets.
  */
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport) {
     std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -356,7 +339,7 @@
  * Test that IComposerClient::getClientTargetSupport returns BAD_DISPLAY when
  * passed an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupportBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupportBadDisplay) {
     std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -380,7 +363,7 @@
  * Test that IComposerClient::getDisplayAttribute succeeds for the required
  * formats, and succeeds or fails correctly for optional attributes.
  */
-TEST_F(GraphicsComposerHidlTest, GetDisplayAttribute) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute) {
     std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         const std::array<IComposerClient::Attribute, 3> requiredAttributes = {{
@@ -406,7 +389,7 @@
 /**
  * Test IComposerClient::getHdrCapabilities.
  */
-TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities) {
+TEST_P(GraphicsComposerHidlTest, GetHdrCapabilities) {
     float maxLuminance;
     float maxAverageLuminance;
     float minLuminance;
@@ -417,7 +400,7 @@
 /**
  * Test IComposerClient::setClientTargetSlotCount.
  */
-TEST_F(GraphicsComposerHidlTest, SetClientTargetSlotCount) {
+TEST_P(GraphicsComposerHidlTest, SetClientTargetSlotCount) {
     mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
 }
 
@@ -427,7 +410,7 @@
  * Test that IComposerClient::setActiveConfig succeeds for all display
  * configs.
  */
-TEST_F(GraphicsComposerHidlTest, SetActiveConfig) {
+TEST_P(GraphicsComposerHidlTest, SetActiveConfig) {
     std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         mComposerClient->setActiveConfig(mPrimaryDisplay, config);
@@ -441,7 +424,7 @@
  * Test that config set during IComposerClient::setActiveConfig is maintained
  * during a display on/off power cycle
  */
-TEST_F(GraphicsComposerHidlTest, SetActiveConfigPowerCycle) {
+TEST_P(GraphicsComposerHidlTest, SetActiveConfigPowerCycle) {
     ASSERT_NO_FATAL_FAILURE(
         mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::OFF));
     ASSERT_NO_FATAL_FAILURE(
@@ -465,7 +448,7 @@
  *
  * Test that IComposerClient::getColorMode always returns ColorMode::NATIVE
  */
-TEST_F(GraphicsComposerHidlTest, GetColorModes) {
+TEST_P(GraphicsComposerHidlTest, GetColorModes) {
     std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
     auto nativeModeLocation = std::find(modes.begin(), modes.end(), ColorMode::NATIVE);
 
@@ -477,7 +460,7 @@
  *
  * Test that IComposerClient::setColorMode succeeds for all color modes.
  */
-TEST_F(GraphicsComposerHidlTest, SetColorMode) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode) {
     std::unordered_set<ColorMode> validModes;
     for (auto mode : hidl_enum_range<ColorMode>()) {
         validModes.insert(mode);
@@ -497,7 +480,7 @@
  * Test that IComposerClient::setColorMode returns BAD_DISPLAY for
  * an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, SetColorModeBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetColorModeBadDisplay) {
     std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
     for (auto mode : modes) {
         Error error = mComposerClient->getRaw()->setColorMode(mInvalidDisplayId, mode);
@@ -511,7 +494,7 @@
  * Test that IComposerClient::setColorMode returns BAD_PARAMETER when passed in
  * an invalid color mode
  */
-TEST_F(GraphicsComposerHidlTest, SetColorModeBadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetColorModeBadParameter) {
     Error error =
         mComposerClient->getRaw()->setColorMode(mPrimaryDisplay, static_cast<ColorMode>(-1));
     ASSERT_EQ(Error::BAD_PARAMETER, error);
@@ -523,7 +506,7 @@
  * Test that IComposerClient::getDozeSupport returns
  * BAD_DISPLAY when passed an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, GetDozeSupportBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetDozeSupportBadDisplay) {
     Error error;
     mComposerClient->getRaw()->getDozeSupport(
         mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; });
@@ -535,7 +518,7 @@
  *
  * Test that IComposerClient::setPowerMode succeeds for all power modes.
  */
-TEST_F(GraphicsComposerHidlTest, SetPowerMode) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode) {
     std::vector<IComposerClient::PowerMode> modes;
     modes.push_back(IComposerClient::PowerMode::OFF);
 
@@ -558,7 +541,7 @@
  * Test IComposerClient::setPowerMode succeeds with different
  * orderings of power modes
  */
-TEST_F(GraphicsComposerHidlTest, SetPowerModeVariations) {
+TEST_P(GraphicsComposerHidlTest, SetPowerModeVariations) {
     std::vector<IComposerClient::PowerMode> modes;
     modes.push_back(IComposerClient::PowerMode::OFF);
     modes.push_back(IComposerClient::PowerMode::ON);
@@ -609,7 +592,7 @@
  * Test IComposerClient::setPowerMode returns BAD_DISPLAY when passed an invalid
  * display handle
  */
-TEST_F(GraphicsComposerHidlTest, SetPowerModeBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetPowerModeBadDisplay) {
     Error error =
         mComposerClient->getRaw()->setPowerMode(mInvalidDisplayId, IComposerClient::PowerMode::ON);
     ASSERT_EQ(Error::BAD_DISPLAY, error);
@@ -621,7 +604,7 @@
  * Test that IComposerClient::setPowerMode returns UNSUPPORTED when passed DOZE
  * or DOZE_SUSPEND on devices that do not support DOZE/DOZE_SUSPEND
  */
-TEST_F(GraphicsComposerHidlTest, SetPowerModeUnsupported) {
+TEST_P(GraphicsComposerHidlTest, SetPowerModeUnsupported) {
     if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) {
         Error error = mComposerClient->getRaw()->setPowerMode(mPrimaryDisplay,
                                                               IComposerClient::PowerMode::DOZE);
@@ -639,7 +622,7 @@
  * Tests that IComposerClient::setPowerMode returns BAD_PARAMETER when passed an invalid
  * PowerMode
  */
-TEST_F(GraphicsComposerHidlTest, SetPowerModeBadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetPowerModeBadParameter) {
     Error error = mComposerClient->getRaw()->setPowerMode(
         mPrimaryDisplay, static_cast<IComposerClient::PowerMode>(-1));
     ASSERT_EQ(Error::BAD_PARAMETER, error);
@@ -651,7 +634,7 @@
  * Test that IComposerClient::setVsyncEnabled succeeds and there is no
  * spurious vsync events.
  */
-TEST_F(GraphicsComposerHidlTest, SetVsyncEnabled) {
+TEST_P(GraphicsComposerHidlTest, SetVsyncEnabled) {
     mComposerCallback->setVsyncAllowed(true);
 
     mComposerClient->setVsyncEnabled(mPrimaryDisplay, true);
@@ -703,7 +686,7 @@
 /**
  * Test IComposerClient::Command::SET_COLOR_TRANSFORM.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_COLOR_TRANSFORM) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_COLOR_TRANSFORM) {
     const std::array<float, 16> identity = {{
         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
         1.0f,
@@ -718,7 +701,7 @@
 /**
  * Test IComposerClient::Command::SET_CLIENT_TARGET.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_CLIENT_TARGET) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_CLIENT_TARGET) {
     mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount);
 
     mWriter->selectDisplay(mPrimaryDisplay);
@@ -731,7 +714,7 @@
 /**
  * Test IComposerClient::Command::SET_OUTPUT_BUFFER.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) {
     if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
         GTEST_SUCCEED() << "no virtual display support";
         return;
@@ -754,7 +737,7 @@
 /**
  * Test IComposerClient::Command::VALIDATE_DISPLAY.
  */
-TEST_F(GraphicsComposerHidlCommandTest, VALIDATE_DISPLAY) {
+TEST_P(GraphicsComposerHidlCommandTest, VALIDATE_DISPLAY) {
     mWriter->selectDisplay(mPrimaryDisplay);
     mWriter->validateDisplay();
     execute();
@@ -763,7 +746,7 @@
 /**
  * Test IComposerClient::Command::ACCEPT_DISPLAY_CHANGES.
  */
-TEST_F(GraphicsComposerHidlCommandTest, ACCEPT_DISPLAY_CHANGES) {
+TEST_P(GraphicsComposerHidlCommandTest, ACCEPT_DISPLAY_CHANGES) {
     mWriter->selectDisplay(mPrimaryDisplay);
     mWriter->validateDisplay();
     mWriter->acceptDisplayChanges();
@@ -773,7 +756,7 @@
 /**
  * Test IComposerClient::Command::PRESENT_DISPLAY.
  */
-TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) {
+TEST_P(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) {
     mWriter->selectDisplay(mPrimaryDisplay);
     mWriter->validateDisplay();
     mWriter->presentDisplay();
@@ -787,7 +770,13 @@
  * additional call to validateDisplay when only the layer buffer handle and
  * surface damage have been set
  */
-TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
+TEST_P(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
+    if (!mComposer->hasCapability(
+                static_cast<IComposer::Capability>(HWC2_CAPABILITY_SKIP_VALIDATE))) {
+        std::cout << "Device does not have skip validate capability, skipping" << std::endl;
+        GTEST_SUCCEED();
+        return;
+    }
     mWriter->selectDisplay(mPrimaryDisplay);
     mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON);
     mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE);
@@ -837,7 +826,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_CURSOR_POSITION.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -879,7 +868,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_BUFFER.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) {
     auto handle = allocate();
     ASSERT_NE(nullptr, handle);
 
@@ -896,7 +885,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -915,7 +904,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_BLEND_MODE.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -931,7 +920,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_COLOR.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -946,7 +935,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -963,7 +952,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_DATASPACE.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -977,7 +966,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_DISPLAY_FRAME.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -991,7 +980,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_PLANE_ALPHA.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -1006,7 +995,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) {
     if (!mComposer->hasCapability(IComposer::Capability::SIDEBAND_STREAM)) {
         GTEST_SUCCEED() << "no sideband stream support";
         return;
@@ -1028,7 +1017,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_SOURCE_CROP.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -1042,7 +1031,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_TRANSFORM.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -1063,7 +1052,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_VISIBLE_REGION.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -1082,7 +1071,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_Z_ORDER.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -1094,6 +1083,16 @@
     execute();
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerHidlCommandTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 }  // namespace
 }  // namespace vts
 }  // namespace V2_1
@@ -1101,13 +1100,3 @@
 }  // namespace graphics
 }  // namespace hardware
 }  // namespace android
-
-int main(int argc, char** argv) {
-    using android::hardware::graphics::composer::V2_1::vts::GraphicsComposerHidlEnvironment;
-    ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
diff --git a/graphics/composer/2.2/default/Android.mk b/graphics/composer/2.2/default/Android.mk
index 4916557..156ecb6 100644
--- a/graphics/composer/2.2/default/Android.mk
+++ b/graphics/composer/2.2/default/Android.mk
@@ -11,8 +11,8 @@
 LOCAL_SHARED_LIBRARIES := \
         android.hardware.graphics.composer@2.1 \
         android.hardware.graphics.composer@2.2 \
-        android.hardware.graphics.mapper@2.0 \
-        android.hardware.graphics.mapper@3.0 \
+        android.hardware.graphics.composer@2.1-resources \
+        android.hardware.graphics.composer@2.2-resources \
         libbase \
         libbinder \
         libcutils \
diff --git a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
index 0d7e86f..efe6dad 100644
--- a/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
+++ b/graphics/composer/2.2/default/android.hardware.graphics.composer@2.2-service.rc
@@ -1,6 +1,4 @@
 service vendor.hwcomposer-2-2 /vendor/bin/hw/android.hardware.graphics.composer@2.2-service
-    interface android.hardware.graphics.composer@2.1::IComposer default
-    interface android.hardware.graphics.composer@2.2::IComposer default
     class hal animation
     user system
     group graphics drmrpc
diff --git a/graphics/composer/2.2/utils/OWNERS b/graphics/composer/2.2/utils/OWNERS
index a17a50c..3f1e82c 100644
--- a/graphics/composer/2.2/utils/OWNERS
+++ b/graphics/composer/2.2/utils/OWNERS
@@ -3,7 +3,3 @@
 lpy@google.com
 stoza@google.com
 vhau@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
diff --git a/graphics/composer/2.2/utils/command-buffer/Android.bp b/graphics/composer/2.2/utils/command-buffer/Android.bp
index efaabd4..c4ceaab 100644
--- a/graphics/composer/2.2/utils/command-buffer/Android.bp
+++ b/graphics/composer/2.2/utils/command-buffer/Android.bp
@@ -3,11 +3,16 @@
     defaults: ["hidl_defaults"],
     vendor_available: true,
     shared_libs: [
-        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+    ],
+    export_shared_lib_headers: [
         "android.hardware.graphics.composer@2.2",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
     ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
     export_include_dirs: ["include"],
 }
diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
index 138d700..00f427a 100644
--- a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
+++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
@@ -76,15 +76,14 @@
 
     static constexpr uint16_t kSetLayerFloatColorLength = 4;
     void setLayerFloatColor(IComposerClient::FloatColor color) {
-        beginCommand_2_2(IComposerClient::Command::SET_LAYER_FLOAT_COLOR,
-                         kSetLayerFloatColorLength);
+        beginCommand(IComposerClient::Command::SET_LAYER_FLOAT_COLOR, kSetLayerFloatColorLength);
         writeFloatColor(color);
         endCommand();
     }
 
     void setLayerPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
-        beginCommand_2_2(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
-                         metadataVec.size() * 2);
+        beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
+                     metadataVec.size() * 2);
         for (const auto& metadata : metadataVec) {
             writeSigned(static_cast<int32_t>(metadata.key));
             writeFloat(metadata.value);
@@ -93,11 +92,6 @@
     }
 
    protected:
-    void beginCommand_2_2(IComposerClient::Command command, uint16_t length) {
-        V2_1::CommandWriterBase::beginCommand(
-            static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
-    }
-
     void writeFloatColor(const IComposerClient::FloatColor& color) {
         writeFloat(color.r);
         writeFloat(color.g);
diff --git a/graphics/composer/2.2/utils/hal/Android.bp b/graphics/composer/2.2/utils/hal/Android.bp
index 10dcae4..f334a11 100644
--- a/graphics/composer/2.2/utils/hal/Android.bp
+++ b/graphics/composer/2.2/utils/hal/Android.bp
@@ -19,9 +19,11 @@
     vendor_available: true,
     shared_libs: [
         "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.2-resources",
     ],
     export_shared_lib_headers: [
         "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.2-resources",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.2-command-buffer",
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
index c760d0a..512d39d 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
@@ -24,7 +24,7 @@
 #include <composer-hal/2.1/ComposerClient.h>
 #include <composer-hal/2.2/ComposerCommandEngine.h>
 #include <composer-hal/2.2/ComposerHal.h>
-#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-resources/2.2/ComposerResources.h>
 
 namespace android {
 namespace hardware {
@@ -89,7 +89,7 @@
 
         auto resources = static_cast<ComposerResources*>(mResources.get());
         const native_handle_t* readbackBuffer;
-        ComposerResources::ReplacedBufferHandle replacedReadbackBuffer;
+        ComposerResources::ReplacedHandle replacedReadbackBuffer(true);
         error = resources->getDisplayReadbackBuffer(display, buffer.getNativeHandle(),
                                                     &readbackBuffer, &replacedReadbackBuffer);
         if (error != Error::NONE) {
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
index 97e3a9e..8d70ba2 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
@@ -23,7 +23,7 @@
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <composer-hal/2.1/ComposerCommandEngine.h>
 #include <composer-hal/2.2/ComposerHal.h>
-#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-resources/2.2/ComposerResources.h>
 
 namespace android {
 namespace hardware {
@@ -49,6 +49,11 @@
         }
     }
 
+    std::unique_ptr<V2_1::CommandWriterBase> createCommandWriter(
+            size_t writerInitialSize) override {
+        return std::make_unique<CommandWriterBase>(writerInitialSize);
+    }
+
     bool executeSetLayerPerFrameMetadata(uint16_t length) {
         // (key, value) pairs
         if (length % 2 != 0) {
@@ -65,7 +70,7 @@
 
         auto err = mHal->setLayerPerFrameMetadata(mCurrentDisplay, mCurrentLayer, metadata);
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -78,7 +83,7 @@
 
         auto err = mHal->setLayerFloatColor(mCurrentDisplay, mCurrentLayer, readFloatColor());
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
deleted file mode 100644
index 85b6651..0000000
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
+++ /dev/null
@@ -1,105 +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.
- */
-
-#pragma once
-
-#ifndef LOG_TAG
-#warning "ComposerResources.h included without LOG_TAG"
-#endif
-
-#include <composer-hal/2.1/ComposerResources.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_2 {
-namespace hal {
-
-using V2_1::hal::ComposerHandleCache;
-using V2_1::hal::ComposerHandleImporter;
-
-class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource {
-   public:
-    ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
-                            uint32_t outputBufferCacheSize)
-        : V2_1::hal::ComposerDisplayResource(type, importer, outputBufferCacheSize),
-          mReadbackBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, 1) {}
-
-    Error getReadbackBuffer(const native_handle_t* inHandle, const native_handle_t** outHandle,
-                            const native_handle** outReplacedHandle) {
-        const uint32_t slot = 0;
-        const bool fromCache = false;
-        return mReadbackBufferCache.getHandle(slot, fromCache, inHandle, outHandle,
-                                              outReplacedHandle);
-    }
-
-   protected:
-    ComposerHandleCache mReadbackBufferCache;
-};
-
-class ComposerResources : public V2_1::hal::ComposerResources {
-   public:
-    static std::unique_ptr<ComposerResources> create() {
-        auto resources = std::make_unique<ComposerResources>();
-        return resources->init() ? std::move(resources) : nullptr;
-    }
-
-    Error getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
-                                   const native_handle_t** outHandle,
-                                   ReplacedBufferHandle* outReplacedHandle) {
-        // import buffer
-        const native_handle_t* importedHandle;
-        Error error = mImporter.importBuffer(rawHandle, &importedHandle);
-        if (error != Error::NONE) {
-            return error;
-        }
-
-        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-
-        auto iter = mDisplayResources.find(display);
-        if (iter == mDisplayResources.end()) {
-            mImporter.freeBuffer(importedHandle);
-            return Error::BAD_DISPLAY;
-        }
-        ComposerDisplayResource& displayResource =
-            *static_cast<ComposerDisplayResource*>(iter->second.get());
-
-        // update cache
-        const native_handle_t* replacedHandle;
-        error = displayResource.getReadbackBuffer(importedHandle, outHandle, &replacedHandle);
-        if (error != Error::NONE) {
-            mImporter.freeBuffer(importedHandle);
-            return error;
-        }
-
-        outReplacedHandle->reset(&mImporter, replacedHandle);
-        return Error::NONE;
-    }
-
-   protected:
-    std::unique_ptr<V2_1::hal::ComposerDisplayResource> createDisplayResource(
-        ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
-        return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
-    }
-};
-
-}  // namespace hal
-}  // namespace V2_2
-}  // namespace composer
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
index 93da0a5..9b3aa90 100644
--- a/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
+++ b/graphics/composer/2.2/utils/passthrough/include/composer-passthrough/2.2/HwcHal.h
@@ -173,6 +173,14 @@
     Error getRenderIntents(Display display, ColorMode mode,
                            std::vector<RenderIntent>* outIntents) override {
         if (!mDispatch.getRenderIntents) {
+            IComposerClient::DisplayType type;
+            if (getDisplayType(display, &type) == Error::BAD_DISPLAY) {
+                return Error::BAD_DISPLAY;
+            }
+            if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3) {
+                return Error::BAD_PARAMETER;
+            }
+
             *outIntents = std::vector<RenderIntent>({RenderIntent::COLORIMETRIC});
             return Error::NONE;
         }
@@ -199,6 +207,9 @@
 
     Error setColorMode_2_2(Display display, ColorMode mode, RenderIntent intent) override {
         if (!mDispatch.setColorModeWithRenderIntent) {
+            if (intent < RenderIntent::COLORIMETRIC || intent > RenderIntent::TONE_MAP_ENHANCE) {
+                return Error::BAD_PARAMETER;
+            }
             if (intent != RenderIntent::COLORIMETRIC) {
                 return Error::UNSUPPORTED;
             }
@@ -282,6 +293,7 @@
    private:
     using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
     using BaseType2_1::getColorModes;
+    using BaseType2_1::getDisplayType;
     using BaseType2_1::mDevice;
     using BaseType2_1::setColorMode;
     using BaseType2_1::createVirtualDisplay;
diff --git a/graphics/composer/2.2/utils/resources/Android.bp b/graphics/composer/2.2/utils/resources/Android.bp
new file mode 100644
index 0000000..752eb81
--- /dev/null
+++ b/graphics/composer/2.2/utils/resources/Android.bp
@@ -0,0 +1,29 @@
+//
+// 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_library_shared {
+    name: "android.hardware.graphics.composer@2.2-resources",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1-resources",
+        "android.hardware.graphics.composer@2.2",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.composer@2.1-resources",
+        "android.hardware.graphics.composer@2.2",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/resources/ComposerResources.cpp b/graphics/composer/2.2/utils/resources/ComposerResources.cpp
new file mode 100644
index 0000000..a0610a3
--- /dev/null
+++ b/graphics/composer/2.2/utils/resources/ComposerResources.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 "ComposerResources 2.2"
+
+#include "composer-resources/2.2/ComposerResources.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+using V2_1::hal::ComposerHandleCache;
+using V2_1::hal::ComposerHandleImporter;
+
+Error ComposerDisplayResource::getReadbackBuffer(const native_handle_t* inHandle,
+                                                 const native_handle_t** outHandle,
+                                                 const native_handle** outReplacedHandle) {
+    const uint32_t slot = 0;
+    const bool fromCache = false;
+    return mReadbackBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+std::unique_ptr<ComposerResources> ComposerResources::create() {
+    auto resources = std::make_unique<ComposerResources>();
+    return resources->init() ? std::move(resources) : nullptr;
+}
+
+Error ComposerResources::getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
+                                                  const native_handle_t** outHandle,
+                                                  ReplacedHandle* outReplacedHandle) {
+    // import buffer
+    const native_handle_t* importedHandle;
+    Error error = mImporter.importBuffer(rawHandle, &importedHandle);
+    if (error != Error::NONE) {
+        return error;
+    }
+
+    std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+    auto iter = mDisplayResources.find(display);
+    if (iter == mDisplayResources.end()) {
+        mImporter.freeBuffer(importedHandle);
+        return Error::BAD_DISPLAY;
+    }
+    ComposerDisplayResource& displayResource =
+            *static_cast<ComposerDisplayResource*>(iter->second.get());
+
+    // update cache
+    const native_handle_t* replacedHandle;
+    error = displayResource.getReadbackBuffer(importedHandle, outHandle, &replacedHandle);
+    if (error != Error::NONE) {
+        mImporter.freeBuffer(importedHandle);
+        return error;
+    }
+
+    outReplacedHandle->reset(&mImporter, replacedHandle);
+    return Error::NONE;
+}
+
+}  // namespace hal
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
new file mode 100644
index 0000000..33012e9
--- /dev/null
+++ b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerResources.h included without LOG_TAG"
+#endif
+
+#include <composer-resources/2.1/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+using V2_1::hal::ComposerHandleCache;
+using V2_1::hal::ComposerHandleImporter;
+
+class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource {
+  public:
+    ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+                            uint32_t outputBufferCacheSize)
+        : V2_1::hal::ComposerDisplayResource(type, importer, outputBufferCacheSize),
+          mReadbackBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, 1) {}
+
+    Error getReadbackBuffer(const native_handle_t* inHandle, const native_handle_t** outHandle,
+                            const native_handle** outReplacedHandle) {
+        const uint32_t slot = 0;
+        const bool fromCache = false;
+        return mReadbackBufferCache.getHandle(slot, fromCache, inHandle, outHandle,
+                                              outReplacedHandle);
+    }
+
+  protected:
+    ComposerHandleCache mReadbackBufferCache;
+};
+
+class ComposerResources : public V2_1::hal::ComposerResources {
+  public:
+    static std::unique_ptr<ComposerResources> create() {
+        auto resources = std::make_unique<ComposerResources>();
+        return resources->init() ? std::move(resources) : nullptr;
+    }
+
+    Error getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
+                                   const native_handle_t** outHandle,
+                                   ReplacedHandle* outReplacedHandle) {
+        // import buffer
+        const native_handle_t* importedHandle;
+        Error error = mImporter.importBuffer(rawHandle, &importedHandle);
+        if (error != Error::NONE) {
+            return error;
+        }
+
+        std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+        auto iter = mDisplayResources.find(display);
+        if (iter == mDisplayResources.end()) {
+            mImporter.freeBuffer(importedHandle);
+            return Error::BAD_DISPLAY;
+        }
+        ComposerDisplayResource& displayResource =
+                *static_cast<ComposerDisplayResource*>(iter->second.get());
+
+        // update cache
+        const native_handle_t* replacedHandle;
+        error = displayResource.getReadbackBuffer(importedHandle, outHandle, &replacedHandle);
+        if (error != Error::NONE) {
+            mImporter.freeBuffer(importedHandle);
+            return error;
+        }
+
+        outReplacedHandle->reset(&mImporter, replacedHandle);
+        return Error::NONE;
+    }
+
+  protected:
+    std::unique_ptr<V2_1::hal::ComposerDisplayResource> createDisplayResource(
+            ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
+        return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
+    }
+};
+
+}  // namespace hal
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index dd979cb..a8bb1a2 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -19,26 +19,35 @@
     defaults: ["hidl_defaults"],
     srcs: [
         "ComposerVts.cpp",
+        "ReadbackVts.cpp",
+        "RenderEngineVts.cpp",
+    ],
+    shared_libs: [
+        "libui",
     ],
     static_libs: [
-        "VtsHalHidlTargetTestBase",
-        "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
-        "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@2.1-vts",
+        "libarect",
+        "libgtest",
+        "libmath",
+        "libnativewindow",
+        "librenderengine",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hardware.graphics.mapper@4.0-vts",
     ],
     export_static_lib_headers: [
         "android.hardware.graphics.composer@2.1-vts",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.mapper@2.1-vts",
     ],
     header_libs: [
-        "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
     ],
     export_header_lib_headers: [
-        "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
     ],
     cflags: [
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index cd6772a..a526137 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -16,7 +16,6 @@
 
 #include <composer-vts/2.2/ComposerVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <hidl/HidlTransportUtils.h>
 
@@ -182,17 +181,23 @@
 
 Gralloc::Gralloc() {
     [this] {
-        ALOGD("Attempting to initialize gralloc3");
-        ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+        ALOGD("Attempting to initialize gralloc4");
+        ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
                                                                        /*errOnFailure=*/false));
-        if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) {
-            mGralloc3 = nullptr;
-            ALOGD("Failed to create gralloc3, initializing gralloc2_1");
-            mGralloc2_1 = std::make_shared<Gralloc2_1>(/*errOnFailure*/ false);
-            if (!mGralloc2_1->getMapper()) {
-                mGralloc2_1 = nullptr;
-                ALOGD("Failed to create gralloc2_1, initializing gralloc2");
-                ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+        if (mGralloc4->getMapper() == nullptr || mGralloc4->getAllocator() == nullptr) {
+            mGralloc4 = nullptr;
+            ALOGD("Failed to initialize gralloc4, initializing gralloc3");
+            ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+                                                                           /*errOnFailure=*/false));
+            if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) {
+                mGralloc3 = nullptr;
+                ALOGD("Failed to initialize gralloc3, initializing gralloc2_1");
+                mGralloc2_1 = std::make_shared<Gralloc2_1>(/*errOnFailure*/ false);
+                if (!mGralloc2_1->getMapper()) {
+                    mGralloc2_1 = nullptr;
+                    ALOGD("Failed to initialize gralloc2_1, initializing gralloc2");
+                    ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+                }
             }
         }
     }();
@@ -201,7 +206,15 @@
 bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, uint32_t width,
                                  uint32_t height, uint32_t layerCount, PixelFormat format,
                                  uint64_t usage, uint32_t stride) {
-    if (mGralloc3) {
+    if (mGralloc4) {
+        IMapper4::BufferDescriptorInfo info{};
+        info.width = width;
+        info.height = height;
+        info.layerCount = layerCount;
+        info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+        info.usage = usage;
+        return mGralloc4->validateBufferSize(bufferHandle, info, stride);
+    } else if (mGralloc3) {
         IMapper3::BufferDescriptorInfo info{};
         info.width = width;
         info.height = height;
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
new file mode 100644
index 0000000..7bb9121
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -0,0 +1,355 @@
+/*
+ * 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.
+ */
+
+#include <composer-vts/2.2/ReadbackVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+void TestLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
+    writer->selectLayer(mLayer);
+    writer->setLayerDisplayFrame(mDisplayFrame);
+    writer->setLayerSourceCrop(mSourceCrop);
+    writer->setLayerZOrder(mZOrder);
+    writer->setLayerSurfaceDamage(mSurfaceDamage);
+    writer->setLayerTransform(mTransform);
+    writer->setLayerPlaneAlpha(mAlpha);
+    writer->setLayerBlendMode(mBlendMode);
+}
+
+const std::vector<ColorMode> ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3};
+const std::vector<Dataspace> ReadbackHelper::dataspaces = {Dataspace::V0_SRGB,
+                                                           Dataspace::DISPLAY_P3};
+
+std::string ReadbackHelper::getColorModeString(ColorMode mode) {
+    switch (mode) {
+        case ColorMode::SRGB:
+            return std::string("SRGB");
+        case ColorMode::DISPLAY_P3:
+            return std::string("DISPLAY_P3");
+        default:
+            return std::string("Unsupported color mode for readback");
+    }
+}
+
+std::string ReadbackHelper::getDataspaceString(Dataspace dataspace) {
+    switch (dataspace) {
+        case Dataspace::V0_SRGB:
+            return std::string("V0_SRGB");
+        case Dataspace::DISPLAY_P3:
+            return std::string("DISPLAY_P3");
+        case Dataspace::UNKNOWN:
+            return std::string("UNKNOWN");
+        default:
+            return std::string("Unsupported dataspace for readback");
+    }
+}
+
+Dataspace ReadbackHelper::getDataspaceForColorMode(ColorMode mode) {
+    switch (mode) {
+        case ColorMode::DISPLAY_P3:
+            return Dataspace::DISPLAY_P3;
+        case ColorMode::SRGB:
+        default:
+            return Dataspace::UNKNOWN;
+    }
+}
+
+LayerSettings TestLayer::toRenderEngineLayerSettings() {
+    LayerSettings layerSettings;
+
+    layerSettings.alpha = half(mAlpha);
+    layerSettings.disableBlending = mBlendMode == IComposerClient::BlendMode::NONE;
+    layerSettings.geometry.boundaries = FloatRect(
+            static_cast<float>(mDisplayFrame.left), static_cast<float>(mDisplayFrame.top),
+            static_cast<float>(mDisplayFrame.right), static_cast<float>(mDisplayFrame.bottom));
+
+    const mat4 translation = mat4::translate(
+            vec4((mTransform & Transform::FLIP_H ? -mDisplayFrame.right : 0.0f),
+                 (mTransform & Transform::FLIP_V ? -mDisplayFrame.bottom : 0.0f), 0.0f, 1.0f));
+
+    const mat4 scale = mat4::scale(vec4(mTransform & Transform::FLIP_H ? -1.0f : 1.0f,
+                                        mTransform & Transform::FLIP_V ? -1.0f : 1.0f, 1.0f, 1.0f));
+
+    layerSettings.geometry.positionTransform = scale * translation;
+
+    return layerSettings;
+}
+
+int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) {
+    switch (pixelFormat) {
+        case PixelFormat::RGBA_8888:
+            return 4;
+        case PixelFormat::RGB_888:
+            return 3;
+        default:
+            return -1;
+    }
+}
+
+void ReadbackHelper::fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
+                                PixelFormat pixelFormat,
+                                std::vector<IComposerClient::Color> desiredPixelColors) {
+    ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == PixelFormat::RGBA_8888);
+    int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
+    ASSERT_NE(-1, bytesPerPixel);
+    for (int row = 0; row < height; row++) {
+        for (int col = 0; col < width; col++) {
+            int pixel = row * width + col;
+            IComposerClient::Color srcColor = desiredPixelColors[pixel];
+
+            int offset = (row * stride + col) * bytesPerPixel;
+            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+            pixelColor[0] = srcColor.r;
+            pixelColor[1] = srcColor.g;
+            pixelColor[2] = srcColor.b;
+
+            if (bytesPerPixel == 4) {
+                pixelColor[3] = srcColor.a;
+            }
+        }
+    }
+}
+
+void ReadbackHelper::clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
+                                 int32_t height, int32_t displayWidth) {
+    for (int row = 0; row < height; row++) {
+        for (int col = 0; col < width; col++) {
+            int pixel = row * displayWidth + col;
+            expectedColors[pixel] = BLACK;
+        }
+    }
+}
+
+void ReadbackHelper::fillColorsArea(std::vector<IComposerClient::Color>& expectedColors,
+                                    int32_t stride, IComposerClient::Rect area,
+                                    IComposerClient::Color color) {
+    for (int row = area.top; row < area.bottom; row++) {
+        for (int col = area.left; col < area.right; col++) {
+            int pixel = row * stride + col;
+            expectedColors[pixel] = color;
+        }
+    }
+}
+
+bool ReadbackHelper::readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
+                                       const Error error) {
+    if (error != Error::NONE) {
+        return false;
+    }
+    // TODO: add support for RGBA_1010102
+    if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
+        return false;
+    }
+    if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
+        return false;
+    }
+    return true;
+}
+
+void ReadbackHelper::compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
+                                         void* bufferData, const uint32_t stride,
+                                         const uint32_t width, const uint32_t height,
+                                         const PixelFormat pixelFormat) {
+    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+    ASSERT_NE(-1, bytesPerPixel);
+    for (int row = 0; row < height; row++) {
+        for (int col = 0; col < width; col++) {
+            int pixel = row * width + col;
+            int offset = (row * stride + col) * bytesPerPixel;
+            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+
+            ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
+            ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
+            ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
+        }
+    }
+}
+
+ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
+                               const std::shared_ptr<Gralloc>& gralloc, uint32_t width,
+                               uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) {
+    mDisplay = display;
+
+    mComposerClient = client;
+    mGralloc = gralloc;
+
+    mPixelFormat = pixelFormat;
+    mDataspace = dataspace;
+
+    mWidth = width;
+    mHeight = height;
+    mLayerCount = 1;
+    mFormat = mPixelFormat;
+    mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
+
+    mAccessRegion.top = 0;
+    mAccessRegion.left = 0;
+    mAccessRegion.width = width;
+    mAccessRegion.height = height;
+}
+
+ReadbackBuffer::~ReadbackBuffer() {
+    if (mBufferHandle != nullptr) {
+        mGralloc->freeBuffer(mBufferHandle);
+    }
+}
+
+void ReadbackBuffer::setReadbackBuffer() {
+    if (mBufferHandle != nullptr) {
+        mGralloc->freeBuffer(mBufferHandle);
+        mBufferHandle = nullptr;
+    }
+    mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
+                                       /*import*/ true, &mStride);
+    ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
+                                                  mFormat, mUsage, mStride));
+    ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1));
+}
+
+void ReadbackBuffer::checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
+    // lock buffer for reading
+    int32_t fenceHandle;
+    ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
+
+    void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, fenceHandle);
+    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
+    ReadbackHelper::compareColorBuffers(expectedColors, bufData, mStride, mWidth, mHeight,
+                                        mPixelFormat);
+    int32_t unlockFence = mGralloc->unlock(mBufferHandle);
+    if (unlockFence != -1) {
+        sync_wait(unlockFence, -1);
+        close(unlockFence);
+    }
+}
+
+void TestColorLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
+    TestLayer::write(writer);
+    writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
+    writer->setLayerColor(mColor);
+}
+
+LayerSettings TestColorLayer::toRenderEngineLayerSettings() {
+    LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
+
+    layerSettings.source.solidColor =
+            half3(static_cast<half>(mColor.r) / 255.0, static_cast<half>(mColor.g) / 255.0,
+                  static_cast<half>(mColor.b) / 255.0);
+    layerSettings.alpha = mAlpha * (static_cast<half>(mColor.a) / 255.0);
+    return layerSettings;
+}
+
+TestBufferLayer::TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
+                                 const std::shared_ptr<Gralloc>& gralloc, Display display,
+                                 int32_t width, int32_t height, PixelFormat format,
+                                 IComposerClient::Composition composition)
+    : TestLayer{client, display} {
+    mGralloc = gralloc;
+    mComposition = composition;
+    mWidth = width;
+    mHeight = height;
+    mLayerCount = 1;
+    mFormat = format;
+    mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                   BufferUsage::COMPOSER_OVERLAY);
+
+    mAccessRegion.top = 0;
+    mAccessRegion.left = 0;
+    mAccessRegion.width = width;
+    mAccessRegion.height = height;
+
+    setSourceCrop({0, 0, (float)width, (float)height});
+}
+
+TestBufferLayer::~TestBufferLayer() {
+    if (mBufferHandle != nullptr) {
+        mGralloc->freeBuffer(mBufferHandle);
+    }
+}
+
+void TestBufferLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
+    TestLayer::write(writer);
+    writer->setLayerCompositionType(mComposition);
+    writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame));
+    if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence);
+}
+
+LayerSettings TestBufferLayer::toRenderEngineLayerSettings() {
+    LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
+    layerSettings.source.buffer.buffer =
+            new GraphicBuffer(mBufferHandle, GraphicBuffer::CLONE_HANDLE, mWidth, mHeight,
+                              static_cast<int32_t>(mFormat), 1, mUsage, mStride);
+
+    layerSettings.source.buffer.usePremultipliedAlpha =
+            mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED;
+
+    const float scaleX = (mSourceCrop.right - mSourceCrop.left) / (mWidth);
+    const float scaleY = (mSourceCrop.bottom - mSourceCrop.top) / (mHeight);
+    const float translateX = mSourceCrop.left / (mWidth);
+    const float translateY = mSourceCrop.top / (mHeight);
+
+    layerSettings.source.buffer.textureTransform =
+            mat4::translate(vec4(translateX, translateY, 0, 1)) *
+            mat4::scale(vec4(scaleX, scaleY, 1.0, 1.0));
+
+    return layerSettings;
+}
+
+void TestBufferLayer::fillBuffer(std::vector<IComposerClient::Color> expectedColors) {
+    void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, -1);
+    ASSERT_NO_FATAL_FAILURE(
+            ReadbackHelper::fillBuffer(mWidth, mHeight, mStride, bufData, mFormat, expectedColors));
+    mFillFence = mGralloc->unlock(mBufferHandle);
+    if (mFillFence != -1) {
+        sync_wait(mFillFence, -1);
+        close(mFillFence);
+    }
+}
+
+void TestBufferLayer::setBuffer(std::vector<IComposerClient::Color> colors) {
+    if (mBufferHandle != nullptr) {
+        mGralloc->freeBuffer(mBufferHandle);
+        mBufferHandle = nullptr;
+    }
+    mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
+                                       /*import*/ true, &mStride);
+    ASSERT_NE(nullptr, mBufferHandle);
+    ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
+    ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
+                                                  mFormat, mUsage, mStride));
+}
+
+void TestBufferLayer::setDataspace(Dataspace dataspace,
+                                   const std::shared_ptr<CommandWriterBase>& writer) {
+    writer->selectLayer(mLayer);
+    writer->setLayerDataspace(dataspace);
+}
+
+void TestBufferLayer::setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) {
+    writer->selectLayer(mLayer);
+    writer->setLayerCompositionType(IComposerClient::Composition::CLIENT);
+}
+
+}  // namespace vts
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
new file mode 100644
index 0000000..c78c358
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#include <composer-vts/2.2/RenderEngineVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+using mapper::V2_1::IMapper;
+using renderengine::DisplaySettings;
+using renderengine::LayerSettings;
+using renderengine::RenderEngineCreationArgs;
+
+TestRenderEngine::TestRenderEngine(const RenderEngineCreationArgs& args) {
+    mFormat = static_cast<common::V1_1::PixelFormat>(args.pixelFormat);
+    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 {
+             return lhs->mZOrder < rhs->mZOrder;
+         });
+
+    if (!mCompositionLayers.empty()) {
+        mCompositionLayers.clear();
+    }
+    for (auto& layer : layers) {
+        LayerSettings settings = layer->toRenderEngineLayerSettings();
+        mCompositionLayers.push_back(settings);
+    }
+}
+
+void TestRenderEngine::initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
+                                         uint64_t usage) {
+    mGraphicBuffer =
+            new GraphicBuffer(width, height, static_cast<int32_t>(mFormat), layerCount, usage);
+}
+
+void TestRenderEngine::drawLayers() {
+    base::unique_fd bufferFence;
+    base::unique_fd readyFence;
+
+    std::vector<const renderengine::LayerSettings*> compositionLayerPointers;
+    compositionLayerPointers.reserve(mCompositionLayers.size());
+    std::transform(mCompositionLayers.begin(), mCompositionLayers.end(),
+                   std::back_insert_iterator(compositionLayerPointers),
+                   [](renderengine::LayerSettings& settings) -> renderengine::LayerSettings* {
+                       return &settings;
+                   });
+    mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers,
+                              mGraphicBuffer->getNativeBuffer(), true, std::move(bufferFence),
+                              &readyFence);
+    int fd = readyFence.release();
+    if (fd != -1) {
+        ASSERT_EQ(0, sync_wait(fd, -1));
+        ASSERT_EQ(0, close(fd));
+    }
+}
+
+void TestRenderEngine::checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors) {
+    void* bufferData;
+    ASSERT_EQ(0, mGraphicBuffer->lock(mGraphicBuffer->getUsage(), &bufferData));
+    ReadbackHelper::compareColorBuffers(expectedColors, bufferData, mGraphicBuffer->getStride(),
+                                        mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
+                                        mFormat);
+    ASSERT_EQ(0, mGraphicBuffer->unlock());
+}
+
+}  // namespace vts
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 8fa9b7b..6bc2732 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -22,7 +22,6 @@
 #include <unordered_set>
 #include <vector>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android/hardware/graphics/composer/2.2/IComposer.h>
 #include <android/hardware/graphics/composer/2.2/IComposerClient.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
@@ -44,9 +43,11 @@
 using common::V1_1::RenderIntent;
 using IMapper2_1 = android::hardware::graphics::mapper::V2_1::IMapper;
 using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
 using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
 using Gralloc2_1 = android::hardware::graphics::mapper::V2_1::vts::Gralloc;
 using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
+using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
 
 class ComposerClient;
 
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
new file mode 100644
index 0000000..d5eedf1
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.2/ComposerVts.h>
+#include <mapper-vts/2.1/MapperVts.h>
+#include <renderengine/RenderEngine.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+using android::hardware::hidl_handle;
+using common::V1_1::BufferUsage;
+using common::V1_1::Dataspace;
+using common::V1_1::PixelFormat;
+using IMapper2_1 = mapper::V2_1::IMapper;
+using Gralloc2_1 = mapper::V2_1::vts::Gralloc;
+using renderengine::LayerSettings;
+using V2_1::Display;
+using V2_1::Layer;
+using V2_1::vts::AccessRegion;
+using V2_1::vts::TestCommandReader;
+
+static const IComposerClient::Color BLACK = {0, 0, 0, 0xff};
+static const IComposerClient::Color RED = {0xff, 0, 0, 0xff};
+static const IComposerClient::Color TRANSLUCENT_RED = {0xff, 0, 0, 0x33};
+static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff};
+static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff};
+
+class TestLayer {
+  public:
+    TestLayer(const std::shared_ptr<ComposerClient>& client, Display display)
+        : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client) {}
+
+    // ComposerClient will take care of destroying layers, no need to explicitly
+    // call destroyLayers here
+    virtual ~TestLayer(){};
+
+    virtual void write(const std::shared_ptr<CommandWriterBase>& writer);
+    virtual LayerSettings toRenderEngineLayerSettings();
+
+    void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; }
+    void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; }
+    void setZOrder(uint32_t z) { mZOrder = z; }
+
+    void setSurfaceDamage(std::vector<IComposerClient::Rect> surfaceDamage) {
+        mSurfaceDamage = surfaceDamage;
+    }
+
+    void setTransform(Transform transform) { mTransform = transform; }
+    void setAlpha(float alpha) { mAlpha = alpha; }
+    void setBlendMode(IComposerClient::BlendMode blendMode) { mBlendMode = blendMode; }
+
+    static constexpr uint32_t kBufferSlotCount = 64;
+
+    IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0};
+    uint32_t mZOrder = 0;
+    std::vector<IComposerClient::Rect> mSurfaceDamage;
+    Transform mTransform = static_cast<Transform>(0);
+    IComposerClient::FRect mSourceCrop = {0, 0, 0, 0};
+    float mAlpha = 1.0;
+    IComposerClient::BlendMode mBlendMode = IComposerClient::BlendMode::NONE;
+
+  protected:
+    Layer mLayer;
+
+  private:
+    std::shared_ptr<ComposerClient> const mComposerClient;
+};
+
+class TestColorLayer : public TestLayer {
+  public:
+    TestColorLayer(const std::shared_ptr<ComposerClient>& client, Display display)
+        : TestLayer{client, display} {}
+
+    void write(const std::shared_ptr<CommandWriterBase>& writer) override;
+
+    LayerSettings toRenderEngineLayerSettings() override;
+
+    void setColor(IComposerClient::Color color) { mColor = color; }
+
+  private:
+    IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff};
+};
+
+class TestBufferLayer : public TestLayer {
+  public:
+    TestBufferLayer(
+            const std::shared_ptr<ComposerClient>& client, const std::shared_ptr<Gralloc>& gralloc,
+            Display display, int32_t width, int32_t height, PixelFormat format,
+            IComposerClient::Composition composition = IComposerClient::Composition::DEVICE);
+
+    ~TestBufferLayer();
+
+    void write(const std::shared_ptr<CommandWriterBase>& writer) override;
+
+    LayerSettings toRenderEngineLayerSettings() override;
+
+    void fillBuffer(std::vector<IComposerClient::Color> expectedColors);
+
+    void setBuffer(std::vector<IComposerClient::Color> colors);
+
+    void setDataspace(Dataspace dataspace, const std::shared_ptr<CommandWriterBase>& writer);
+
+    void setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer);
+
+    uint32_t mWidth;
+    uint32_t mHeight;
+    uint32_t mLayerCount;
+    PixelFormat mFormat;
+    uint64_t mUsage;
+    AccessRegion mAccessRegion;
+    uint32_t mStride;
+
+  protected:
+    IComposerClient::Composition mComposition;
+    std::shared_ptr<Gralloc> mGralloc;
+    int32_t mFillFence;
+    const native_handle_t* mBufferHandle = nullptr;
+};
+
+class ReadbackHelper {
+  public:
+    static std::string getColorModeString(ColorMode mode);
+
+    static std::string getDataspaceString(Dataspace dataspace);
+
+    static Dataspace getDataspaceForColorMode(ColorMode mode);
+
+    static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
+
+    static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
+                           PixelFormat pixelFormat,
+                           std::vector<IComposerClient::Color> desiredPixelColors);
+
+    static void clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
+                            int32_t height, int32_t displayWidth);
+
+    static void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride,
+                               IComposerClient::Rect area, IComposerClient::Color color);
+
+    static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
+                                  const Error error);
+
+    static const std::vector<ColorMode> colorModes;
+    static const std::vector<Dataspace> dataspaces;
+
+    static void compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
+                                    void* bufferData, const uint32_t stride, const uint32_t width,
+                                    const uint32_t height, const PixelFormat pixelFormat);
+};
+
+class ReadbackBuffer {
+  public:
+    ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
+                   const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
+                   PixelFormat pixelFormat, Dataspace dataspace);
+    ~ReadbackBuffer();
+
+    void setReadbackBuffer();
+
+    void checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors);
+
+  protected:
+    uint32_t mWidth;
+    uint32_t mHeight;
+    uint32_t mLayerCount;
+    PixelFormat mFormat;
+    uint64_t mUsage;
+    AccessRegion mAccessRegion;
+    uint32_t mStride;
+    const native_handle_t* mBufferHandle = nullptr;
+    PixelFormat mPixelFormat;
+    Dataspace mDataspace;
+    Display mDisplay;
+    std::shared_ptr<Gralloc> mGralloc;
+    std::shared_ptr<ComposerClient> mComposerClient;
+};
+
+}  // namespace vts
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
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
new file mode 100644
index 0000000..f2d5f19
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#include <composer-vts/2.2/ReadbackVts.h>
+#include <math/half.h>
+#include <math/vec3.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+
+using mapper::V2_1::IMapper;
+using renderengine::DisplaySettings;
+using renderengine::RenderEngineCreationArgs;
+using vts::Gralloc;
+
+class TestRenderEngine {
+  public:
+    static constexpr uint32_t sMaxFrameBufferAcquireBuffers = 2;
+
+    TestRenderEngine(const RenderEngineCreationArgs& args);
+    ~TestRenderEngine();
+
+    void setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers);
+    void initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint64_t usage);
+    void setDisplaySettings(DisplaySettings& displaySettings) {
+        mDisplaySettings = displaySettings;
+    };
+    void drawLayers();
+    void checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors);
+
+  private:
+    common::V1_1::PixelFormat mFormat;
+    std::vector<renderengine::LayerSettings> mCompositionLayers;
+    std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+    std::vector<renderengine::LayerSettings> mRenderLayers;
+    sp<GraphicBuffer> mGraphicBuffer;
+    DisplaySettings mDisplaySettings;
+};
+
+}  // namespace vts
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index a8e70ae..a8a05e4 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -24,28 +24,43 @@
 
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
+        "libEGL",
+        "libGLESv1_CM",
+        "libGLESv2",
         "libfmq",
+        "libgui",
         "libhidlbase",
+        "libprocessgroup",
         "libsync",
+        "libui",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.2-vts",
-        "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.0-vts",
-        "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@2.1-vts",
-        "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0-vts",
+        "libgtest",
+        "librenderengine",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
     ],
-    test_suites: ["general-tests"],
+    disable_framework: true,
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 02c4c9c..cb43e64 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * 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.
@@ -16,15 +16,20 @@
 
 #define LOG_TAG "graphics_composer_hidl_hal_readback_tests@2.2"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <android-base/unique_fd.h>
-#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <composer-vts/2.2/ComposerVts.h>
-#include <mapper-vts/2.1/MapperVts.h>
+#include <composer-vts/2.2/ReadbackVts.h>
+#include <composer-vts/2.2/RenderEngineVts.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
 
 namespace android {
 namespace hardware {
@@ -34,130 +39,24 @@
 namespace vts {
 namespace {
 
+using android::GraphicBuffer;
+using android::Rect;
 using android::hardware::hidl_handle;
 using common::V1_1::BufferUsage;
 using common::V1_1::Dataspace;
 using common::V1_1::PixelFormat;
 using mapper::V2_1::IMapper;
+using V2_1::Config;
 using V2_1::Display;
-using V2_1::Layer;
-using V2_1::vts::AccessRegion;
 using V2_1::vts::TestCommandReader;
+using vts::Gralloc;
 
-static const IComposerClient::Color BLACK = {0, 0, 0, 0xff};
-static const IComposerClient::Color RED = {0xff, 0, 0, 0xff};
-static const IComposerClient::Color TRANSLUCENT_RED = {0xff, 0, 0, 0x33};
-static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff};
-static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff};
-
-// Test environment for graphics.composer
-class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static GraphicsComposerHidlEnvironment* Instance() {
-        static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override { registerTestService<IComposer>(); }
-
-   private:
-    GraphicsComposerHidlEnvironment() {}
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
-};
-
-class TestLayer {
-   public:
-    TestLayer(const std::shared_ptr<ComposerClient>& client, Display display)
-        : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client) {}
-
-    // ComposerClient will take care of destroying layers, no need to explicitly
-    // call destroyLayers here
-    virtual ~TestLayer(){};
-
-    virtual void write(const std::shared_ptr<CommandWriterBase>& writer) {
-        writer->selectLayer(mLayer);
-        writer->setLayerDisplayFrame(mDisplayFrame);
-        writer->setLayerSourceCrop(mSourceCrop);
-        writer->setLayerZOrder(mZOrder);
-        writer->setLayerSurfaceDamage(mSurfaceDamage);
-        writer->setLayerTransform(mTransform);
-        writer->setLayerPlaneAlpha(mAlpha);
-        writer->setLayerBlendMode(mBlendMode);
-    }
-
-    void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; }
-    void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; }
-    void setZOrder(uint32_t z) { mZOrder = z; }
-
-    void setSurfaceDamage(std::vector<IComposerClient::Rect> surfaceDamage) {
-        mSurfaceDamage = surfaceDamage;
-    }
-
-    void setTransform(Transform transform) { mTransform = transform; }
-    void setAlpha(float alpha) { mAlpha = alpha; }
-    void setBlendMode(IComposerClient::BlendMode blendMode) { mBlendMode = blendMode; }
-
-    static constexpr uint32_t kBufferSlotCount = 64;
-
-    IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0};
-    uint32_t mZOrder = 0;
-    std::vector<IComposerClient::Rect> mSurfaceDamage;
-    Transform mTransform = static_cast<Transform>(0);
-    IComposerClient::FRect mSourceCrop = {0, 0, 0, 0};
-    float mAlpha = 1.0;
-    IComposerClient::BlendMode mBlendMode = IComposerClient::BlendMode::NONE;
-
-   protected:
-    Layer mLayer;
-
-   private:
-    std::shared_ptr<ComposerClient> const mComposerClient;
-};
-
-class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
-    static int32_t GetBytesPerPixel(PixelFormat pixelFormat) {
-        switch (pixelFormat) {
-            case PixelFormat::RGBA_8888:
-                return 4;
-            case PixelFormat::RGB_888:
-                return 3;
-            default:
-                return -1;
-        }
-    }
-
-    static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
-                           PixelFormat pixelFormat,
-                           std::vector<IComposerClient::Color> desiredPixelColors) {
-        ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == PixelFormat::RGBA_8888);
-        int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
-        ASSERT_NE(-1, bytesPerPixel);
-        for (int row = 0; row < height; row++) {
-            for (int col = 0; col < width; col++) {
-                int pixel = row * width + col;
-                IComposerClient::Color srcColor = desiredPixelColors[pixel];
-
-                int offset = (row * stride + col) * bytesPerPixel;
-                uint8_t* pixelColor = (uint8_t*)bufferData + offset;
-                pixelColor[0] = srcColor.r;
-                pixelColor[1] = srcColor.g;
-                pixelColor[2] = srcColor.b;
-
-                if (bytesPerPixel == 4) {
-                    pixelColor[3] = srcColor.a;
-                }
-            }
-        }
-    }
-
-   protected:
+class GraphicsCompositionTestBase : public ::testing::Test {
+  protected:
     using PowerMode = V2_1::IComposerClient::PowerMode;
-    void SetUp() override {
-        VtsHalHidlTargetTestBase::SetUp();
+    void SetUpBase(const std::string& service_name) {
         ASSERT_NO_FATAL_FAILURE(
-            mComposer = std::make_unique<Composer>(
-                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+                mComposer = std::make_unique<Composer>(IComposer::getService(service_name)));
         ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
         mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
         mComposerClient->registerCallback(mComposerCallback);
@@ -173,6 +72,8 @@
             mDisplayHeight = mComposerClient->getDisplayAttribute(
                 mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT));
 
+        setTestColorModes();
+
         // explicitly disable vsync
         ASSERT_NO_FATAL_FAILURE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false));
         mComposerCallback->setVsyncAllowed(false);
@@ -182,22 +83,28 @@
         mReader = std::make_unique<TestCommandReader>();
         mGralloc = std::make_shared<Gralloc>();
 
-        std::vector<ColorMode> colorModes = mComposerClient->getColorModes(mPrimaryDisplay);
-        if (std::find(colorModes.begin(), colorModes.end(), ColorMode::SRGB) == colorModes.end()) {
-            mHasReadbackBuffer = false;
-            return;
-        }
-        mWriter->selectDisplay(mPrimaryDisplay);
-        ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB,
-                                                              RenderIntent::COLORIMETRIC));
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-            mPrimaryDisplay,
-            [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                mHasReadbackBuffer = readbackSupported(tmpPixelFormat, tmpDataspace, tmpError);
-                mPixelFormat = tmpPixelFormat;
-                mDataspace = tmpDataspace;
-            });
         ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON));
+
+        ASSERT_NO_FATAL_FAILURE(
+                mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine(
+                        renderengine::RenderEngineCreationArgs::Builder()
+                            .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+                            .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers)
+                            .setUseColorManagerment(true)
+                            .setEnableProtectedContext(false)
+                            .setPrecacheToneMapperShaderOnly(false)
+                            .setContextPriority(renderengine::RenderEngine::ContextPriority::HIGH)
+                            .build())));
+
+        renderengine::DisplaySettings clientCompositionDisplay;
+        clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight);
+        clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay;
+        clientCompositionDisplay.clearRegion = Region(clientCompositionDisplay.physicalDisplay);
+
+        mTestRenderEngine->initGraphicBuffer(
+                static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight), 1,
+                static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN));
+        mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
     }
 
     void TearDown() override {
@@ -209,7 +116,6 @@
             EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
             EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
         }
-        VtsHalHidlTargetTestBase::TearDown();
     }
 
     void clearCommandReaderState() {
@@ -217,10 +123,6 @@
         mReader->mErrors.clear();
     }
 
-    void execute() {
-        ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get()));
-    }
-
     void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
         for (auto layer : layers) {
             layer->write(mWriter);
@@ -228,42 +130,10 @@
         execute();
     }
 
-    void clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
-                     int32_t height) {
-        for (int row = 0; row < height; row++) {
-            for (int col = 0; col < width; col++) {
-                int pixel = row * mDisplayWidth + col;
-                expectedColors[pixel] = BLACK;
-            }
-        }
+    void execute() {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get()));
     }
 
-    void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride,
-                        IComposerClient::Rect area, IComposerClient::Color color) {
-        for (int row = area.top; row < area.bottom; row++) {
-            for (int col = area.left; col < area.right; col++) {
-                int pixel = row * stride + col;
-                expectedColors[pixel] = color;
-            }
-        }
-    }
-
-    bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
-                           const Error error) {
-        if (error != Error::NONE) {
-            return false;
-        }
-        // TODO: add support for RGBA_1010102
-        if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
-            return false;
-        }
-        if (dataspace != Dataspace::V0_SRGB) {
-            return false;
-        }
-        return true;
-    }
-
-
     std::unique_ptr<Composer> mComposer;
     std::shared_ptr<ComposerClient> mComposerClient;
 
@@ -272,9 +142,11 @@
     Display mPrimaryDisplay;
     int32_t mDisplayWidth;
     int32_t mDisplayHeight;
+    std::vector<ColorMode> mTestColorModes;
     std::shared_ptr<CommandWriterBase> mWriter;
     std::unique_ptr<TestCommandReader> mReader;
     std::shared_ptr<Gralloc> mGralloc;
+    std::unique_ptr<TestRenderEngine> mTestRenderEngine;
 
     bool mHasReadbackBuffer;
     PixelFormat mPixelFormat;
@@ -293,735 +165,782 @@
             return displays[0];
         }
     }
-};
-class ReadbackBuffer {
-   public:
-    ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
-                   const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
-                   PixelFormat pixelFormat, Dataspace dataspace) {
-        mDisplay = display;
 
-        mComposerClient = client;
-        mGralloc = gralloc;
-
-        mFormat = pixelFormat;
-        mDataspace = dataspace;
-
-        mWidth = width;
-        mHeight = height;
-        mLayerCount = 1;
-        mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
-
-        mAccessRegion.top = 0;
-        mAccessRegion.left = 0;
-        mAccessRegion.width = width;
-        mAccessRegion.height = height;
-    };
-
-    ~ReadbackBuffer() {
-        if (mBufferHandle != nullptr) {
-            mGralloc->freeBuffer(mBufferHandle);
-        }
-    }
-
-    void setReadbackBuffer() {
-        if (mBufferHandle != nullptr) {
-            mGralloc->freeBuffer(mBufferHandle);
-            mBufferHandle = nullptr;
-        }
-        mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
-                                           /*import*/ true, &mStride);
-        ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
-                                                      mFormat, mUsage, mStride));
-        ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1));
-    }
-
-    void checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
-        // lock buffer for reading
-        int32_t fenceHandle;
-        ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
-
-        void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, fenceHandle);
-        ASSERT_TRUE(mFormat == PixelFormat::RGB_888 || mFormat == PixelFormat::RGBA_8888);
-        int32_t bytesPerPixel = GraphicsComposerReadbackTest::GetBytesPerPixel(mFormat);
-        ASSERT_NE(-1, bytesPerPixel);
-        for (int row = 0; row < mHeight; row++) {
-            for (int col = 0; col < mWidth; col++) {
-                int pixel = row * mWidth + col;
-                int offset = (row * mStride + col) * bytesPerPixel;
-                uint8_t* pixelColor = (uint8_t*)bufData + offset;
-
-                ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
-                ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
-                ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
+    void setTestColorModes() {
+        mTestColorModes.clear();
+        mComposerClient->getRaw()->getColorModes_2_2(mPrimaryDisplay, [&](const auto& tmpError,
+                                                                          const auto& tmpModes) {
+            ASSERT_EQ(Error::NONE, tmpError);
+            for (ColorMode mode : tmpModes) {
+                if (std::find(ReadbackHelper::colorModes.begin(), ReadbackHelper::colorModes.end(),
+                              mode) != ReadbackHelper::colorModes.end()) {
+                    mTestColorModes.push_back(mode);
+                }
             }
-        }
-        int32_t unlockFence = mGralloc->unlock(mBufferHandle);
-        if (unlockFence != -1) {
-            sync_wait(unlockFence, -1);
-            close(unlockFence);
-        }
+        });
     }
-
-    uint32_t mWidth;
-    uint32_t mHeight;
-    uint32_t mLayerCount;
-    PixelFormat mFormat;
-    uint64_t mUsage;
-    AccessRegion mAccessRegion;
-
-  protected:
-    uint32_t mStride;
-    const native_handle_t* mBufferHandle = nullptr;
-    Dataspace mDataspace;
-    Display mDisplay;
-    std::shared_ptr<Gralloc> mGralloc;
-    std::shared_ptr<ComposerClient> mComposerClient;
 };
 
-class TestColorLayer : public TestLayer {
-   public:
-    TestColorLayer(const std::shared_ptr<ComposerClient>& client, Display display)
-        : TestLayer{client, display} {}
-
-    void write(const std::shared_ptr<CommandWriterBase>& writer) override {
-        TestLayer::write(writer);
-        writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
-        writer->setLayerColor(mColor);
-    }
-
-    void setColor(IComposerClient::Color color) { mColor = color; }
-
-   private:
-    IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff};
+class GraphicsCompositionTest : public GraphicsCompositionTestBase,
+                                public testing::WithParamInterface<std::string> {
+  public:
+    void SetUp() override { SetUpBase(GetParam()); }
 };
 
-class TestBufferLayer : public TestLayer {
-   public:
-    TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
-                    const std::shared_ptr<Gralloc>& gralloc, Display display, int32_t width,
-                    int32_t height, PixelFormat format,
-                    IComposerClient::Composition composition = IComposerClient::Composition::DEVICE)
-        : TestLayer{client, display} {
-        mGralloc = gralloc;
-        mComposition = composition;
-        mWidth = width;
-        mHeight = height;
-        mLayerCount = 1;
-        mFormat = format;
-        mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                       BufferUsage::COMPOSER_OVERLAY);
-
-        mAccessRegion.top = 0;
-        mAccessRegion.left = 0;
-        mAccessRegion.width = width;
-        mAccessRegion.height = height;
-
-        setSourceCrop({0, 0, (float)width, (float)height});
-    }
-
-    ~TestBufferLayer() {
-        if (mBufferHandle != nullptr) {
-            mGralloc->freeBuffer(mBufferHandle);
-        }
-    }
-
-    void write(const std::shared_ptr<CommandWriterBase>& writer) override {
-        TestLayer::write(writer);
-        writer->setLayerCompositionType(mComposition);
-        writer->setLayerDataspace(Dataspace::UNKNOWN);
-        writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame));
-        if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence);
-    }
-
-    void fillBuffer(std::vector<IComposerClient::Color> expectedColors) {
-        void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, -1);
-        ASSERT_NO_FATAL_FAILURE(GraphicsComposerReadbackTest::fillBuffer(
-                mWidth, mHeight, mStride, bufData, mFormat, expectedColors));
-        mFillFence = mGralloc->unlock(mBufferHandle);
-        if (mFillFence != -1) {
-            sync_wait(mFillFence, -1);
-            close(mFillFence);
-        }
-    }
-    void setBuffer(std::vector<IComposerClient::Color> colors) {
-        if (mBufferHandle != nullptr) {
-            mGralloc->freeBuffer(mBufferHandle);
-            mBufferHandle = nullptr;
-        }
-        mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
-                                           /*import*/ true, &mStride);
-        ASSERT_NE(nullptr, mBufferHandle);
-        ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
-        ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
-                                                      mFormat, mUsage, mStride));
-    }
-
-    void setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) {
-        writer->selectLayer(mLayer);
-        writer->setLayerCompositionType(IComposerClient::Composition::CLIENT);
-    }
-
-    AccessRegion mAccessRegion;
-    uint32_t mStride;
-    uint32_t mWidth;
-    uint32_t mHeight;
-    uint32_t mLayerCount;
-    PixelFormat mFormat;
-
-  protected:
-    uint64_t mUsage;
-    IComposerClient::Composition mComposition;
-    std::shared_ptr<Gralloc> mGralloc;
-    int32_t mFillFence;
-    const native_handle_t* mBufferHandle = nullptr;
-};
-
-TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+TEST_P(GraphicsCompositionTest, SingleSolidColorLayer) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
-    }
-
-    auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
-    IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
-    layer->setColor(BLUE);
-    layer->setDisplayFrame(coloredSquare);
-    layer->setZOrder(10);
-
-    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
-    // expected color for each pixel
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-    writeLayers(layers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    // if hwc cannot handle and asks for composition change,
-    // just succeed the test
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-}
-
-TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
-                  << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
-    }
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
-
-    auto layer =
-        std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
-                                          mDisplayHeight, PixelFormat::RGBA_8888);
-    layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
-    layer->setZOrder(10);
-    ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
-
-    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
-    writeLayers(layers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    mWriter->presentDisplay();
-    execute();
-
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-}
-
-TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
-                  << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
-    }
-
-
-    auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
-    IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
-    layer->setColor(BLUE);
-    layer->setDisplayFrame(coloredSquare);
-    layer->setZOrder(10);
-    layer->write(mWriter);
-
-    // This following buffer call should have no effect
-    PixelFormat format = PixelFormat::RGBA_8888;
-    uint64_t usage =
-            static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
-    const native_handle_t* bufferHandle =
-            mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, format, usage);
-    mWriter->setLayerBuffer(0, bufferHandle, -1);
-
-    // expected color for each pixel
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-    mWriter->validateDisplay();
-    execute();
-
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-}
-
-TEST_F(GraphicsComposerReadbackTest, ClientComposition) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
-                  << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
-    }
-
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
-
-    auto layer =
-        std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
-                                          mDisplayHeight, PixelFormat::RGBA_FP16);
-    layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
-    layer->setZOrder(10);
-
-    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-    writeLayers(layers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-
-    if (mReader->mCompositionChanges.size() != 0) {
-        ASSERT_EQ(1, mReader->mCompositionChanges.size());
-        ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
-
+        mWriter->selectDisplay(mPrimaryDisplay);
         ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setColor(BLUE);
+        layer->setDisplayFrame(coloredSquare);
+        layer->setZOrder(10);
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        // expected color for each pixel
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        // if hwc cannot handle and asks for composition change,
+        // just succeed the test
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerBuffer) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+                  << std::endl;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        mWriter->selectDisplay(mPrimaryDisplay);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
+                                       GREEN);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+                                       BLUE);
+
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+                                                       mDisplayWidth, mDisplayHeight,
+                                                       PixelFormat::RGBA_8888);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        writeLayers(layers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        mWriter->presentDisplay();
+        execute();
+
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+                  << std::endl;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setColor(BLUE);
+        layer->setDisplayFrame(coloredSquare);
+        layer->setZOrder(10);
+        layer->write(mWriter);
+
+        // This following buffer call should have no effect
+        uint64_t usage =
+                static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
+        const native_handle_t* bufferHandle =
+                mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
+        mWriter->setLayerBuffer(0, bufferHandle, -1);
+
+        // expected color for each pixel
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        mWriter->validateDisplay();
+        execute();
+
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, ClientComposition) {
+    ASSERT_NO_FATAL_FAILURE(
             mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
 
-        // create client target buffer
-        uint32_t clientStride;
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+                  << std::endl;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        mWriter->selectDisplay(mPrimaryDisplay);
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2},
+                                       GREEN);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+                                       BLUE);
+
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+                                                       mDisplayWidth, mDisplayHeight,
+                                                       PixelFormat::RGBA_FP16);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        writeLayers(layers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+
+        if (mReader->mCompositionChanges.size() != 0) {
+            ASSERT_EQ(1, mReader->mCompositionChanges.size());
+            ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
+
+            PixelFormat clientFormat = PixelFormat::RGBA_8888;
+            uint64_t clientUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN |
+                                                         BufferUsage::CPU_WRITE_OFTEN |
+                                                         BufferUsage::COMPOSER_CLIENT_TARGET);
+            Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
+            IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
+
+            bool clientTargetSupported = mComposerClient->getClientTargetSupport_2_2(
+                    mPrimaryDisplay, layer->mWidth, layer->mHeight, clientFormat, clientDataspace);
+            // if the client target format is not supported, skip this
+            // configuration
+            if (!clientTargetSupported) {
+                std::cout << "Client target configuration width: " << layer->mWidth
+                          << " height: " << layer->mHeight
+                          << " pixel format: PixelFormat::RGBA_8888 dataspace: "
+                          << ReadbackHelper::getDataspaceString(clientDataspace)
+                          << " unsupported for display" << std::endl;
+                continue;
+            }
+
+            // create client target buffer
+            uint32_t clientStride;
+            const native_handle_t* clientBufferHandle =
+                    mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount,
+                                       clientFormat, clientUsage, /*import*/ true, &clientStride);
+            ASSERT_NE(nullptr, clientBufferHandle);
+
+            void* clientBufData =
+                    mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1);
+
+            ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(layer->mWidth, layer->mHeight,
+                                                               clientStride, clientBufData,
+                                                               clientFormat, expectedColors));
+            int clientFence = mGralloc->unlock(clientBufferHandle);
+            if (clientFence != -1) {
+                sync_wait(clientFence, -1);
+                close(clientFence);
+            }
+
+            mWriter->setClientTarget(0, clientBufferHandle, clientFence, clientDataspace,
+                                     std::vector<IComposerClient::Rect>(1, damage));
+
+            layer->setToClientComposition(mWriter);
+            mWriter->validateDisplay();
+            execute();
+            ASSERT_EQ(0, mReader->mCompositionChanges.size());
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        mWriter->presentDisplay();
+        execute();
+
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+    }
+}
+
+TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) {
+    ASSERT_NO_FATAL_FAILURE(
+            mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
+
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
+                  << std::endl;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        auto deviceLayer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2,
+                PixelFormat::RGBA_8888);
+        std::vector<IComposerClient::Color> deviceColors(deviceLayer->mWidth *
+                                                         deviceLayer->mHeight);
+        ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mWidth,
+                                       {0, 0, static_cast<int32_t>(deviceLayer->mWidth),
+                                        static_cast<int32_t>(deviceLayer->mHeight)},
+                                       GREEN);
+        deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->mWidth),
+                                      static_cast<int32_t>(deviceLayer->mHeight)});
+        deviceLayer->setZOrder(10);
+        deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
+        deviceLayer->write(mWriter);
+
         PixelFormat clientFormat = PixelFormat::RGBA_8888;
         uint64_t clientUsage =
                 static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
                                       BufferUsage::COMPOSER_CLIENT_TARGET);
+        Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
+        int32_t clientWidth = mDisplayWidth;
+        int32_t clientHeight = mDisplayHeight / 2;
+
+        bool clientTargetSupported = mComposerClient->getClientTargetSupport_2_2(
+                mPrimaryDisplay, clientWidth, clientHeight, clientFormat, clientDataspace);
+        // if the client target format is not supported, skip this
+        // configuration
+        if (!clientTargetSupported) {
+            std::cout << "Client target configuration width: " << clientWidth
+                      << " height: " << clientHeight
+                      << " pixel format: PixelFormat::RGBA_8888 dataspace: "
+                      << ReadbackHelper::getDataspaceString(clientDataspace)
+                      << " unsupported for display" << std::endl;
+            continue;
+        }
+
+        auto clientLayer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGralloc, mPrimaryDisplay, clientWidth, clientHeight,
+                PixelFormat::RGBA_FP16, IComposerClient::Composition::DEVICE);
+        IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
+        clientLayer->setDisplayFrame(clientFrame);
+        clientLayer->setZOrder(0);
+        clientLayer->write(mWriter);
+        mWriter->validateDisplay();
+        execute();
+
+        if (mReader->mCompositionChanges.size() != 1) {
+            std::cout << "HWC asked for none or more than 1 composition change, skipping"
+                      << std::endl;
+            mReader->mCompositionChanges.clear();
+            continue;
+        }
+        // create client target buffer
+        ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
+        uint32_t clientStride;
         const native_handle_t* clientBufferHandle =
-                mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount, clientFormat,
-                                   clientUsage, /*import*/ true, &clientStride);
+                mGralloc->allocate(mDisplayWidth, mDisplayHeight, clientLayer->mLayerCount,
+                                   clientFormat, clientUsage, /*import*/ true, &clientStride);
         ASSERT_NE(nullptr, clientBufferHandle);
 
-        void* clientBufData =
-                mGralloc->lock(clientBufferHandle, clientUsage, layer->mAccessRegion, -1);
+        void* clientBufData = mGralloc->lock(clientBufferHandle, clientUsage,
+                                             {0, 0, mDisplayWidth, mDisplayHeight}, -1);
 
-        ASSERT_NO_FATAL_FAILURE(fillBuffer(layer->mWidth, layer->mHeight, clientStride,
-                                           clientBufData, clientFormat, expectedColors));
+        std::vector<IComposerClient::Color> clientColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED);
+        ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mDisplayWidth, mDisplayHeight,
+                                                           clientStride, clientBufData,
+                                                           clientFormat, clientColors));
         int clientFence = mGralloc->unlock(clientBufferHandle);
         if (clientFence != -1) {
             sync_wait(clientFence, -1);
             close(clientFence);
         }
 
-        IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
-        mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN,
-                                 std::vector<IComposerClient::Rect>(1, damage));
-
-        layer->setToClientComposition(mWriter);
+        mWriter->setClientTarget(0, clientBufferHandle, clientFence, clientDataspace,
+                                 std::vector<IComposerClient::Rect>(1, clientFrame));
+        clientLayer->setToClientComposition(mWriter);
         mWriter->validateDisplay();
         execute();
         ASSERT_EQ(0, mReader->mCompositionChanges.size());
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
     }
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    mWriter->presentDisplay();
-    execute();
-
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 }
 
-TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+TEST_P(GraphicsCompositionTest, SetLayerDamage) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        mWriter->selectDisplay(mPrimaryDisplay);
+
+        IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4};
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+                                                       mDisplayWidth, mDisplayHeight,
+                                                       PixelFormat::RGBA_8888);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+
+        // update surface damage and recheck
+        redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2};
+        ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+        ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
+        layer->setSurfaceDamage(std::vector<IComposerClient::Rect>(
+                1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2}));
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_EQ(0, mReader->mCompositionChanges.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
     }
-
-    ASSERT_NO_FATAL_FAILURE(
-        mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
-
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-    auto deviceLayer =
-        std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
-                                          mDisplayHeight / 2, PixelFormat::RGBA_8888);
-    std::vector<IComposerClient::Color> deviceColors(deviceLayer->mWidth * deviceLayer->mHeight);
-    fillColorsArea(deviceColors, deviceLayer->mWidth,
-                   {0, 0, static_cast<int32_t>(deviceLayer->mWidth),
-                    static_cast<int32_t>(deviceLayer->mHeight)},
-                   GREEN);
-    deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->mWidth),
-                                  static_cast<int32_t>(deviceLayer->mHeight)});
-    deviceLayer->setZOrder(10);
-    ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
-    deviceLayer->write(mWriter);
-
-    auto clientLayer = std::make_shared<TestBufferLayer>(
-        mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2,
-        PixelFormat::RGBA_8888, IComposerClient::Composition::CLIENT);
-    IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
-    clientLayer->setDisplayFrame(clientFrame);
-    clientLayer->setZOrder(0);
-    clientLayer->write(mWriter);
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    uint64_t clientUsage =
-            static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                  BufferUsage::COMPOSER_CLIENT_TARGET);
-    uint32_t clientStride;
-    const native_handle_t* clientBufferHandle =
-            mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888,
-                               clientUsage, /*import*/ true, &clientStride);
-    ASSERT_NE(nullptr, clientBufferHandle);
-
-    AccessRegion clientAccessRegion;
-    clientAccessRegion.left = 0;
-    clientAccessRegion.top = 0;
-    clientAccessRegion.width = mDisplayWidth;
-    clientAccessRegion.height = mDisplayHeight;
-    void* clientData = mGralloc->lock(clientBufferHandle, clientUsage, clientAccessRegion, -1);
-    std::vector<IComposerClient::Color> clientColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED);
-    ASSERT_NO_FATAL_FAILURE(fillBuffer(mDisplayWidth, mDisplayHeight, clientStride, clientData,
-                                       PixelFormat::RGBA_8888, clientColors));
-    int clientFence = mGralloc->unlock(clientBufferHandle);
-    if (clientFence != -1) {
-        sync_wait(clientFence, -1);
-        close(clientFence);
-    }
-
-    mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN,
-                             std::vector<IComposerClient::Rect>(1, clientFrame));
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 }
 
-TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+TEST_P(GraphicsCompositionTest, SetLayerPlaneAlpha) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelformat/dataspace";
-        return;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        layer->setColor(RED);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setAlpha(0);
+        layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
-
-    IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4};
-
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
-
-    auto layer =
-        std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
-                                          mDisplayHeight, PixelFormat::RGBA_8888);
-    layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
-    layer->setZOrder(10);
-    ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
-
-    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-    writeLayers(layers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-
-    // update surface damage and recheck
-    redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2};
-    clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
-
-    ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
-    layer->setSurfaceDamage(
-        std::vector<IComposerClient::Rect>(1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2}));
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-    writeLayers(layers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-    ASSERT_EQ(0, mReader->mCompositionChanges.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 }
 
-TEST_F(GraphicsComposerReadbackTest, SetLayerPlaneAlpha) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+TEST_P(GraphicsCompositionTest, SetLayerSourceCrop) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        mWriter->selectDisplay(mPrimaryDisplay);
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
+                                       BLUE);
+
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+                                                       mDisplayWidth, mDisplayHeight,
+                                                       PixelFormat::RGBA_8888);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+        layer->setSourceCrop({0, static_cast<float>(mDisplayHeight / 2),
+                              static_cast<float>(mDisplayWidth),
+                              static_cast<float>(mDisplayHeight)});
+        ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+        // update expected colors to match crop
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        writeLayers(layers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
-
-    auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
-    layer->setColor(RED);
-    layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
-    layer->setZOrder(10);
-    layer->setAlpha(0);
-    layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
-
-    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-    writeLayers(layers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 }
 
-TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+TEST_P(GraphicsCompositionTest, SetLayerZOrder) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2};
+        IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight};
+        auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        redLayer->setColor(RED);
+        redLayer->setDisplayFrame(redRect);
+
+        auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        blueLayer->setColor(BLUE);
+        blueLayer->setDisplayFrame(blueRect);
+        blueLayer->setZOrder(5);
+
+        std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer};
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+        // red in front of blue
+        redLayer->setZOrder(10);
+
+        // fill blue first so that red will overwrite on overlap
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+
+        redLayer->setZOrder(1);
+        ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        writeLayers(layers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mCompositionChanges.size());
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(layers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
-
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
-
-    auto layer =
-        std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
-                                          mDisplayHeight, PixelFormat::RGBA_8888);
-    layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
-    layer->setZOrder(10);
-    layer->setSourceCrop({0, static_cast<float>(mDisplayHeight / 2),
-                          static_cast<float>(mDisplayWidth), static_cast<float>(mDisplayHeight)});
-    ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
-
-    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
-
-    // update expected colors to match crop
-    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-    writeLayers(layers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 }
 
-TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
-                  << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
-    }
-
-    IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2};
-    IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight};
-    auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
-    redLayer->setColor(RED);
-    redLayer->setDisplayFrame(redRect);
-
-    auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
-    blueLayer->setColor(BLUE);
-    blueLayer->setDisplayFrame(blueRect);
-    blueLayer->setZOrder(5);
-
-    std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer};
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
-    // red in front of blue
-    redLayer->setZOrder(10);
-
-    // fill blue first so that red will overwrite on overlap
-    fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
-    fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-    writeLayers(layers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-
-    redLayer->setZOrder(1);
-    clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
-    fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-    writeLayers(layers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mCompositionChanges.size());
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
-}
-
-class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTest,
-                                              public ::testing::WithParamInterface<float> {
-   public:
+class GraphicsBlendModeCompositionTest
+    : public GraphicsCompositionTestBase,
+      public testing::WithParamInterface<std::tuple<std::string, std::string>> {
+  public:
     void SetUp() override {
-        GraphicsComposerReadbackTest::SetUp();
+        SetUpBase(std::get<0>(GetParam()));
+        mTestColorModes = {ColorMode::SRGB};  // TODO: add more color mode support
         mBackgroundColor = BLACK;
         mTopLayerColor = RED;
     }
 
-    void TearDown() override { GraphicsComposerReadbackTest::TearDown(); }
-
     void setBackgroundColor(IComposerClient::Color color) { mBackgroundColor = color; }
 
     void setTopLayerColor(IComposerClient::Color color) { mTopLayerColor = color; }
@@ -1029,8 +948,8 @@
     void setUpLayers(IComposerClient::BlendMode blendMode) {
         mLayers.clear();
         std::vector<IComposerClient::Color> topLayerPixelColors(mDisplayWidth * mDisplayHeight);
-        fillColorsArea(topLayerPixelColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight},
-                       mTopLayerColor);
+        ReadbackHelper::fillColorsArea(topLayerPixelColors, mDisplayWidth,
+                                       {0, 0, mDisplayWidth, mDisplayHeight}, mTopLayerColor);
 
         auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
         backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
@@ -1042,10 +961,11 @@
                                                        PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
+        layer->setDataspace(Dataspace::UNKNOWN, mWriter);
         ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors));
 
         layer->setBlendMode(blendMode);
-        layer->setAlpha(GetParam());
+        layer->setAlpha(std::stof(std::get<1>(GetParam())));
 
         mLayers.push_back(backgroundLayer);
         mLayers.push_back(layer);
@@ -1053,7 +973,7 @@
 
     void setExpectedColors(std::vector<IComposerClient::Color>& expectedColors) {
         ASSERT_EQ(2, mLayers.size());
-        clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
+        ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth);
 
         auto layer = mLayers[1];
         IComposerClient::BlendMode blendMode = layer->mBlendMode;
@@ -1091,122 +1011,178 @@
     IComposerClient::Color mTopLayerColor;
 };
 
-TEST_P(GraphicsComposerBlendModeReadbackTest, None) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+// TODO(b/145557764): Re-enable after the bug is fixed.
+TEST_P(GraphicsBlendModeCompositionTest, DISABLED_None) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        mWriter->selectDisplay(mPrimaryDisplay);
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+        setBackgroundColor(BLACK);
+        setTopLayerColor(TRANSLUCENT_RED);
+        setUpLayers(IComposerClient::BlendMode::NONE);
+        setExpectedColors(expectedColors);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        writeLayers(mLayers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
-
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
-    setBackgroundColor(BLACK);
-    setTopLayerColor(TRANSLUCENT_RED);
-    setUpLayers(IComposerClient::BlendMode::NONE);
-    setExpectedColors(expectedColors);
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-    writeLayers(mLayers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 }
 
 // TODO: bug 116865056: Readback returns (245, 0, 0) for layer plane
 // alpha of .2, expected 10.2
-TEST_P(GraphicsComposerBlendModeReadbackTest, DISABLED_Coverage) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+TEST_P(GraphicsBlendModeCompositionTest, DISABLED_Coverage) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+
+        mWriter->selectDisplay(mPrimaryDisplay);
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+        setBackgroundColor(BLACK);
+        setTopLayerColor(TRANSLUCENT_RED);
+
+        setUpLayers(IComposerClient::BlendMode::COVERAGE);
+        setExpectedColors(expectedColors);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        writeLayers(mLayers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
     }
-
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
-    setBackgroundColor(BLACK);
-    setTopLayerColor(TRANSLUCENT_RED);
-
-    setUpLayers(IComposerClient::BlendMode::COVERAGE);
-    setExpectedColors(expectedColors);
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-    writeLayers(mLayers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 }
 
-TEST_P(GraphicsComposerBlendModeReadbackTest, Premultiplied) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+TEST_P(GraphicsBlendModeCompositionTest, Premultiplied) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+        mWriter->selectDisplay(mPrimaryDisplay);
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+        setBackgroundColor(BLACK);
+        setTopLayerColor(TRANSLUCENT_RED);
+        setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
+        setExpectedColors(expectedColors);
+
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        writeLayers(mLayers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
-
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-
-    setBackgroundColor(BLACK);
-    setTopLayerColor(TRANSLUCENT_RED);
-    setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
-    setExpectedColors(expectedColors);
-
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-    writeLayers(mLayers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 }
 
-INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsComposerBlendModeReadbackTest,
-                        ::testing::Values(.2, 1.0));
-
-class GraphicsComposerTransformReadbackTest : public GraphicsComposerReadbackTest {
-   protected:
+class GraphicsTransformCompositionTest : public GraphicsCompositionTest {
+  protected:
     void SetUp() override {
-        GraphicsComposerReadbackTest::SetUp();
+        GraphicsCompositionTest::SetUp();
+
+        mWriter->selectDisplay(mPrimaryDisplay);
 
         auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
         backgroundLayer->setColor({0, 0, 0, 0});
@@ -1225,8 +1201,8 @@
         mLayer->setZOrder(10);
 
         std::vector<IComposerClient::Color> baseColors(mSideLength * mSideLength);
-        fillColorsArea(baseColors, mSideLength, redRect, RED);
-        fillColorsArea(baseColors, mSideLength, blueRect, BLUE);
+        ReadbackHelper::fillColorsArea(baseColors, mSideLength, redRect, RED);
+        ReadbackHelper::fillColorsArea(baseColors, mSideLength, blueRect, BLUE);
         ASSERT_NO_FATAL_FAILURE(mLayer->setBuffer(baseColors));
 
         mLayers = {backgroundLayer, mLayer};
@@ -1239,112 +1215,189 @@
     int mSideLength;
 };
 
-TEST_F(GraphicsComposerTransformReadbackTest, FLIP_H) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+TEST_P(GraphicsTransformCompositionTest, FLIP_H) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
-    }
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-    mLayer->setTransform(Transform::FLIP_H);
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE);
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-    writeLayers(mLayers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
 
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+        mLayer->setTransform(Transform::FLIP_H);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE);
+
+        writeLayers(mLayers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
+    }
 }
 
-TEST_F(GraphicsComposerTransformReadbackTest, FLIP_V) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+TEST_P(GraphicsTransformCompositionTest, FLIP_V) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        mLayer->setTransform(Transform::FLIP_V);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE);
+
+        writeLayers(mLayers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-    mLayer->setTransform(Transform::FLIP_V);
-
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE);
-
-    writeLayers(mLayers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 }
 
-TEST_F(GraphicsComposerTransformReadbackTest, ROT_180) {
-    if (!mHasReadbackBuffer) {
-        std::cout << "Readback not supported or unsuppported pixelFormat/dataspace or SRGB not a "
-                     "valid color mode"
+TEST_P(GraphicsTransformCompositionTest, ROT_180) {
+    for (ColorMode mode : mTestColorModes) {
+        std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
                   << std::endl;
-        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
-        return;
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(
+                mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+                mPrimaryDisplay,
+                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
+                                                                           tmpDataspace, tmpError);
+                    mPixelFormat = tmpPixelFormat;
+                    mDataspace = tmpDataspace;
+                });
+
+        if (!mHasReadbackBuffer) {
+            std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+            return;
+        }
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+        mLayer->setTransform(Transform::ROT_180);
+        mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+
+        std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength},
+                                       RED);
+        ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
+                                       {0, 0, mSideLength / 2, mSideLength / 2}, BLUE);
+
+        writeLayers(mLayers);
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->validateDisplay();
+        execute();
+        if (mReader->mCompositionChanges.size() != 0) {
+            clearCommandReaderState();
+            GTEST_SUCCEED();
+            return;
+        }
+        ASSERT_EQ(0, mReader->mErrors.size());
+        mWriter->presentDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+        mTestRenderEngine->setRenderLayers(mLayers);
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers());
+        ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors));
     }
-    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                  mDisplayHeight, mPixelFormat, mDataspace);
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
-
-    mLayer->setTransform(Transform::ROT_180);
-
-    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
-    fillColorsArea(expectedColors, mDisplayWidth,
-                   {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, RED);
-    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mSideLength / 2, mSideLength / 2}, BLUE);
-
-    writeLayers(mLayers);
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->validateDisplay();
-    execute();
-    if (mReader->mCompositionChanges.size() != 0) {
-        clearCommandReaderState();
-        GTEST_SUCCEED();
-        return;
-    }
-    ASSERT_EQ(0, mReader->mErrors.size());
-    mWriter->presentDisplay();
-    execute();
-    ASSERT_EQ(0, mReader->mErrors.size());
-    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsCompositionTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_CASE_P(
+        BlendModeTest, GraphicsBlendModeCompositionTest,
+        testing::Combine(
+                testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+                testing::Values("0.2", "1.0")),
+        android::hardware::PrintInstanceTupleNameToString<>);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsTransformCompositionTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 }  // anonymous namespace
 }  // namespace vts
 }  // namespace V2_2
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 51832f9..95a0f69 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -16,12 +16,14 @@
 
 #define LOG_TAG "graphics_composer_hidl_hal_test@2.2"
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <composer-vts/2.2/ComposerVts.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <mapper-vts/2.0/MapperVts.h>
 
 namespace android {
@@ -41,29 +43,11 @@
 using common::V1_1::RenderIntent;
 using mapper::V2_0::IMapper;
 
-// Test environment for graphics.composer
-class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static GraphicsComposerHidlEnvironment* Instance() {
-        static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IComposer>(); }
-
-   private:
-    GraphicsComposerHidlEnvironment() {}
-
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
-};
-
-class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
+  protected:
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(
-            mComposer = std::make_unique<Composer>(
-                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+                mComposer = std::make_unique<Composer>(IComposer::getService(GetParam())));
         ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
 
         mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
@@ -188,7 +172,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -239,7 +223,7 @@
 /**
  * Test IComposerClient::getPerFrameMetadataKeys.
  */
-TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) {
+TEST_P(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) {
     std::vector<IComposerClient::PerFrameMetadataKey> keys;
     Error error = Error::NONE;
     mComposerClient->getRaw()->getPerFrameMetadataKeys(
@@ -261,7 +245,7 @@
  *
  * Test that virtual displays can be created and has the correct display type.
  */
-TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay_2_2) {
+TEST_P(GraphicsComposerHidlTest, CreateVirtualDisplay_2_2) {
     if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
         GTEST_SUCCEED() << "no virtual display support";
         return;
@@ -286,7 +270,7 @@
  * Test that IComposerClient::getClientTargetSupport returns true for the
  * required client targets.
  */
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_2) {
     std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -310,7 +294,7 @@
  * Error::BAD_DISPLAY when passed in an invalid display handle
  */
 
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_2BadDisplay) {
     std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -332,7 +316,7 @@
 /**
  * Test IComposerClient::setPowerMode_2_2.
  */
-TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2) {
     std::vector<IComposerClient::PowerMode> modes;
     modes.push_back(IComposerClient::PowerMode::OFF);
     modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);
@@ -349,7 +333,7 @@
  * Test that IComposerClient::setPowerMode_2_2 succeeds for different varations
  * of PowerMode
  */
-TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Variations) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2Variations) {
     std::vector<IComposerClient::PowerMode> modes;
 
     modes.push_back(IComposerClient::PowerMode::OFF);
@@ -404,7 +388,7 @@
  * Tests that IComposerClient::setPowerMode_2_2 returns BAD_DISPLAY when passed an
  * invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2BadDisplay) {
     Error error = mComposerClient->getRaw()->setPowerMode_2_2(mInvalidDisplayId,
                                                               IComposerClient::PowerMode::ON);
     ASSERT_EQ(Error::BAD_DISPLAY, error);
@@ -416,7 +400,7 @@
  * Test that IComposerClient::setPowerMode_2_2 returns BAD_PARAMETER when passed
  * an invalid PowerMode
  */
-TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2BadParameter) {
     Error error = mComposerClient->getRaw()->setPowerMode_2_2(
         mPrimaryDisplay, static_cast<IComposerClient::PowerMode>(-1));
     ASSERT_EQ(Error::BAD_PARAMETER, error);
@@ -428,7 +412,7 @@
  * Test that IComposerClient::setPowerMode_2_2 returns UNSUPPORTED when passed
  * DOZE or DOZE_SUPPORT on a device that does not support these modes
  */
-TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Unsupported) {
+TEST_P(GraphicsComposerHidlTest, SetPowerMode_2_2Unsupported) {
     if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) {
         Error error = mComposerClient->getRaw()->setPowerMode_2_2(mPrimaryDisplay,
                                                                   IComposerClient::PowerMode::DOZE);
@@ -445,7 +429,7 @@
  *
  * Test IComposerClient::setReadbackBuffer
  */
-TEST_F(GraphicsComposerHidlTest, SetReadbackBuffer) {
+TEST_P(GraphicsComposerHidlTest, SetReadbackBuffer) {
     if (!mHasReadbackBuffer) {
         return;
     }
@@ -469,7 +453,7 @@
  * Test that IComposerClient::setReadbackBuffer returns an Error::BAD_DISPLAY
  * when passed an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) {
     if (!mHasReadbackBuffer) {
         return;
     }
@@ -493,7 +477,7 @@
  * Test that IComposerClient::setReadbackBuffer returns Error::BAD_PARAMETER
  * when passed an invalid buffer handle
  */
-TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetReadbackBufferBadParameter) {
     if (!mHasReadbackBuffer) {
         return;
     }
@@ -502,7 +486,7 @@
     ASSERT_EQ(Error::BAD_PARAMETER, error);
 }
 
-TEST_F(GraphicsComposerHidlTest, GetReadbackBufferFenceInactive) {
+TEST_P(GraphicsComposerHidlTest, GetReadbackBufferFenceInactive) {
     if (!mHasReadbackBuffer) {
         return;
     }
@@ -516,7 +500,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_FLOAT_COLOR.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) {
     V2_1::Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -554,7 +538,7 @@
 /**
  * Test IComposerClient::getDataspaceSaturationMatrix.
  */
-TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrix) {
+TEST_P(GraphicsComposerHidlTest, GetDataspaceSaturationMatrix) {
     auto matrix = mComposerClient->getDataspaceSaturationMatrix(Dataspace::SRGB_LINEAR);
     // the last row is known
     ASSERT_EQ(0.0f, matrix[12]);
@@ -570,7 +554,7 @@
  * Error::BAD_PARAMETER when passed a dataspace other than
  * Dataspace::SRGB_LINEAR
  */
-TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrixBadParameter) {
+TEST_P(GraphicsComposerHidlTest, GetDataspaceSaturationMatrixBadParameter) {
     mComposerClient->getRaw()->getDataspaceSaturationMatrix(
         Dataspace::UNKNOWN,
         [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_PARAMETER, tmpError); });
@@ -579,7 +563,7 @@
 /**
  * Test IComposerClient::getColorMode_2_2.
  */
-TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2) {
+TEST_P(GraphicsComposerHidlTest, GetColorMode_2_2) {
     std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
 
     auto nativeMode = std::find(modes.cbegin(), modes.cend(), ColorMode::NATIVE);
@@ -592,7 +576,7 @@
  * Test that IComposerClient::getColorMode returns Error::BAD_DISPLAY when
  * passed an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetColorMode_2_2BadDisplay) {
     mComposerClient->getRaw()->getColorModes_2_2(
         mInvalidDisplayId,
         [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); });
@@ -601,7 +585,7 @@
 /**
  * Test IComposerClient::getRenderIntents.
  */
-TEST_F(GraphicsComposerHidlTest, GetRenderIntents) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntents) {
     std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
     for (auto mode : modes) {
         std::vector<RenderIntent> intents =
@@ -631,7 +615,7 @@
  * Test that IComposerClient::getRenderIntent returns Error::BAD_DISPLAY when
  * passed an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntentsBadDisplay) {
     std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
     for (auto mode : modes) {
         mComposerClient->getRaw()->getRenderIntents(
@@ -646,7 +630,7 @@
  * Test that IComposerClient::getRenderIntents returns Error::BAD_PARAMETER when
  * pased either an invalid Color mode or an invalid Render Intent
  */
-TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadParameter) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntentsBadParameter) {
     mComposerClient->getRaw()->getRenderIntents(
         mPrimaryDisplay, static_cast<ColorMode>(-1),
         [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); });
@@ -655,7 +639,7 @@
 /**
  * Test IComposerClient::setColorMode_2_2.
  */
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_2) {
     std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
     for (auto mode : modes) {
         std::vector<RenderIntent> intents =
@@ -674,7 +658,7 @@
  * Test that IComposerClient::setColorMode_2_2 returns an Error::BAD_DISPLAY
  * when passed an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_2BadDisplay) {
     Error error = mComposerClient->getRaw()->setColorMode_2_2(mInvalidDisplayId, ColorMode::NATIVE,
                                                               RenderIntent::COLORIMETRIC);
 
@@ -687,7 +671,7 @@
  * Test that IComposerClient::setColorMode_2_2 returns Error::BAD_PARAMETER when
  * passed an invalid Color mode or an invalid render intent
  */
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_2BadParameter) {
     Error colorModeError = mComposerClient->getRaw()->setColorMode_2_2(
         mPrimaryDisplay, static_cast<ColorMode>(-1), RenderIntent::COLORIMETRIC);
     EXPECT_EQ(Error::BAD_PARAMETER, colorModeError);
@@ -697,6 +681,16 @@
     EXPECT_EQ(Error::BAD_PARAMETER, renderIntentError);
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerHidlCommandTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 }  // namespace
 }  // namespace vts
 }  // namespace V2_2
@@ -704,12 +698,3 @@
 }  // namespace graphics
 }  // namespace hardware
 }  // namespace android
-
-int main(int argc, char** argv) {
-    using android::hardware::graphics::composer::V2_2::vts::GraphicsComposerHidlEnvironment;
-    ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    return status;
-}
diff --git a/graphics/composer/2.3/default/Android.bp b/graphics/composer/2.3/default/Android.bp
index 59b9436..a5696dd 100644
--- a/graphics/composer/2.3/default/Android.bp
+++ b/graphics/composer/2.3/default/Android.bp
@@ -28,8 +28,8 @@
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.composer@2.1-resources",
+        "android.hardware.graphics.composer@2.2-resources",
         "libbase",
         "libbinder",
         "libcutils",
diff --git a/graphics/composer/2.3/utils/OWNERS b/graphics/composer/2.3/utils/OWNERS
index b3ea6be..cc6d937 100644
--- a/graphics/composer/2.3/utils/OWNERS
+++ b/graphics/composer/2.3/utils/OWNERS
@@ -2,7 +2,3 @@
 lpy@google.com
 stoza@google.com
 vhau@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
diff --git a/graphics/composer/2.3/utils/command-buffer/Android.bp b/graphics/composer/2.3/utils/command-buffer/Android.bp
index c48fe7a..36ac297 100644
--- a/graphics/composer/2.3/utils/command-buffer/Android.bp
+++ b/graphics/composer/2.3/utils/command-buffer/Android.bp
@@ -3,12 +3,15 @@
     defaults: ["hidl_defaults"],
     vendor_available: true,
     shared_libs: [
-        "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3",
+    ],
+    export_shared_lib_headers: [
         "android.hardware.graphics.composer@2.3",
     ],
     header_libs: [
-        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+    export_header_lib_headers: [
         "android.hardware.graphics.composer@2.2-command-buffer",
     ],
     export_include_dirs: ["include"],
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
index e1a870e..afc22d8 100644
--- a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -46,8 +46,8 @@
 class CommandWriterBase : public V2_2::CommandWriterBase {
    public:
     void setLayerPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
-        beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
-                         metadataVec.size() * 2);
+        beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA,
+                     metadataVec.size() * 2);
         for (const auto& metadata : metadataVec) {
             writeSigned(static_cast<int32_t>(metadata.key));
             writeFloat(metadata.value);
@@ -69,8 +69,8 @@
 
     static constexpr uint16_t kSetLayerColorTransformLength = 16;
     void setLayerColorTransform(const float* matrix) {
-        beginCommand_2_3(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM,
-                         kSetLayerColorTransformLength);
+        beginCommand(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM,
+                     kSetLayerColorTransformLength);
         for (int i = 0; i < 16; i++) {
             writeFloat(matrix[i]);
         }
@@ -109,7 +109,7 @@
         // Blobs are written as:
         // {numElements, key1, size1, blob1, key2, size2, blob2, key3, size3...}
         uint16_t length = static_cast<uint16_t>(commandLength);
-        beginCommand_2_3(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length);
+        beginCommand(IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length);
         write(static_cast<uint32_t>(metadata.size()));
         for (auto metadataBlob : metadata) {
             writeSigned(static_cast<int32_t>(metadataBlob.key));
@@ -120,11 +120,6 @@
     }
 
    protected:
-    void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
-        V2_2::CommandWriterBase::beginCommand_2_2(
-            static_cast<V2_2::IComposerClient::Command>(static_cast<int32_t>(command)), length);
-    }
-
     void writeBlob(uint32_t length, const unsigned char* blob) {
         memcpy(&mData[mDataWritten], blob, length);
         uint32_t numElements = length / 4;
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
index b289b6a..041fbc8 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
@@ -21,9 +21,9 @@
 #endif
 
 #include <android/hardware/graphics/composer/2.3/IComposerClient.h>
-#include <composer-hal/2.2/ComposerResources.h>
 #include <composer-hal/2.3/ComposerCommandEngine.h>
 #include <composer-hal/2.3/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
 
 namespace android {
 namespace hardware {
@@ -184,18 +184,18 @@
     }
 
   protected:
+    using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+    using BaseType2_1::mHal;
+    using BaseType2_1::mResources;
     std::unique_ptr<V2_1::hal::ComposerCommandEngine> createCommandEngine() override {
         return std::make_unique<ComposerCommandEngine>(
             mHal, static_cast<V2_2::hal::ComposerResources*>(mResources.get()));
     }
 
-   private:
+  private:
     using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl<Interface, Hal>;
-    using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
     using BaseType2_1::mCommandEngine;
     using BaseType2_1::mCommandEngineMutex;
-    using BaseType2_1::mHal;
-    using BaseType2_1::mResources;
 };
 
 }  // namespace detail
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
index 1a40d96..02f6212 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
@@ -23,8 +23,8 @@
 #include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
 #include <composer-hal/2.1/ComposerCommandEngine.h>
 #include <composer-hal/2.2/ComposerCommandEngine.h>
-#include <composer-hal/2.2/ComposerResources.h>
 #include <composer-hal/2.3/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
 
 namespace android {
 namespace hardware {
@@ -50,6 +50,11 @@
         }
     }
 
+    std::unique_ptr<V2_1::CommandWriterBase> createCommandWriter(
+            size_t writerInitialSize) override {
+        return std::make_unique<CommandWriterBase>(writerInitialSize);
+    }
+
     bool executeSetLayerColorTransform(uint16_t length) {
         if (length != CommandWriterBase::kSetLayerColorTransformLength) {
             return false;
@@ -61,7 +66,7 @@
         }
         auto err = mHal->setLayerColorTransform(mCurrentDisplay, mCurrentLayer, matrix);
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
 
         return true;
@@ -97,7 +102,7 @@
         }
         auto err = mHal->setLayerPerFrameMetadataBlobs(mCurrentDisplay, mCurrentLayer, metadata);
         if (err != Error::NONE) {
-            mWriter.setError(getCommandLoc(), err);
+            mWriter->setError(getCommandLoc(), err);
         }
         return true;
     }
@@ -111,8 +116,8 @@
 
    private:
     using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
-    using BaseType2_1::mWriter;
     using BaseType2_2 = V2_2::hal::ComposerCommandEngine;
+    using BaseType2_1::mWriter;
 
     ComposerHal* mHal;
 };
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
index d3b29bb..e0e1394 100644
--- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
@@ -294,9 +294,6 @@
             (brightness < 0.0f && brightness != -1.0f)) {
             return Error::BAD_PARAMETER;
         }
-        if (!mDispatch.setDisplayBrightness) {
-            return Error::UNSUPPORTED;
-        }
         int32_t error = mDispatch.setDisplayBrightness(mDevice, display, brightness);
         return static_cast<Error>(error);
     }
@@ -307,6 +304,13 @@
             return false;
         }
 
+        if (!BaseType2_1::initDispatch(HWC2_FUNCTION_GET_DISPLAY_CAPABILITIES,
+                                       &mDispatch.getDisplayCapabilities) ||
+            !BaseType2_1::initDispatch(HWC2_FUNCTION_SET_DISPLAY_BRIGHTNESS,
+                                       &mDispatch.setDisplayBrightness)) {
+            return false;
+        }
+
         this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
                                    &mDispatch.getDisplayIdentificationData);
         this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
@@ -317,14 +321,10 @@
                                    &mDispatch.setDisplayedContentSamplingEnabled);
         this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLE,
                                    &mDispatch.getDisplayedContentSample);
-        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CAPABILITIES,
-                                   &mDispatch.getDisplayCapabilities);
         this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_PER_FRAME_METADATA_BLOBS,
                                    &mDispatch.setLayerPerFrameMetadataBlobs);
         this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_BRIGHTNESS_SUPPORT,
                                    &mDispatch.getDisplayBrightnessSupport);
-        this->initOptionalDispatch(HWC2_FUNCTION_SET_DISPLAY_BRIGHTNESS,
-                                   &mDispatch.setDisplayBrightness);
         return true;
     }
 
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index 2fe6cd6..3d81e8f 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -21,22 +21,18 @@
         "ComposerVts.cpp",
     ],
     static_libs: [
-        "VtsHalHidlTargetTestBase",
-        "android.hardware.graphics.composer@2.1",
-        "android.hardware.graphics.composer@2.1-vts",
-        "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.2-vts",
         "android.hardware.graphics.composer@2.3",
-	"android.hardware.graphics.mapper@2.0",
-	"android.hardware.graphics.mapper@2.0-vts",
-	"android.hardware.graphics.mapper@2.1",
-	"android.hardware.graphics.mapper@2.1-vts",
-	"android.hardware.graphics.mapper@3.0",
-	"android.hardware.graphics.mapper@3.0-vts",
+        "libgtest",
+    ],
+    export_static_lib_headers: [
+        "android.hardware.graphics.composer@2.2-vts",
+        "android.hardware.graphics.composer@2.3",
     ],
     header_libs: [
-        "android.hardware.graphics.composer@2.1-command-buffer",
-        "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.3-command-buffer",
+    ],
+    export_header_lib_headers: [
         "android.hardware.graphics.composer@2.3-command-buffer",
     ],
     cflags: [
diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
index d4f5b3a..d73a3b0 100644
--- a/graphics/composer/2.3/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
 
 #include <composer-vts/2.3/ComposerVts.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -27,11 +25,6 @@
 
 using V2_1::Error;
 
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
-    : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
 Composer::Composer(const sp<IComposer>& composer)
     : V2_2::vts::Composer(composer), mComposer(composer) {}
 
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
index 0d4e5b8..dae9ab4 100644
--- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -19,7 +19,6 @@
 #include <memory>
 #include <vector>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android/hardware/graphics/composer/2.3/IComposer.h>
 #include <android/hardware/graphics/composer/2.3/IComposerClient.h>
 #include <composer-vts/2.2/ComposerVts.h>
@@ -49,12 +48,10 @@
    public:
     Composer();
     explicit Composer(const std::string& name);
+    explicit Composer(const sp<IComposer>& composer);
 
     std::unique_ptr<ComposerClient> createClient();
 
-  protected:
-    explicit Composer(const sp<IComposer>& composer);
-
    private:
     const sp<IComposer> mComposer;
 };
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index e421889..fdb055a 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -24,26 +24,31 @@
         "libfmq",
         "libhidlbase",
         "libsync",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.2-vts",
         "android.hardware.graphics.composer@2.3",
         "android.hardware.graphics.composer@2.3-vts",
-        "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.0-vts",
-        "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@2.1-vts",
-        "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0-vts",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
         "android.hardware.graphics.composer@2.3-command-buffer",
     ],
+    disable_framework: true,
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index dafe587..94766af 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -18,13 +18,15 @@
 
 #include <algorithm>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <composer-vts/2.3/ComposerVts.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <mapper-vts/2.0/MapperVts.h>
 
 namespace android {
@@ -43,29 +45,11 @@
 using mapper::V2_0::IMapper;
 using V2_2::vts::Gralloc;
 
-// Test environment for graphics.composer
-class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static GraphicsComposerHidlEnvironment* Instance() {
-        static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IComposer>(); }
-
-   private:
-    GraphicsComposerHidlEnvironment() {}
-
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
-};
-
-class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
+  protected:
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(
-            mComposer = std::make_unique<Composer>(
-                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+                mComposer = std::make_unique<Composer>(IComposer::getService(GetParam())));
         ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
 
         mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
@@ -175,7 +159,7 @@
  *
  * TODO: Check that ports are unique for multiple displays.
  */
-TEST_F(GraphicsComposerHidlTest, GetDisplayIdentificationData) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayIdentificationData) {
     uint8_t port0;
     std::vector<uint8_t> data0;
     if (mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port0, &data0)) {
@@ -193,7 +177,7 @@
 /**
  * Test IComposerClient::Command::SET_LAYER_PER_FRAME_METADATA.
  */
-TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) {
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_PER_FRAME_METADATA) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -244,7 +228,7 @@
 /**
  * Test IComposerClient::getHdrCapabilities_2_3
  */
-TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetHdrCapabilities_2_3) {
     float maxLuminance;
     float maxAverageLuminance;
     float minLuminance;
@@ -256,7 +240,7 @@
 /**
  * Test IComposerClient::getPerFrameMetadataKeys_2_3
  */
-TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetPerFrameMetadataKeys_2_3) {
     std::vector<IComposerClient::PerFrameMetadataKey> keys;
     mComposerClient->getRaw()->getPerFrameMetadataKeys_2_3(
         mPrimaryDisplay, [&](const auto tmpError, const auto outKeys) {
@@ -270,7 +254,7 @@
 /**
  * TestIComposerClient::getReadbackBufferAttributes_2_3
  */
-TEST_F(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetReadbackBufferAttributes_2_3) {
     Dataspace dataspace;
     PixelFormat pixelFormat;
 
@@ -288,7 +272,7 @@
 /**
  * Test IComposerClient::getClientTargetSupport_2_3
  */
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_3) {
     std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -311,7 +295,7 @@
  * Error::BAD_DISPLAY when passed in an invalid display handle
  */
 
-TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_3BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetClientTargetSupport_2_3BadDisplay) {
     std::vector<V2_1::Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
     for (auto config : configs) {
         int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
@@ -333,7 +317,7 @@
 /**
  * Test IComposerClient::getRenderIntents_2_3
  */
-TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3) {
     std::vector<ColorMode> modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
     for (auto mode : modes) {
         std::vector<RenderIntent> intents =
@@ -363,7 +347,7 @@
  * Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_DISPLAY when
  * passed an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3BadDisplay) {
     std::vector<ColorMode> modes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
     for (auto mode : modes) {
         mComposerClient->getRaw()->getRenderIntents_2_3(
@@ -378,7 +362,7 @@
  * Test that IComposerClient::getRenderIntents_2_3 returns Error::BAD_PARAMETER when
  * pased either an invalid Color mode or an invalid Render Intent
  */
-TEST_F(GraphicsComposerHidlTest, GetRenderIntents_2_3BadParameter) {
+TEST_P(GraphicsComposerHidlTest, GetRenderIntents_2_3BadParameter) {
     mComposerClient->getRaw()->getRenderIntents_2_3(
         mPrimaryDisplay, static_cast<ColorMode>(-1),
         [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); });
@@ -387,7 +371,7 @@
 /**
  * IComposerClient::getColorModes_2_3
  */
-TEST_F(GraphicsComposerHidlTest, GetColorModes_2_3) {
+TEST_P(GraphicsComposerHidlTest, GetColorModes_2_3) {
     std::vector<ColorMode> colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
 
     auto native = std::find(colorModes.cbegin(), colorModes.cend(), ColorMode::NATIVE);
@@ -400,7 +384,7 @@
  * Test that IComposerClient::getColorModes_2_3 returns Error::BAD_DISPLAY when
  * passed an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, GetColorMode_2_3BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, GetColorMode_2_3BadDisplay) {
     mComposerClient->getRaw()->getColorModes_2_3(
         mInvalidDisplayId,
         [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); });
@@ -409,7 +393,7 @@
 /**
  * IComposerClient::setColorMode_2_3
  */
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3) {
     std::vector<ColorMode> colorModes = mComposerClient->getColorModes_2_3(mPrimaryDisplay);
     for (auto mode : colorModes) {
         std::vector<RenderIntent> intents =
@@ -430,7 +414,7 @@
  * Test that IComposerClient::setColorMode_2_3 returns an Error::BAD_DISPLAY
  * when passed an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadDisplay) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3BadDisplay) {
     Error error = mComposerClient->getRaw()->setColorMode_2_3(mInvalidDisplayId, ColorMode::NATIVE,
                                                               RenderIntent::COLORIMETRIC);
 
@@ -443,7 +427,7 @@
  * Test that IComposerClient::setColorMode_2_3 returns Error::BAD_PARAMETER when
  * passed an invalid Color mode or an invalid render intent
  */
-TEST_F(GraphicsComposerHidlTest, SetColorMode_2_3BadParameter) {
+TEST_P(GraphicsComposerHidlTest, SetColorMode_2_3BadParameter) {
     Error colorModeError = mComposerClient->getRaw()->setColorMode_2_3(
         mPrimaryDisplay, static_cast<ColorMode>(-1), RenderIntent::COLORIMETRIC);
     EXPECT_EQ(Error::BAD_PARAMETER, colorModeError);
@@ -458,7 +442,7 @@
  * TODO Add color to the layer, use matrix to keep only red component,
  * and check.
  */
-TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) {
+TEST_P(GraphicsComposerHidlTest, SetLayerColorTransform) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -485,7 +469,7 @@
     }
 }
 
-TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) {
     int constexpr invalid = -1;
     auto format = static_cast<PixelFormat>(invalid);
     auto dataspace = static_cast<Dataspace>(invalid);
@@ -505,7 +489,7 @@
               static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid));
 };
 
-TEST_F(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) {
+TEST_P(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) {
     auto const maxFrames = 10;
     auto const enableAllComponents = 0;
     auto error = mComposerClient->setDisplayedContentSamplingEnabled(
@@ -523,7 +507,7 @@
     EXPECT_EQ(error, Error::NONE);
 }
 
-TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSample) {
+TEST_P(GraphicsComposerHidlTest, GetDisplayedContentSample) {
     int constexpr invalid = -1;
     auto format = static_cast<PixelFormat>(invalid);
     auto dataspace = static_cast<Dataspace>(invalid);
@@ -558,7 +542,7 @@
  * getDisplayCapabilities is required in composer 2.3
  * Test some constraints.
  */
-TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBasic) {
+TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBasic) {
     std::vector<IComposerClient::DisplayCapability> capabilities;
     const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
     ASSERT_EQ(Error::NONE, error);
@@ -572,13 +556,13 @@
     EXPECT_EQ(mComposerClient->getDisplayBrightnessSupport(mPrimaryDisplay), hasBrightnessSupport);
 }
 
-TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
+TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
     std::vector<IComposerClient::DisplayCapability> capabilities;
     const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities);
     EXPECT_EQ(Error::BAD_DISPLAY, error);
 }
 
-TEST_F(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) {
+TEST_P(GraphicsComposerHidlTest, SetLayerPerFrameMetadataBlobs) {
     Layer layer;
     ASSERT_NO_FATAL_FAILURE(layer =
                                 mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
@@ -604,7 +588,7 @@
 /*
  * Test that if brightness operations are supported, setDisplayBrightness works as expected.
  */
-TEST_F(GraphicsComposerHidlTest, setDisplayBrightness) {
+TEST_P(GraphicsComposerHidlTest, setDisplayBrightness) {
     std::vector<IComposerClient::DisplayCapability> capabilities;
     const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
     ASSERT_EQ(Error::NONE, error);
@@ -627,6 +611,16 @@
     EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -2.0f), Error::BAD_PARAMETER);
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerHidlCommandTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 }  // namespace
 }  // namespace vts
 }  // namespace V2_3
@@ -634,12 +628,3 @@
 }  // namespace graphics
 }  // namespace hardware
 }  // namespace android
-
-int main(int argc, char** argv) {
-    using android::hardware::graphics::composer::V2_3::vts::GraphicsComposerHidlEnvironment;
-    ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    return status;
-}
diff --git a/graphics/composer/2.4/Android.bp b/graphics/composer/2.4/Android.bp
new file mode 100644
index 0000000..2bbe751
--- /dev/null
+++ b/graphics/composer/2.4/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.composer@2.4",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IComposer.hal",
+        "IComposerCallback.hal",
+        "IComposerClient.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/graphics/composer/2.4/IComposer.hal b/graphics/composer/2.4/IComposer.hal
new file mode 100644
index 0000000..d3b3cb6
--- /dev/null
+++ b/graphics/composer/2.4/IComposer.hal
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.hardware.graphics.composer@2.4;
+
+import IComposerClient;
+import @2.1::Error;
+import @2.3::IComposer;
+
+interface IComposer extends @2.3::IComposer {
+    /**
+     * Creates a v2.4 client of the composer. Supersedes @2.3::createClient.
+     *
+     * @return error is NONE upon success. Otherwise,
+     *         NO_RESOURCES when the client could not be created.
+     * @return client is the newly created client.
+     */
+    createClient_2_4() generates (Error error, IComposerClient client);
+};
diff --git a/graphics/composer/2.4/IComposerCallback.hal b/graphics/composer/2.4/IComposerCallback.hal
new file mode 100644
index 0000000..f343cee
--- /dev/null
+++ b/graphics/composer/2.4/IComposerCallback.hal
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package android.hardware.graphics.composer@2.4;
+
+import @2.1::Display;
+import @2.1::IComposerCallback;
+
+interface IComposerCallback extends @2.1::IComposerCallback {
+    /**
+     * Notifies the client that a vsync event has occurred. This callback must
+     * only be triggered when vsync is enabled for this display (through
+     * setVsyncEnabled).
+     *
+     * @param display is the display which has received a vsync event
+     * @param timestamp is the CLOCK_MONOTONIC time at which the vsync event
+     *        occurred, in nanoseconds.
+     * @param vsyncPeriodNanos is the display vsync period in nanoseconds i.e. the next onVsync_2_4
+     *        is expected to be called vsyncPeriodNanos nanoseconds after this call.
+     */
+    oneway onVsync_2_4(Display display, int64_t timestamp, VsyncPeriodNanos vsyncPeriodNanos);
+
+    /**
+     * Notifies the client that the previously reported timing for vsync period change has been
+     * updated. This may occur if the composer missed the deadline for changing the vsync period
+     * or the client submitted a refresh frame too late.
+     *
+     * @param display is the display which vsync period change is in progress
+     * @param updatedTimeline is the new timeline for the vsync period change.
+     */
+    oneway onVsyncPeriodTimingChanged(Display display, VsyncPeriodChangeTimeline updatedTimeline);
+
+    /**
+     * Notifies the client that the conditions which previously led to returning
+     * SEAMLESS_NOT_POSSIBLE from setActiveConfigWithConstraints have changed and now seamless may
+     * be possible. Client should retry calling setActiveConfigWithConstraints.
+     *
+     * @param display is a display setActiveConfigWithConstraints previously failed with
+     * SEAMLESS_NOT_POSSIBLE.
+     */
+    oneway onSeamlessPossible(Display display);
+};
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
new file mode 100644
index 0000000..9e3cf0e
--- /dev/null
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -0,0 +1,348 @@
+/*
+ * 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.
+ */
+
+package android.hardware.graphics.composer@2.4;
+
+import android.hardware.graphics.common@1.2::PixelFormat;
+import android.hardware.graphics.common@1.2::Dataspace;
+import android.hardware.graphics.composer@2.1::IComposerClient.Command;
+import IComposerCallback;
+import @2.1::Config;
+import @2.1::Display;
+import @2.1::Error;
+import @2.1::IComposerClient;
+import @2.3::IComposerClient;
+
+interface IComposerClient extends @2.3::IComposerClient {
+    /**
+     * Display attributes queryable through getDisplayAttribute_2_4.
+     */
+    enum Attribute : @2.1::IComposerClient.Attribute {
+        /**
+         * The configuration group ID (as int32_t) this config is associated to.
+         * Switching between configurations within the same group may be done seamlessly
+         * in some conditions via setActiveConfigWithConstraints.
+         */
+        CONFIG_GROUP = 7,
+    };
+
+    /**
+     * Required capabilities which are supported by the display. The
+     * particular set of supported capabilities for a given display may be
+     * retrieved using getDisplayCapabilities.
+     */
+    enum DisplayCapability : @2.3::IComposerClient.DisplayCapability {
+        /**
+         * Indicates that the display supports protected contents.
+         * When returned, hardware composer must be able to accept client target
+         * with protected buffers.
+         */
+        PROTECTED_CONTENTS = 4,
+
+        /**
+         * Indicates that both the composer HAL implementation and the given display
+         * support a low latency mode, such as HDMI 2.1 Auto Low Latency Mode.
+         */
+        AUTO_LOW_LATENCY_MODE = 5,
+    };
+
+    enum Command : @2.3::IComposerClient.Command {
+        /**
+         * SET_CLIENT_TARGET_PROPERTY has this pseudo prototype
+         *
+         * This command has the following binary layout in bytes:
+         *
+         *     0 - 3: clientTargetProperty.pixelFormat
+         *     4 - 7: clientTargetProperty.dataspace
+         *
+         *   setClientTargetProperty(ClientTargetProperty clientTargetProperty);
+         */
+         SET_CLIENT_TARGET_PROPERTY = 0x105 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+
+        /**
+         * SET_LAYER_GENERIC_METADATA has this pseudo prototype
+         *
+         *   setLayerGenericMetadata(string key, bool mandatory, vec<uint8_t> value);
+         *
+         * Sets a piece of generic metadata for the given layer. If this
+         * function is called twice with the same key but different values, the
+         * newer value must override the older one. Calling this function with a
+         * 0-length value must reset that key's metadata as if it had not been
+         * set.
+         *
+         * A given piece of metadata may either be mandatory or a hint
+         * (non-mandatory) as indicated by the second parameter. Mandatory
+         * metadata may affect the composition result, which is to say that it
+         * may cause a visible change in the final image. By contrast, hints may
+         * only affect the composition strategy, such as which layers are
+         * composited by the client, but must not cause a visible change in the
+         * final image. The value of the mandatory flag shall match the value
+         * returned from getLayerGenericMetadataKeys for the given key.
+         *
+         * Only keys which have been returned from getLayerGenericMetadataKeys()
+         * shall be accepted. Any other keys must result in an UNSUPPORTED error.
+         *
+         * The value passed into this function shall be the binary
+         * representation of a HIDL type corresponding to the given key. For
+         * example, a key of 'com.example.V1_3.Foo' shall be paired with a
+         * value of type com.example@1.3::Foo, which would be defined in a
+         * vendor HAL extension.
+         *
+         * This function will be encoded in the command buffer in this order:
+         *   1) The key length, stored as a uint32_t
+         *   2) The key itself, padded to a uint32_t boundary if necessary
+         *   3) The mandatory flag, stored as a uint32_t
+         *   4) The value length in bytes, stored as a uint32_t
+         *   5) The value itself, padded to a uint32_t boundary if necessary
+         *
+         * @param key indicates which metadata value should be set on this layer
+         * @param mandatory indicates whether this particular key represents
+         *        mandatory metadata or a hint (non-mandatory metadata), as
+         *        described above
+         * @param value is a binary representation of a HIDL struct
+         *        corresponding to the key as described above
+         */
+        SET_LAYER_GENERIC_METADATA = 0x40e << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+    };
+
+    /**
+     * Supersedes {@link @2.1::IComposerClient.DisplayType}.
+     */
+    enum DisplayConnectionType : uint32_t {
+        /**
+         * Display is connected through internal port, e.g. DSI, eDP.
+         */
+        INTERNAL = 0,
+        /**
+         * Display is connected through external port, e.g. HDMI, DisplayPort.
+         */
+        EXTERNAL = 1,
+    };
+
+    enum ContentType : uint32_t {
+        NONE = 0,
+
+        /**
+         * These modes correspond to those found in the HDMI 1.4 specification.
+         */
+        GRAPHICS = 1,
+        PHOTO = 2,
+        CINEMA = 3,
+        GAME = 4,
+    };
+
+    /**
+     * Constraints for changing vsync period.
+     */
+    struct VsyncPeriodChangeConstraints {
+        /**
+         * Time in CLOCK_MONOTONIC after which the vsync period may change
+         * (i.e., the vsync period must not change before this time).
+         */
+        int64_t desiredTimeNanos;
+
+        /**
+         * If true, requires that the vsync period change must happen seamlessly without
+         * a noticeable visual artifact.
+         */
+        bool seamlessRequired;
+    };
+
+    struct ClientTargetProperty {
+        PixelFormat pixelFormat;
+        Dataspace dataspace;
+    };
+
+    /**
+     * Provides a IComposerCallback object for the device to call.
+     *
+     * This function must be called only once.
+     *
+     * @param callback is the IComposerCallback object.
+     */
+    registerCallback_2_4(IComposerCallback callback);
+
+    /**
+     * Provides a list of supported capabilities (as described in the
+     * definition of DisplayCapability above). This list must not change after
+     * initialization.
+     *
+     * @return error is NONE upon success. Otherwise,
+     *     BAD_DISPLAY when an invalid display handle was passed in.
+     * @return capabilities is a list of supported capabilities.
+     */
+    getDisplayCapabilities_2_4(Display display)
+        generates (Error error, vec<DisplayCapability> capabilities);
+
+    /**
+     * Returns whether the given physical display is internal or external.
+     *
+     * @return error is NONE upon success. Otherwise,
+     *     BAD_DISPLAY when the given display is invalid or virtual.
+     * @return type is the connection type of the display.
+     */
+    getDisplayConnectionType(Display display) generates (Error error, DisplayConnectionType type);
+
+    /**
+     * Returns a display attribute value for a particular display
+     * configuration.
+     *
+     * @param display is the display to query.
+     * @param config is the display configuration for which to return
+     *        attribute values.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         BAD_CONFIG when config does not name a valid configuration for
+     *                    this display.
+     *         BAD_PARAMETER when attribute is unrecognized.
+     *         UNSUPPORTED when attribute cannot be queried for the config.
+     * @return value is the value of the attribute.
+     */
+    getDisplayAttribute_2_4(Display display, Config config, Attribute attribute)
+        generates (Error error, int32_t value);
+
+    /**
+     * Retrieves which vsync period the display is currently using.
+     *
+     * If no display configuration is currently active, this function must
+     * return BAD_CONFIG. If the vsync period is about to change due to a
+     * setActiveConfigWithConstraints call, this function must return the current vsync period
+     * until the change takes place.
+     *
+     * @param display is the display for which the vsync period is queried.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         BAD_CONFIG when no configuration is currently active.
+     * @return vsyncPeriodNanos is the current vsync period of the display.
+     */
+    getDisplayVsyncPeriod(Display display)
+        generates (Error error, VsyncPeriodNanos vsyncPeriodNanos);
+
+    /**
+     * Sets the active configuration and the refresh rate for this display.
+     * If the new config shares the same config group as the current config,
+     * only the vsync period shall change.
+     * Upon returning, the given display configuration, except vsync period, must be active and
+     * remain so until either this function is called again or the display is disconnected.
+     * When the display starts to refresh at the new vsync period, onVsync_2_4 callback must be
+     * called with the new vsync period.
+     *
+     * @param display is the display for which the active config is set.
+     * @param config is the new display configuration.
+     * @param vsyncPeriodChangeConstraints are the constraints required for changing vsync period.
+     *
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         BAD_CONFIG when the configuration handle passed in is not valid
+     *                    for this display.
+     *         SEAMLESS_NOT_ALLOWED when seamlessRequired was true but config provided doesn't
+     *                              share the same config group as the current config.
+     *         SEAMLESS_NOT_POSSIBLE when seamlessRequired was true but the display cannot achieve
+     *                               the vsync period change without a noticeable visual artifact.
+     *                               When the conditions change and it may be possible to change
+     *                               the vsync period seamlessly, onSeamlessPossible callback
+     *                               must be called to indicate that caller should retry.
+     * @return timeline is the timeline for the vsync period change.
+     */
+    setActiveConfigWithConstraints(Display display, Config config,
+        VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints)
+        generates (Error error, VsyncPeriodChangeTimeline timeline);
+
+    /**
+     * Requests the display to enable/disable its low latency mode.
+     *
+     * If the display is connected via HDMI 2.1, then Auto Low Latency Mode should be triggered. If
+     * the display is internally connected and a custom low latency mode is available, that should
+     * be triggered.
+     *
+     * This function should only be called if the display reports support for
+     * DisplayCapability::AUTO_LOW_LATENCY_MODE from getDisplayCapabilities_2_4.
+     *
+     * @return error is NONE upon success. Otherwise,
+     *     BAD_DISPLAY when an invalid display handle was passed in.
+     *     UNSUPPORTED when AUTO_LOW_LATENCY_MODE is not supported by the composer
+     *         implementation or the given display
+     */
+    setAutoLowLatencyMode(Display display, bool on)
+        generates (Error error);
+
+    /**
+     * Provides a list of all the content types supported by this display (any of
+     * ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}). This list must not change after
+     * initialization.
+     *
+     * Content types are introduced in HDMI 1.4 and supporting them is optional. The
+     * ContentType::NONE is always supported and will not be returned by this method..
+     *
+     * @return error is NONE upon success. Otherwise,
+     *     BAD_DISPLAY when an invalid display handle was passed in.
+     * @return supportedContentTypes is a list of supported content types.
+     */
+    getSupportedContentTypes(Display display)
+        generates(Error error, vec<ContentType> supportedContentTypes);
+
+    /**
+     * Instructs the connected display that the content being shown is of the given type - one of
+     * GRAPHICS, PHOTO, CINEMA, GAME.
+     *
+     * Content types are introduced in HDMI 1.4 and supporting them is optional. If they are
+     * supported, this signal should switch the display to a mode that is optimal for the given
+     * type of content. See HDMI 1.4 specification for more information.
+     *
+     * If the display is internally connected (not through HDMI), and such modes are available,
+     * this method should trigger them.
+     *
+     * This function should only be called if the display reports support for the corresponding
+     * content type (ContentType::{GRAPHICS, PHOTO, CINEMA, GAME}) from getSupportedContentTypes.
+     * ContentType::NONE is supported by default and can always be set.
+     *
+     * @return error is NONE upon success. Otherwise,
+     *     BAD_DISPLAY when an invalid display handle was passed in.
+     *     UNSUPPORTED when the given content type is not supported by the composer
+     *         implementation or the given display
+     */
+    setContentType(Display display, ContentType type)
+        generates (Error error);
+
+    struct LayerGenericMetadataKey {
+        /**
+         * Key names must comply with the requirements specified for
+         * getLayerGenericMetadataKeys below
+         */
+        string name;
+
+        /**
+         * The mandatory flag is defined in the description of
+         * setLayerGenericMetadata above
+         */
+        bool mandatory;
+    };
+
+    /**
+     * Retrieves the set of keys that may be passed into setLayerGenericMetadata
+     *
+     * Key names must meet the following requirements:
+     * - Must be specified in reverse domain name notation
+     * - Must not start with 'com.android' or 'android'
+     * - Must be unique within the returned vector
+     * - Must correspond to a matching HIDL struct type, which defines the
+     *   structure of its values. For example, the key 'com.example.V1-3.Foo'
+     *   should correspond to a value of type com.example@1.3::Foo, which is
+     *   defined in a vendor HAL extension
+     */
+    getLayerGenericMetadataKeys()
+        generates(Error error, vec<LayerGenericMetadataKey> keys);
+};
diff --git a/graphics/composer/2.4/default/Android.bp b/graphics/composer/2.4/default/Android.bp
new file mode 100644
index 0000000..a30609b
--- /dev/null
+++ b/graphics/composer/2.4/default/Android.bp
@@ -0,0 +1,46 @@
+//
+// 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.
+//
+
+cc_binary {
+    name: "android.hardware.graphics.composer@2.4-service",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: ["service.cpp"],
+    init_rc: ["android.hardware.graphics.composer@2.4-service.rc"],
+    header_libs: [
+        "android.hardware.graphics.composer@2.4-passthrough",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.4",
+        "android.hardware.graphics.composer@2.1-resources",
+        "android.hardware.graphics.composer@2.2-resources",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "libhwc2on1adapter",
+        "libhwc2onfbadapter",
+        "liblog",
+        "libsync",
+        "libutils",
+    ],
+}
diff --git a/graphics/composer/2.4/default/OWNERS b/graphics/composer/2.4/default/OWNERS
new file mode 100644
index 0000000..cc6d937
--- /dev/null
+++ b/graphics/composer/2.4/default/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
diff --git a/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
new file mode 100644
index 0000000..a296b0a
--- /dev/null
+++ b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
@@ -0,0 +1,7 @@
+service vendor.hwcomposer-2-4 /vendor/bin/hw/android.hardware.graphics.composer@2.4-service
+    class hal animation
+    user system
+    group graphics drmrpc
+    capabilities SYS_NICE
+    onrestart restart surfaceflinger
+    writepid /dev/cpuset/system-background/tasks
diff --git a/graphics/composer/2.4/default/service.cpp b/graphics/composer/2.4/default/service.cpp
new file mode 100644
index 0000000..98dac3e
--- /dev/null
+++ b/graphics/composer/2.4/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include <sched.h>
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <binder/ProcessState.h>
+#include <composer-passthrough/2.4/HwcLoader.h>
+#include <hidl/HidlTransportSupport.h>
+
+using android::hardware::graphics::composer::V2_4::IComposer;
+using android::hardware::graphics::composer::V2_4::passthrough::HwcLoader;
+
+int main() {
+    // the conventional HAL might start binder services
+    android::ProcessState::initWithDriver("/dev/vndbinder");
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
+    android::ProcessState::self()->startThreadPool();
+
+    // same as SF main thread
+    struct sched_param param = {0};
+    param.sched_priority = 2;
+    if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO: %d", errno);
+    }
+
+    android::hardware::configureRpcThreadpool(4, true /* will join */);
+
+    android::sp<IComposer> composer = HwcLoader::load();
+    if (composer == nullptr) {
+        return 1;
+    }
+    if (composer->registerAsService() != android::NO_ERROR) {
+        ALOGE("failed to register service");
+        return 1;
+    }
+
+    android::hardware::joinRpcThreadpool();
+
+    ALOGE("service is terminating");
+    return 1;
+}
diff --git a/graphics/composer/2.4/types.hal b/graphics/composer/2.4/types.hal
new file mode 100644
index 0000000..065f024
--- /dev/null
+++ b/graphics/composer/2.4/types.hal
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package android.hardware.graphics.composer@2.4;
+
+import @2.1::Error;
+
+enum Error : @2.1::Error {
+    /**
+     * Seamless cannot be required for configurations that don't share a config group
+     */
+    SEAMLESS_NOT_ALLOWED = 9,
+    /**
+     * Seamless requirements cannot be met
+     */
+    SEAMLESS_NOT_POSSIBLE = 10,
+};
+
+/**
+ * Timing for a vsync period change.
+ */
+struct VsyncPeriodChangeTimeline {
+    /**
+     * The time in CLOCK_MONOTONIC when the new display will start to refresh at
+     * the new vsync period.
+     */
+    int64_t newVsyncAppliedTimeNanos;
+
+    /**
+     * Set to true if the client is required to send a frame to be displayed before
+     * the change can take place.
+     */
+    bool refreshRequired;
+
+    /**
+     * The time in CLOCK_MONOTONIC when the client is expected to send the new frame.
+     * Should be ignored if refreshRequired is false.
+     */
+    int64_t refreshTimeNanos;
+};
+
+typedef uint32_t VsyncPeriodNanos;
diff --git a/graphics/composer/2.4/utils/OWNERS b/graphics/composer/2.4/utils/OWNERS
new file mode 100644
index 0000000..cc6d937
--- /dev/null
+++ b/graphics/composer/2.4/utils/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
diff --git a/graphics/composer/2.4/utils/command-buffer/Android.bp b/graphics/composer/2.4/utils/command-buffer/Android.bp
new file mode 100644
index 0000000..8acf0e1
--- /dev/null
+++ b/graphics/composer/2.4/utils/command-buffer/Android.bp
@@ -0,0 +1,18 @@
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.4-command-buffer",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.4",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.composer@2.4",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.3-command-buffer",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.3-command-buffer",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
new file mode 100644
index 0000000..eb35e5c
--- /dev/null
+++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+
+using android::hardware::MessageQueue;
+using android::hardware::graphics::composer::V2_4::Error;
+using android::hardware::graphics::composer::V2_4::IComposerClient;
+
+// This class helps build a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase : public V2_3::CommandWriterBase {
+  public:
+    static constexpr uint16_t kSetClientTargetPropertyLength = 2;
+
+    CommandWriterBase(uint32_t initialMaxSize) : V2_3::CommandWriterBase(initialMaxSize) {}
+
+    void setClientTargetProperty(
+            const IComposerClient::ClientTargetProperty& clientTargetProperty) {
+        beginCommand(IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY,
+                     kSetClientTargetPropertyLength);
+        writeSigned(static_cast<int32_t>(clientTargetProperty.pixelFormat));
+        writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace));
+        endCommand();
+    }
+
+    void setLayerGenericMetadata(const hidl_string& key, const bool mandatory,
+                                 const hidl_vec<uint8_t>& value) {
+        const size_t commandSize = 3 + sizeToElements(key.size()) + sizeToElements(value.size());
+        if (commandSize > std::numeric_limits<uint16_t>::max()) {
+            LOG_FATAL("Too much generic metadata (%zu elements)", commandSize);
+            return;
+        }
+
+        beginCommand(IComposerClient::Command::SET_LAYER_GENERIC_METADATA,
+                     static_cast<uint16_t>(commandSize));
+        write(key.size());
+        writeBlob(key.size(), reinterpret_cast<const unsigned char*>(key.c_str()));
+        write(mandatory);
+        write(value.size());
+        writeBlob(value.size(), value.data());
+        endCommand();
+    }
+
+  protected:
+    uint32_t sizeToElements(uint32_t size) { return (size + 3) / 4; }
+};
+
+// This class helps parse a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase : public V2_3::CommandReaderBase {
+  public:
+    CommandReaderBase() : V2_3::CommandReaderBase() {}
+};
+
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.4/utils/hal/Android.bp b/graphics/composer/2.4/utils/hal/Android.bp
new file mode 100644
index 0000000..f4cdea4
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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.
+//
+
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.4-hal",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.4",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.composer@2.4",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.3-hal",
+        "android.hardware.graphics.composer@2.4-command-buffer",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.3-hal",
+        "android.hardware.graphics.composer@2.4-command-buffer",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h
new file mode 100644
index 0000000..129bae6
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Composer.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <composer-hal/2.3/Composer.h>
+#include <composer-hal/2.4/ComposerClient.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+namespace detail {
+
+// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerImpl : public V2_3::hal::detail::ComposerImpl<Interface, Hal> {
+  public:
+    static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) {
+        return std::make_unique<ComposerImpl>(std::move(hal));
+    }
+
+    explicit ComposerImpl(std::unique_ptr<Hal> hal) : BaseType2_3(std::move(hal)) {}
+
+    // IComposer 2.4 interface
+
+    Return<void> createClient_2_4(IComposer::createClient_2_4_cb hidl_cb) override {
+        std::unique_lock<std::mutex> lock(mClientMutex);
+        if (!waitForClientDestroyedLocked(lock)) {
+            hidl_cb(Error::NO_RESOURCES, nullptr);
+            return Void();
+        }
+
+        sp<ComposerClient> client = ComposerClient::create(mHal.get()).release();
+        if (!client) {
+            hidl_cb(Error::NO_RESOURCES, nullptr);
+            return Void();
+        }
+
+        auto clientDestroyed = [this]() { onClientDestroyed(); };
+        client->setOnClientDestroyed(clientDestroyed);
+
+        mClient = client;
+        hidl_cb(Error::NONE, client);
+        return Void();
+    }
+
+  private:
+    using BaseType2_3 = V2_3::hal::detail::ComposerImpl<Interface, Hal>;
+    using BaseType2_1 = V2_1::hal::detail::ComposerImpl<Interface, Hal>;
+
+    using BaseType2_1::mClient;
+    using BaseType2_1::mClientMutex;
+    using BaseType2_1::mHal;
+    using BaseType2_1::onClientDestroyed;
+    using BaseType2_1::waitForClientDestroyedLocked;
+};
+
+}  // namespace detail
+
+using Composer = detail::ComposerImpl<IComposer, ComposerHal>;
+
+}  // namespace hal
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
new file mode 100644
index 0000000..c889069
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerClient.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.4/IComposerCallback.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-hal/2.4/ComposerCommandEngine.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-resources/2.1/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+namespace detail {
+
+// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl<Interface, Hal> {
+  public:
+    ComposerClientImpl(Hal* hal) : BaseType2_3(hal) {}
+
+    ~ComposerClientImpl() override { mHal->unregisterEventCallback_2_4(); }
+
+    class HalEventCallback : public Hal::EventCallback_2_4 {
+      public:
+        HalEventCallback(const sp<IComposerCallback> callback,
+                         V2_1::hal::ComposerResources* resources)
+            : mCallback(callback), mResources(resources) {}
+
+        void onHotplug(Display display, IComposerCallback::Connection connected) override {
+            if (connected == IComposerCallback::Connection::CONNECTED) {
+                mResources->addPhysicalDisplay(display);
+            } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
+                mResources->removeDisplay(display);
+            }
+
+            auto ret = mCallback->onHotplug(display, connected);
+            ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str());
+        }
+
+        void onRefresh(Display display) override {
+            mResources->setDisplayMustValidateState(display, true);
+            auto ret = mCallback->onRefresh(display);
+            ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s", ret.description().c_str());
+        }
+
+        void onVsync(Display display, int64_t timestamp) override {
+            auto ret = mCallback->onVsync(display, timestamp);
+            ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s", ret.description().c_str());
+        }
+
+        void onVsync_2_4(Display display, int64_t timestamp,
+                         VsyncPeriodNanos vsyncPeriodNanos) override {
+            auto ret = mCallback->onVsync_2_4(display, timestamp, vsyncPeriodNanos);
+            ALOGE_IF(!ret.isOk(), "failed to send onVsync_2_4: %s", ret.description().c_str());
+        }
+
+        void onVsyncPeriodTimingChanged(Display display,
+                                        const VsyncPeriodChangeTimeline& updatedTimeline) override {
+            auto ret = mCallback->onVsyncPeriodTimingChanged(display, updatedTimeline);
+            ALOGE_IF(!ret.isOk(), "failed to send onVsyncPeriodTimingChanged: %s",
+                     ret.description().c_str());
+        }
+
+        void onSeamlessPossible(Display display) override {
+            auto ret = mCallback->onSeamlessPossible(display);
+            ALOGE_IF(!ret.isOk(), "failed to send onSealmessPossible: %s",
+                     ret.description().c_str());
+        }
+
+      protected:
+        const sp<IComposerCallback> mCallback;
+        V2_1::hal::ComposerResources* const mResources;
+    };
+
+    Return<void> registerCallback_2_4(const sp<IComposerCallback>& callback) override {
+        // no locking as we require this function to be called only once
+        mHalEventCallback_2_4 = std::make_unique<HalEventCallback>(callback, mResources.get());
+        mHal->registerEventCallback_2_4(mHalEventCallback_2_4.get());
+        return Void();
+    }
+
+    Return<void> getDisplayCapabilities_2_4(
+            Display display, IComposerClient::getDisplayCapabilities_2_4_cb hidl_cb) override {
+        std::vector<IComposerClient::DisplayCapability> capabilities;
+        Error error = mHal->getDisplayCapabilities_2_4(display, &capabilities);
+        hidl_cb(error, capabilities);
+        return Void();
+    }
+
+    Return<void> getDisplayConnectionType(
+            Display display, IComposerClient::getDisplayConnectionType_cb hidl_cb) override {
+        IComposerClient::DisplayConnectionType type;
+        Error error = mHal->getDisplayConnectionType(display, &type);
+        hidl_cb(error, type);
+        return Void();
+    }
+
+    Return<void> getDisplayAttribute_2_4(
+            Display display, Config config, IComposerClient::Attribute attribute,
+            IComposerClient::getDisplayAttribute_2_4_cb hidl_cb) override {
+        int32_t value = 0;
+        Error error = mHal->getDisplayAttribute_2_4(display, config, attribute, &value);
+        hidl_cb(error, value);
+        return Void();
+    }
+
+    Return<void> getDisplayVsyncPeriod(Display display,
+                                       IComposerClient::getDisplayVsyncPeriod_cb hidl_cb) override {
+        VsyncPeriodNanos vsyncPeriods;
+        Error error = mHal->getDisplayVsyncPeriod(display, &vsyncPeriods);
+        hidl_cb(error, vsyncPeriods);
+        return Void();
+    }
+
+    Return<void> setActiveConfigWithConstraints(
+            Display display, Config config,
+            const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+            IComposerClient::setActiveConfigWithConstraints_cb hidl_cb) override {
+        VsyncPeriodChangeTimeline timeline = {};
+        Error error = mHal->setActiveConfigWithConstraints(display, config,
+                                                           vsyncPeriodChangeConstraints, &timeline);
+        hidl_cb(error, timeline);
+        return Void();
+    }
+
+    Return<Error> setAutoLowLatencyMode(Display display, bool on) override {
+        return mHal->setAutoLowLatencyMode(display, on);
+    }
+
+    Return<void> getSupportedContentTypes(
+            Display display, IComposerClient::getSupportedContentTypes_cb hidl_cb) override {
+        std::vector<IComposerClient::ContentType> supportedContentTypes;
+        Error error = mHal->getSupportedContentTypes(display, &supportedContentTypes);
+
+        hidl_cb(error, supportedContentTypes);
+        return Void();
+    }
+
+    Return<Error> setContentType(Display display,
+                                 IComposerClient::ContentType contentType) override {
+        return mHal->setContentType(display, contentType);
+    }
+
+    Return<void> getLayerGenericMetadataKeys(
+            IComposerClient::getLayerGenericMetadataKeys_cb hidl_cb) override {
+        std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+        Error error = mHal->getLayerGenericMetadataKeys(&keys);
+        hidl_cb(error, keys);
+        return Void();
+    }
+
+    static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
+        auto client = std::make_unique<ComposerClientImpl>(hal);
+        return client->init() ? std::move(client) : nullptr;
+    }
+
+  protected:
+    std::unique_ptr<V2_1::hal::ComposerCommandEngine> createCommandEngine() override {
+        return std::make_unique<ComposerCommandEngine>(
+                mHal, static_cast<V2_2::hal::ComposerResources*>(mResources.get()));
+    }
+
+  private:
+    using BaseType2_3 = V2_3::hal::detail::ComposerClientImpl<Interface, Hal>;
+    using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+    using BaseType2_1::mHal;
+    using BaseType2_1::mResources;
+    std::unique_ptr<HalEventCallback> mHalEventCallback_2_4;
+};
+
+}  // namespace detail
+
+using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>;
+
+}  // namespace hal
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
new file mode 100644
index 0000000..697d6b8
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerCommandEngine.h included without LOG_TAG"
+#endif
+
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <composer-hal/2.1/ComposerCommandEngine.h>
+#include <composer-hal/2.3/ComposerCommandEngine.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+class ComposerCommandEngine : public V2_3::hal::ComposerCommandEngine {
+  public:
+    ComposerCommandEngine(ComposerHal* hal, V2_2::hal::ComposerResources* resources)
+        : BaseType2_3(hal, resources), mHal(hal) {}
+
+  protected:
+    std::unique_ptr<V2_1::CommandWriterBase> createCommandWriter(
+            size_t writerInitialSize) override {
+        return std::make_unique<CommandWriterBase>(writerInitialSize);
+    }
+
+  private:
+    using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
+    using BaseType2_3 = V2_3::hal::ComposerCommandEngine;
+    using BaseType2_1::mWriter;
+
+    V2_1::Error executeValidateDisplayInternal() override {
+        std::vector<Layer> changedLayers;
+        std::vector<IComposerClient::Composition> compositionTypes;
+        uint32_t displayRequestMask = 0x0;
+        std::vector<Layer> requestedLayers;
+        std::vector<uint32_t> requestMasks;
+        IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888,
+                                                                   Dataspace::UNKNOWN};
+
+        auto err = mHal->validateDisplay_2_4(mCurrentDisplay, &changedLayers, &compositionTypes,
+                                             &displayRequestMask, &requestedLayers, &requestMasks,
+                                             &clientTargetProperty);
+        mResources->setDisplayMustValidateState(mCurrentDisplay, false);
+        if (err == Error::NONE) {
+            mWriter->setChangedCompositionTypes(changedLayers, compositionTypes);
+            mWriter->setDisplayRequests(displayRequestMask, requestedLayers, requestMasks);
+            getWriter()->setClientTargetProperty(clientTargetProperty);
+        } else {
+            mWriter->setError(getCommandLoc(), static_cast<V2_1::Error>(err));
+        }
+        return static_cast<V2_1::Error>(err);
+    }
+
+    CommandWriterBase* getWriter() { return static_cast<CommandWriterBase*>(mWriter.get()); }
+
+    bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
+        switch (static_cast<IComposerClient::Command>(command)) {
+            case IComposerClient::Command::SET_LAYER_GENERIC_METADATA:
+                return executeSetLayerGenericMetadata(length);
+            default:
+                return BaseType2_3::executeCommand(command, length);
+        }
+    }
+
+    bool executeSetLayerGenericMetadata(uint16_t length) {
+        // We expect at least two buffer lengths and a mandatory flag
+        if (length < 3) {
+            return false;
+        }
+
+        const uint32_t keySize = read();
+        std::string key;
+        key.resize(keySize);
+        readBlob(keySize, key.data());
+
+        const bool mandatory = read();
+
+        const uint32_t valueSize = read();
+        std::vector<uint8_t> value(valueSize);
+        readBlob(valueSize, value.data());
+
+        auto error = mHal->setLayerGenericMetadata(mCurrentDisplay, mCurrentLayer, key, mandatory,
+                                                   value);
+        if (error != Error::NONE) {
+            // The error cast is safe because setLayerGenericMetadata doesn't
+            // return any of the new values added in V2_4::Error
+            mWriter->setError(getCommandLoc(), static_cast<V2_1::Error>(error));
+        }
+
+        return true;
+    }
+
+    ComposerHal* mHal;
+};
+
+}  // namespace hal
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
new file mode 100644
index 0000000..58991c1
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/graphics/composer/2.4/types.h>
+#include <composer-hal/2.3/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Config;
+using V2_1::Display;
+using V2_1::Layer;
+using V2_4::Error;
+using V2_4::VsyncPeriodNanos;
+
+class ComposerHal : public V2_3::hal::ComposerHal {
+  public:
+    class EventCallback_2_4 {
+      public:
+        virtual ~EventCallback_2_4() = default;
+        virtual void onHotplug(Display display, IComposerCallback::Connection connected) = 0;
+        virtual void onRefresh(Display display) = 0;
+        virtual void onVsync(Display display, int64_t timestamp) = 0;
+        virtual void onVsync_2_4(Display display, int64_t timestamp,
+                                 VsyncPeriodNanos vsyncPeriodNanos) = 0;
+        virtual void onVsyncPeriodTimingChanged(Display display,
+                                                const VsyncPeriodChangeTimeline& timeline) = 0;
+        virtual void onSeamlessPossible(Display display) = 0;
+    };
+
+    virtual void registerEventCallback_2_4(EventCallback_2_4* callback) = 0;
+
+    virtual void unregisterEventCallback_2_4() = 0;
+
+    virtual Error getDisplayCapabilities_2_4(
+            Display display, std::vector<IComposerClient::DisplayCapability>* outCapabilities) = 0;
+    virtual Error getDisplayConnectionType(Display display,
+                                           IComposerClient::DisplayConnectionType* outType) = 0;
+    virtual Error getDisplayAttribute_2_4(Display display, Config config,
+                                          IComposerClient::Attribute attribute,
+                                          int32_t* outValue) = 0;
+    virtual Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) = 0;
+    virtual Error setActiveConfigWithConstraints(
+            Display display, Config config,
+            const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+            VsyncPeriodChangeTimeline* timeline) = 0;
+    virtual Error setAutoLowLatencyMode(Display display, bool on) = 0;
+    virtual Error getSupportedContentTypes(
+            Display display,
+            std::vector<IComposerClient::ContentType>* outSupportedContentTypes) = 0;
+    virtual Error setContentType(Display display, IComposerClient::ContentType contentType) = 0;
+    virtual Error validateDisplay_2_4(
+            Display display, std::vector<Layer>* outChangedLayers,
+            std::vector<IComposerClient::Composition>* outCompositionTypes,
+            uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+            std::vector<uint32_t>* outRequestMasks,
+            IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
+    virtual Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+                                          bool mandatory, const std::vector<uint8_t>& value) = 0;
+    virtual Error getLayerGenericMetadataKeys(
+            std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
+};
+
+}  // namespace hal
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.4/utils/passthrough/Android.bp b/graphics/composer/2.4/utils/passthrough/Android.bp
new file mode 100644
index 0000000..43d9aaa
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.4-passthrough",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    header_libs: [
+        "android.hardware.graphics.composer@2.3-passthrough",
+        "android.hardware.graphics.composer@2.4-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.3-passthrough",
+        "android.hardware.graphics.composer@2.4-hal",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
new file mode 100644
index 0000000..d28e006
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -0,0 +1,402 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcHal.h included without LOG_TAG"
+#endif
+
+#include <type_traits>
+
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-passthrough/2.3/HwcHal.h>
+#include <hardware/hwcomposer_defs.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace passthrough {
+
+namespace detail {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Config;
+using V2_1::Display;
+using V2_1::Layer;
+using V2_4::Error;
+
+// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
+template <typename Hal>
+class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
+  public:
+    void registerEventCallback_2_4(hal::ComposerHal::EventCallback_2_4* callback) override {
+        mEventCallback_2_4 = callback;
+
+        BaseType2_1::mDispatch.registerCallback(
+                mDevice, HWC2_CALLBACK_HOTPLUG, this,
+                reinterpret_cast<hwc2_function_pointer_t>(hotplugHook));
+        BaseType2_1::mDispatch.registerCallback(
+                mDevice, HWC2_CALLBACK_REFRESH, this,
+                reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
+        BaseType2_1::mDispatch.registerCallback(
+                mDevice, HWC2_CALLBACK_VSYNC_2_4, this,
+                reinterpret_cast<hwc2_function_pointer_t>(vsync_2_4_Hook));
+        BaseType2_1::mDispatch.registerCallback(
+                mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED, this,
+                reinterpret_cast<hwc2_function_pointer_t>(vsyncPeriodTimingChangedHook));
+        BaseType2_1::mDispatch.registerCallback(
+                mDevice, HWC2_CALLBACK_SEAMLESS_POSSIBLE, this,
+                reinterpret_cast<hwc2_function_pointer_t>(seamlessPossibleHook));
+    }
+
+    void unregisterEventCallback_2_4() override {
+        // we assume the callback functions
+        //
+        //  - can be unregistered
+        //  - can be in-flight
+        //  - will never be called afterward
+        //
+        // which is likely incorrect
+        BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, nullptr);
+        BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, nullptr);
+        BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, nullptr);
+        BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_PERIOD_TIMING_CHANGED,
+                                                this, nullptr);
+        BaseType2_1::mDispatch.registerCallback(mDevice, HWC2_CALLBACK_SEAMLESS_POSSIBLE, this,
+                                                nullptr);
+
+        mEventCallback_2_4 = nullptr;
+    }
+
+    Error getDisplayCapabilities_2_4(
+            Display display,
+            std::vector<IComposerClient::DisplayCapability>* outCapabilities) override {
+        std::vector<V2_3::IComposerClient::DisplayCapability> capabilities;
+        V2_3::Error error_2_3 = BaseType2_3::getDisplayCapabilities(display, &capabilities);
+        Error error = static_cast<Error>(error_2_3);
+        if (error != Error::NONE) {
+            return error;
+        }
+        outCapabilities->clear();
+        outCapabilities->reserve(capabilities.size());
+        for (auto capability : capabilities) {
+            outCapabilities->push_back(static_cast<IComposerClient::DisplayCapability>(capability));
+        }
+        return Error::NONE;
+    }
+
+    Error getDisplayConnectionType(Display display,
+                                   IComposerClient::DisplayConnectionType* outType) override {
+        if (!mDispatch.getDisplayConnectionType) {
+            return Error::UNSUPPORTED;
+        }
+
+        uint32_t type = HWC2_DISPLAY_CONNECTION_TYPE_INTERNAL;
+        int32_t error = mDispatch.getDisplayConnectionType(mDevice, display, &type);
+        *outType = static_cast<IComposerClient::DisplayConnectionType>(type);
+        return static_cast<Error>(error);
+    }
+
+    Error getDisplayAttribute_2_4(Display display, Config config,
+                                  IComposerClient::Attribute attribute,
+                                  int32_t* outValue) override {
+        int32_t err = BaseType2_1::mDispatch.getDisplayAttribute(
+                mDevice, display, config, static_cast<int32_t>(attribute), outValue);
+        if (err != HWC2_ERROR_NONE && *outValue == -1) {
+            // Convert the error from hwcomposer2 to IComposerClient definition
+            return Error::BAD_PARAMETER;
+        }
+        return static_cast<Error>(err);
+    }
+
+    Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override {
+        if (!mDispatch.getDisplayVsyncPeriod) {
+            return Error::UNSUPPORTED;
+        }
+
+        int32_t error = mDispatch.getDisplayVsyncPeriod(mDevice, display, outVsyncPeriod);
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+        return Error::NONE;
+    }
+
+    Error setActiveConfigWithConstraints(
+            Display display, Config config,
+            const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+            VsyncPeriodChangeTimeline* timeline) override {
+        if (!mDispatch.setActiveConfigWithConstraints) {
+            return Error::UNSUPPORTED;
+        }
+
+        hwc_vsync_period_change_constraints_t vsync_period_change_constraints;
+        vsync_period_change_constraints.desiredTimeNanos =
+                vsyncPeriodChangeConstraints.desiredTimeNanos;
+        vsync_period_change_constraints.seamlessRequired =
+                vsyncPeriodChangeConstraints.seamlessRequired;
+
+        hwc_vsync_period_change_timeline_t out_timeline;
+        int32_t error = mDispatch.setActiveConfigWithConstraints(
+                mDevice, display, config, &vsync_period_change_constraints, &out_timeline);
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+        timeline->newVsyncAppliedTimeNanos = out_timeline.newVsyncAppliedTimeNanos;
+        timeline->refreshRequired = out_timeline.refreshRequired;
+        timeline->refreshTimeNanos = out_timeline.refreshTimeNanos;
+        return Error::NONE;
+    }
+
+    Error setAutoLowLatencyMode(Display display, bool on) override {
+        if (!mDispatch.setAutoLowLatencyMode) {
+            return Error::UNSUPPORTED;
+        }
+
+        int32_t error = mDispatch.setAutoLowLatencyMode(mDevice, display, on);
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+        return Error::NONE;
+    }
+
+    Error getSupportedContentTypes(
+            Display display,
+            std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override {
+        if (!mDispatch.getSupportedContentTypes) {
+            return Error::UNSUPPORTED;
+        }
+
+        uint32_t count = 0;
+        int32_t error = mDispatch.getSupportedContentTypes(mDevice, display, &count, nullptr);
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+
+        outSupportedContentTypes->resize(count);
+
+        error = mDispatch.getSupportedContentTypes(
+                mDevice, display, &count,
+                reinterpret_cast<std::underlying_type<IComposerClient::ContentType>::type*>(
+                        outSupportedContentTypes->data()));
+        if (error != HWC2_ERROR_NONE) {
+            *outSupportedContentTypes = std::vector<IComposerClient::ContentType>();
+            return static_cast<Error>(error);
+        }
+        return Error::NONE;
+    }
+
+    Error setContentType(Display display, IComposerClient::ContentType contentType) override {
+        if (!mDispatch.setContentType) {
+            return Error::UNSUPPORTED;
+        }
+
+        int32_t error =
+                mDispatch.setContentType(mDevice, display, static_cast<int32_t>(contentType));
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+        return Error::NONE;
+    }
+
+    Error validateDisplay_2_4(
+            Display display, std::vector<Layer>* outChangedLayers,
+            std::vector<IComposerClient::Composition>* outCompositionTypes,
+            uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+            std::vector<uint32_t>* outRequestMasks,
+            IComposerClient::ClientTargetProperty* outClientTargetProperty) override {
+        auto err = static_cast<Error>(BaseType2_1::validateDisplay(
+                display, outChangedLayers, outCompositionTypes, outDisplayRequestMask,
+                outRequestedLayers, outRequestMasks));
+        if (err != Error::NONE) {
+            return err;
+        }
+
+        if (mDispatch.getClientTargetProperty) {
+            hwc_client_target_property_t clientTargetProperty;
+            err = static_cast<Error>(
+                    mDispatch.getClientTargetProperty(mDevice, display, &clientTargetProperty));
+            outClientTargetProperty->pixelFormat =
+                    static_cast<PixelFormat>(clientTargetProperty.pixelFormat);
+            outClientTargetProperty->dataspace =
+                    static_cast<Dataspace>(clientTargetProperty.dataspace);
+        }
+
+        return err;
+    }
+
+    Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+                                  bool mandatory, const std::vector<uint8_t>& value) override {
+        if (!mDispatch.setLayerGenericMetadata) {
+            return Error::UNSUPPORTED;
+        }
+
+        if (key.size() > std::numeric_limits<uint32_t>::max()) {
+            return Error::BAD_PARAMETER;
+        }
+
+        if (value.size() > std::numeric_limits<uint32_t>::max()) {
+            return Error::BAD_PARAMETER;
+        }
+
+        int32_t error = mDispatch.setLayerGenericMetadata(
+                mDevice, display, layer, static_cast<uint32_t>(key.size()), key.c_str(), mandatory,
+                static_cast<uint32_t>(value.size()), value.data());
+        return static_cast<Error>(error);
+    }
+
+    Error getLayerGenericMetadataKeys(
+            std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override {
+        if (!mDispatch.getLayerGenericMetadataKey) {
+            return Error::UNSUPPORTED;
+        }
+
+        std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+
+        uint32_t index = 0;
+        uint32_t keyLength = 0;
+        while (true) {
+            mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, nullptr, nullptr);
+            if (keyLength == 0) {
+                break;
+            }
+
+            IComposerClient::LayerGenericMetadataKey key;
+            std::string keyName;
+            keyName.resize(keyLength);
+            mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, keyName.data(),
+                                                 &key.mandatory);
+            key.name = keyName;
+            keys.emplace_back(std::move(key));
+
+            // Only attempt to load the first 100 keys to avoid an infinite loop
+            // if something goes wrong
+            if (++index > 100) {
+                break;
+            }
+        }
+
+        *outKeys = std::move(keys);
+        return Error::NONE;
+    }
+
+  protected:
+    bool initDispatch() override {
+        if (!BaseType2_3::initDispatch()) {
+            return false;
+        }
+
+        if (!BaseType2_1::initDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD,
+                                       &mDispatch.getDisplayVsyncPeriod) ||
+            !BaseType2_1::initDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS,
+                                       &mDispatch.setActiveConfigWithConstraints)) {
+            return false;
+        }
+
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CONNECTION_TYPE,
+                                   &mDispatch.getDisplayConnectionType);
+        this->initOptionalDispatch(HWC2_FUNCTION_SET_AUTO_LOW_LATENCY_MODE,
+                                   &mDispatch.setAutoLowLatencyMode);
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_CONTENT_TYPES,
+                                   &mDispatch.getSupportedContentTypes);
+        this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType);
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_PROPERTY,
+                                   &mDispatch.getClientTargetProperty);
+        this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_GENERIC_METADATA,
+                                   &mDispatch.setLayerGenericMetadata);
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_LAYER_GENERIC_METADATA_KEY,
+                                   &mDispatch.getLayerGenericMetadataKey);
+
+        return true;
+    }
+
+    static void hotplugHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+                            int32_t connected) {
+        auto hal = static_cast<HwcHalImpl*>(callbackData);
+        hal->mEventCallback_2_4->onHotplug(display,
+                                           static_cast<IComposerCallback::Connection>(connected));
+    }
+
+    static void refreshHook(hwc2_callback_data_t callbackData, hwc2_display_t display) {
+        auto hal = static_cast<HwcHalImpl*>(callbackData);
+        hal->mEventCallback_2_4->onRefresh(display);
+    }
+
+    static void vsyncHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+                          int64_t timestamp) {
+        auto hal = static_cast<HwcHalImpl*>(callbackData);
+        hal->mEventCallback_2_4->onVsync(display, timestamp);
+    }
+
+    static void vsync_2_4_Hook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+                               int64_t timestamp, hwc2_vsync_period_t vsyncPeriodNanos) {
+        auto hal = static_cast<HwcHalImpl*>(callbackData);
+        hal->mEventCallback_2_4->onVsync_2_4(display, timestamp, vsyncPeriodNanos);
+    }
+
+    static void vsyncPeriodTimingChangedHook(hwc2_callback_data_t callbackData,
+                                             hwc2_display_t display,
+                                             hwc_vsync_period_change_timeline_t* updated_timeline) {
+        auto hal = static_cast<HwcHalImpl*>(callbackData);
+        VsyncPeriodChangeTimeline timeline;
+        timeline.newVsyncAppliedTimeNanos = updated_timeline->newVsyncAppliedTimeNanos;
+        timeline.refreshRequired = updated_timeline->refreshRequired;
+        timeline.refreshTimeNanos = updated_timeline->refreshTimeNanos;
+        hal->mEventCallback_2_4->onVsyncPeriodTimingChanged(display, timeline);
+    }
+
+    static void seamlessPossibleHook(hwc2_callback_data_t callbackData, hwc2_display_t display) {
+        auto hal = static_cast<HwcHalImpl*>(callbackData);
+        hal->mEventCallback_2_4->onSeamlessPossible(display);
+    }
+
+  private:
+    struct {
+        HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType;
+        HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod;
+        HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS setActiveConfigWithConstraints;
+        HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE setAutoLowLatencyMode;
+        HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes;
+        HWC2_PFN_SET_CONTENT_TYPE setContentType;
+        HWC2_PFN_GET_CLIENT_TARGET_PROPERTY getClientTargetProperty;
+        HWC2_PFN_SET_LAYER_GENERIC_METADATA setLayerGenericMetadata;
+        HWC2_PFN_GET_LAYER_GENERIC_METADATA_KEY getLayerGenericMetadataKey;
+    } mDispatch = {};
+
+    hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr;
+
+    using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
+    using BaseType2_3 = V2_3::passthrough::detail::HwcHalImpl<Hal>;
+    using BaseType2_1::mDevice;
+};
+
+}  // namespace detail
+
+using HwcHal = detail::HwcHalImpl<hal::ComposerHal>;
+
+}  // namespace passthrough
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h
new file mode 100644
index 0000000..a7cc588
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcLoader.h included without LOG_TAG"
+#endif
+
+#include <composer-hal/2.4/Composer.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-passthrough/2.3/HwcLoader.h>
+#include <composer-passthrough/2.4/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace passthrough {
+
+class HwcLoader : public V2_3::passthrough::HwcLoader {
+  public:
+    static IComposer* load() {
+        const hw_module_t* module = loadModule();
+        if (!module) {
+            return nullptr;
+        }
+
+        auto hal = createHalWithAdapter(module);
+        if (!hal) {
+            return nullptr;
+        }
+
+        return createComposer(std::move(hal)).release();
+    }
+
+    // create a ComposerHal instance
+    static std::unique_ptr<hal::ComposerHal> createHal(const hw_module_t* module) {
+        auto hal = std::make_unique<HwcHal>();
+        return hal->initWithModule(module) ? std::move(hal) : nullptr;
+    }
+
+    // create a ComposerHal instance, insert an adapter if necessary
+    static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) {
+        bool adapted;
+        hwc2_device_t* device = openDeviceWithAdapter(module, &adapted);
+        if (!device) {
+            return nullptr;
+        }
+        auto hal = std::make_unique<HwcHal>();
+        return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr;
+    }
+
+    // create an IComposer instance
+    static std::unique_ptr<IComposer> createComposer(std::unique_ptr<hal::ComposerHal> hal) {
+        return hal::Composer::create(std::move(hal));
+    }
+};
+
+}  // namespace passthrough
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
new file mode 100644
index 0000000..fc13c2a
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -0,0 +1,45 @@
+//
+// 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.
+//
+
+cc_library_static {
+    name: "android.hardware.graphics.composer@2.4-vts",
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "ComposerVts.cpp",
+        "GraphicsComposerCallback.cpp",
+        "TestCommandReader.cpp",
+    ],
+    static_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3-vts",
+        "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.4",
+        "libgtest",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.3-command-buffer",
+        "android.hardware.graphics.composer@2.4-command-buffer",
+    ],
+    cflags: [
+        "-O0",
+        "-g",
+        "-DLOG_TAG=\"ComposerVts\"",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
new file mode 100644
index 0000000..b3f3374
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+
+#include <composer-vts/2.4/ComposerVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+
+using V2_4::Error;
+
+Composer::Composer(const sp<IComposer>& composer)
+    : V2_3::vts::Composer(composer), mComposer(composer) {}
+
+std::unique_ptr<ComposerClient> Composer::createClient() {
+    std::unique_ptr<ComposerClient> client;
+    mComposer->createClient_2_4([&client](const auto& tmpError, const auto& tmpClient) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+        client = std::make_unique<ComposerClient>(tmpClient);
+    });
+
+    return client;
+}
+
+sp<IComposerClient> ComposerClient::getRaw() const {
+    return mClient;
+}
+
+Error ComposerClient::getDisplayCapabilities(
+        Display display, std::vector<IComposerClient::DisplayCapability>* outCapabilities) {
+    Error error = Error::NONE;
+    mClient->getDisplayCapabilities_2_4(display,
+                                        [&](const auto& tmpError, const auto& tmpCapabilities) {
+                                            error = tmpError;
+                                            *outCapabilities = tmpCapabilities;
+                                        });
+    return error;
+}
+
+Error ComposerClient::getDisplayConnectionType(Display display,
+                                               IComposerClient::DisplayConnectionType* outType) {
+    Error error = Error::NONE;
+    mClient->getDisplayConnectionType(display, [&](const auto& tmpError, const auto& tmpType) {
+        error = tmpError;
+        *outType = tmpType;
+    });
+    return error;
+}
+
+int32_t ComposerClient::getDisplayAttribute_2_4(
+        android::hardware::graphics::composer::V2_1::Display display,
+        android::hardware::graphics::composer::V2_1::Config config,
+        IComposerClient::Attribute attribute) {
+    int32_t value = 0;
+    mClient->getDisplayAttribute_2_4(
+            display, config, attribute, [&](const auto& tmpError, const auto& tmpValue) {
+                ASSERT_EQ(Error::NONE, tmpError) << "failed to get display attribute";
+                value = tmpValue;
+            });
+
+    return value;
+}
+
+void ComposerClient::registerCallback_2_4(const sp<IComposerCallback>& callback) {
+    mClient->registerCallback_2_4(callback);
+}
+
+Error ComposerClient::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) {
+    Error error = Error::NONE;
+    mClient->getDisplayVsyncPeriod(display, [&](const auto& tmpError, const auto& tmpVsyncPeriod) {
+        error = tmpError;
+        *outVsyncPeriod = tmpVsyncPeriod;
+    });
+    return error;
+}
+
+Error ComposerClient::setActiveConfigWithConstraints(
+        Display display, Config config,
+        const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+        VsyncPeriodChangeTimeline* timeline) {
+    Error error = Error::NONE;
+    mClient->setActiveConfigWithConstraints(display, config, vsyncPeriodChangeConstraints,
+                                            [&](const auto& tmpError, const auto& tmpTimeline) {
+                                                error = tmpError;
+                                                *timeline = tmpTimeline;
+                                            });
+    return error;
+}
+
+Error ComposerClient::setAutoLowLatencyMode(Display display, bool on) {
+    return mClient->setAutoLowLatencyMode(display, on);
+}
+
+Error ComposerClient::getSupportedContentTypes(
+        Display display, std::vector<IComposerClient::ContentType>* outSupportedContentTypes) {
+    Error error = Error::NONE;
+    mClient->getSupportedContentTypes(
+            display, [&](const auto& tmpError, const auto& tmpSupportedContentTypes) {
+                error = tmpError;
+                *outSupportedContentTypes = tmpSupportedContentTypes;
+            });
+    return error;
+}
+
+Error ComposerClient::setContentType(Display display, IComposerClient::ContentType contentType) {
+    return mClient->setContentType(display, contentType);
+}
+
+Error ComposerClient::getLayerGenericMetadataKeys(
+        std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) {
+    Error error = Error::NONE;
+    mClient->getLayerGenericMetadataKeys([&](const auto tmpError, const auto& tmpKeys) {
+        error = tmpError;
+        *outKeys = tmpKeys;
+    });
+    return error;
+}
+
+void ComposerClient::execute(TestCommandReader* reader, CommandWriterBase* writer) {
+    bool queueChanged = false;
+    uint32_t commandLength = 0;
+    hidl_vec<hidl_handle> commandHandles;
+    ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
+
+    if (queueChanged) {
+        auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor());
+        ASSERT_EQ(V2_1::Error::NONE, ret);
+    }
+
+    mClient->executeCommands_2_3(
+            commandLength, commandHandles,
+            [&](const auto& tmpError, const auto& tmpOutQueueChanged, const auto& tmpOutLength,
+                const auto& tmpOutHandles) {
+                ASSERT_EQ(V2_1::Error::NONE, tmpError);
+
+                if (tmpOutQueueChanged) {
+                    mClient->getOutputCommandQueue(
+                            [&](const auto& tmpError, const auto& tmpDescriptor) {
+                                ASSERT_EQ(V2_3::Error::NONE, tmpError);
+                                reader->setMQDescriptor(tmpDescriptor);
+                            });
+                }
+
+                ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
+                reader->parse();
+            });
+    reader->reset();
+    writer->reset();
+}
+
+}  // namespace vts
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp
new file mode 100644
index 0000000..c9366a8
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <composer-vts/2.4/GraphicsComposerCallback.h>
+
+namespace android::hardware::graphics::composer::V2_4::vts {
+
+void GraphicsComposerCallback::setVsyncAllowed(bool allowed) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mVsyncAllowed = allowed;
+}
+
+std::vector<Display> GraphicsComposerCallback::getDisplays() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return std::vector<Display>(mDisplays.begin(), mDisplays.end());
+}
+
+int32_t GraphicsComposerCallback::getInvalidHotplugCount() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mInvalidHotplugCount;
+}
+
+int32_t GraphicsComposerCallback::getInvalidRefreshCount() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mInvalidRefreshCount;
+}
+
+int32_t GraphicsComposerCallback::getInvalidVsyncCount() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mInvalidVsyncCount;
+}
+
+int32_t GraphicsComposerCallback::getInvalidVsync_2_4Count() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mInvalidVsync_2_4Count;
+}
+
+int32_t GraphicsComposerCallback::getInvalidVsyncPeriodChangeCount() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mInvalidVsyncPeriodChangeCount;
+}
+
+int32_t GraphicsComposerCallback::getInvalidSeamlessPossibleCount() const {
+    std::lock_guard<std::mutex> lock(mMutex);
+    return mInvalidSeamlessPossibleCount;
+}
+
+std::optional<VsyncPeriodChangeTimeline>
+GraphicsComposerCallback::takeLastVsyncPeriodChangeTimeline() {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    std::optional<VsyncPeriodChangeTimeline> ret;
+    ret.swap(mTimeline);
+
+    return ret;
+}
+
+Return<void> GraphicsComposerCallback::onHotplug(Display display, Connection connection) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    if (connection == Connection::CONNECTED) {
+        if (!mDisplays.insert(display).second) {
+            mInvalidHotplugCount++;
+        }
+    } else if (connection == Connection::DISCONNECTED) {
+        if (!mDisplays.erase(display)) {
+            mInvalidHotplugCount++;
+        }
+    }
+
+    return Void();
+}
+
+Return<void> GraphicsComposerCallback::onRefresh(Display display) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    if (mDisplays.count(display) == 0) {
+        mInvalidRefreshCount++;
+    }
+
+    return Void();
+}
+
+Return<void> GraphicsComposerCallback::onVsync(Display, int64_t) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    // On composer 2.4, onVsync is not expected at all
+    mInvalidVsyncCount++;
+
+    return Void();
+}
+
+Return<void> GraphicsComposerCallback::onVsync_2_4(Display display, int64_t, VsyncPeriodNanos) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    if (!mVsyncAllowed || mDisplays.count(display) == 0) {
+        mInvalidVsync_2_4Count++;
+    }
+
+    return Void();
+}
+
+Return<void> GraphicsComposerCallback::onVsyncPeriodTimingChanged(
+        Display display, const VsyncPeriodChangeTimeline& updatedTimeline) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    if (mDisplays.count(display) == 0) {
+        mInvalidVsyncPeriodChangeCount++;
+    }
+
+    mTimeline = updatedTimeline;
+
+    return Void();
+}
+
+Return<void> GraphicsComposerCallback::onSeamlessPossible(Display) {
+    std::lock_guard<std::mutex> lock(mMutex);
+
+    mInvalidSeamlessPossibleCount++;
+
+    return Void();
+}
+
+}  // namespace android::hardware::graphics::composer::V2_4::vts
\ No newline at end of file
diff --git a/graphics/composer/2.4/utils/vts/TestCommandReader.cpp b/graphics/composer/2.4/utils/vts/TestCommandReader.cpp
new file mode 100644
index 0000000..a1ca628
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/TestCommandReader.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <composer-vts/2.4/TestCommandReader.h>
+
+#include <gtest/gtest.h>
+
+namespace android::hardware::graphics::composer::V2_4::vts {
+
+void TestCommandReader::parseSingleCommand(int32_t commandRaw, uint16_t length) {
+    IComposerClient::Command command = static_cast<IComposerClient::Command>(commandRaw);
+
+    switch (command) {
+        case IComposerClient::Command::SET_CLIENT_TARGET_PROPERTY:
+            ASSERT_EQ(2, length);
+            read();
+            close(readFence());
+            break;
+        default:
+            return android::hardware::graphics::composer::V2_1::vts::TestCommandReader::
+                    parseSingleCommand(commandRaw, length);
+    }
+}
+
+}  // namespace android::hardware::graphics::composer::V2_4::vts
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
new file mode 100644
index 0000000..28e17b4
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-vts/2.3/ComposerVts.h>
+#include <composer-vts/2.4/TestCommandReader.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Config;
+using V2_1::Display;
+using V2_4::Error;
+using V2_4::IComposer;
+using V2_4::IComposerClient;
+using V2_4::VsyncPeriodNanos;
+
+class ComposerClient;
+
+// A wrapper to IComposer.
+class Composer : public V2_3::vts::Composer {
+  public:
+    Composer();
+    explicit Composer(const std::string& name);
+    explicit Composer(const sp<IComposer>& composer);
+
+    std::unique_ptr<ComposerClient> createClient();
+
+  private:
+    const sp<IComposer> mComposer;
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient : public V2_3::vts::ComposerClient {
+  public:
+    explicit ComposerClient(const sp<IComposerClient>& client)
+        : V2_3::vts::ComposerClient(client), mClient(client) {}
+
+    sp<IComposerClient> getRaw() const;
+
+    Error getDisplayCapabilities(
+            Display display,
+            std::vector<IComposerClient::DisplayCapability>* outDisplayCapabilities);
+
+    Error getDisplayConnectionType(Display display,
+                                   IComposerClient::DisplayConnectionType* outType);
+
+    int32_t getDisplayAttribute_2_4(Display display, Config config,
+                                    IComposerClient::Attribute attribute);
+
+    void registerCallback_2_4(const sp<IComposerCallback>& callback);
+
+    Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriods);
+
+    Error setActiveConfigWithConstraints(
+            Display display, Config config,
+            const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+            VsyncPeriodChangeTimeline* timeline);
+
+    Error setAutoLowLatencyMode(Display display, bool on);
+
+    Error getSupportedContentTypes(
+            Display display, std::vector<IComposerClient::ContentType>* outSupportedContentTypes);
+
+    Error setContentType(Display display, IComposerClient::ContentType contentType);
+
+    void execute(TestCommandReader* reader, CommandWriterBase* writer);
+
+    Error getLayerGenericMetadataKeys(
+            std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys);
+
+  private:
+    const sp<IComposerClient> mClient;
+};
+
+}  // namespace vts
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h
new file mode 100644
index 0000000..f4e23ae
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android/hardware/graphics/composer/2.4/IComposerCallback.h>
+
+#include <mutex>
+#include <unordered_set>
+
+namespace android::hardware::graphics::composer::V2_4::vts {
+
+using Display = V2_1::Display;
+
+// IComposerCallback to be installed with IComposerClient::registerCallback.
+class GraphicsComposerCallback : public IComposerCallback {
+  public:
+    void setVsyncAllowed(bool allowed);
+
+    std::vector<Display> getDisplays() const;
+
+    int32_t getInvalidHotplugCount() const;
+
+    int32_t getInvalidRefreshCount() const;
+
+    int32_t getInvalidVsyncCount() const;
+
+    int32_t getInvalidVsync_2_4Count() const;
+
+    int32_t getInvalidVsyncPeriodChangeCount() const;
+
+    int32_t getInvalidSeamlessPossibleCount() const;
+
+    std::optional<VsyncPeriodChangeTimeline> takeLastVsyncPeriodChangeTimeline();
+
+  private:
+    Return<void> onHotplug(Display display, Connection connection) override;
+    Return<void> onRefresh(Display display) override;
+    Return<void> onVsync(Display display, int64_t) override;
+    Return<void> onVsync_2_4(Display display, int64_t, VsyncPeriodNanos vsyncPeriodNanos) override;
+    Return<void> onVsyncPeriodTimingChanged(
+            Display display, const VsyncPeriodChangeTimeline& updatedTimeline) override;
+    Return<void> onSeamlessPossible(Display display) override;
+
+    mutable std::mutex mMutex;
+    // the set of all currently connected displays
+    std::unordered_set<Display> mDisplays;
+    // true only when vsync is enabled
+    bool mVsyncAllowed = true;
+
+    std::optional<VsyncPeriodChangeTimeline> mTimeline;
+
+    // track invalid callbacks
+    int32_t mInvalidHotplugCount = 0;
+    int32_t mInvalidRefreshCount = 0;
+    int32_t mInvalidVsyncCount = 0;
+    int32_t mInvalidVsync_2_4Count = 0;
+    int32_t mInvalidVsyncPeriodChangeCount = 0;
+    int32_t mInvalidSeamlessPossibleCount = 0;
+};
+
+}  // namespace android::hardware::graphics::composer::V2_4::vts
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/TestCommandReader.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/TestCommandReader.h
new file mode 100644
index 0000000..5736fa6
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/TestCommandReader.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+
+namespace android::hardware::graphics::composer::V2_4::vts {
+
+// A command parser that checks that no error nor unexpected commands are
+// returned.
+class TestCommandReader
+    : public android::hardware::graphics::composer::V2_1::vts::TestCommandReader {
+  protected:
+    void parseSingleCommand(int32_t commandRaw, uint16_t length) override;
+};
+
+}  // namespace android::hardware::graphics::composer::V2_4::vts
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
new file mode 100644
index 0000000..88b6114
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -0,0 +1,56 @@
+//
+// 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.
+//
+
+cc_test {
+    name: "VtsHalGraphicsComposerV2_4TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"],
+
+    // TODO(b/64437680): Assume these libs are always available on the device.
+    shared_libs: [
+        "libfmq",
+        "libsync",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.1-vts",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.2-vts",
+        "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.3-vts",
+        "android.hardware.graphics.composer@2.4",
+        "android.hardware.graphics.composer@2.4-vts",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1-vts",
+        "android.hardware.graphics.mapper@3.0-vts",
+        "android.hardware.graphics.mapper@4.0-vts",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.3-command-buffer",
+        "android.hardware.graphics.composer@2.4-command-buffer",
+    ],
+    disable_framework: true,
+    test_suites: ["general-tests", "vts-core"],
+}
diff --git a/graphics/composer/2.4/vts/functional/OWNERS b/graphics/composer/2.4/vts/functional/OWNERS
new file mode 100644
index 0000000..b3ea6be
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/OWNERS
@@ -0,0 +1,8 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
new file mode 100644
index 0000000..f0de4f7
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -0,0 +1,685 @@
+/*
+ * 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 "graphics_composer_hidl_hal_test@2.4"
+
+#include <algorithm>
+#include <regex>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <composer-vts/2.4/ComposerVts.h>
+#include <composer-vts/2.4/GraphicsComposerCallback.h>
+#include <composer-vts/2.4/TestCommandReader.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <mapper-vts/2.0/MapperVts.h>
+#include <mapper-vts/3.0/MapperVts.h>
+#include <mapper-vts/4.0/MapperVts.h>
+#include <utils/Timers.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+namespace {
+
+using namespace std::chrono_literals;
+
+using common::V1_0::BufferUsage;
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::PixelFormat;
+using mapper::V2_0::IMapper;
+using V2_1::Layer;
+using V2_2::Transform;
+using V2_2::vts::Gralloc;
+
+using ContentType = IComposerClient::ContentType;
+using DisplayCapability = IComposerClient::DisplayCapability;
+
+class GraphicsComposerHidlTest : public ::testing::TestWithParam<std::string> {
+  protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposer = std::make_unique<Composer>(IComposer::getService(GetParam())));
+        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+
+        mComposerCallback = new GraphicsComposerCallback;
+        mComposerClient->registerCallback_2_4(mComposerCallback);
+
+        // assume the first display is primary and is never removed
+        mPrimaryDisplay = waitForFirstDisplay();
+
+        mInvalidDisplayId = GetInvalidDisplayId();
+
+        // explicitly disable vsync
+        mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+        mComposerCallback->setVsyncAllowed(false);
+
+        mWriter = std::make_unique<CommandWriterBase>(1024);
+        mReader = std::make_unique<TestCommandReader>();
+    }
+
+    void TearDown() override {
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_EQ(0, mReader->mCompositionChanges.size());
+        if (mComposerCallback != nullptr) {
+            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsync_2_4Count());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncPeriodChangeCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidSeamlessPossibleCount());
+        }
+    }
+
+    // returns an invalid display id (one that has not been registered to a
+    // display.  Currently assuming that a device will never have close to
+    // std::numeric_limit<uint64_t>::max() displays registered while running tests
+    Display GetInvalidDisplayId() {
+        std::vector<Display> validDisplays = mComposerCallback->getDisplays();
+        uint64_t id = std::numeric_limits<uint64_t>::max();
+        while (id > 0) {
+            if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) {
+                return id;
+            }
+            id--;
+        }
+
+        return 0;
+    }
+
+    // returns an invalid config id (one that has not been registered to a
+    // display).  Currently assuming that a device will never have close to
+    // std::numeric_limit<uint64_t>::max() configs registered while running tests
+    Display GetInvalidConfigId(Display display) {
+        std::vector<Config> validConfigs = mComposerClient->getDisplayConfigs(display);
+        uint64_t id = std::numeric_limits<uint64_t>::max();
+        while (id > 0) {
+            if (std::find(validConfigs.begin(), validConfigs.end(), id) == validConfigs.end()) {
+                return id;
+            }
+            id--;
+        }
+
+        return 0;
+    }
+
+    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+    void forEachTwoConfigs(Display display, std::function<void(Config, Config)> func) {
+        const auto displayConfigs = mComposerClient->getDisplayConfigs(display);
+        for (const Config config1 : displayConfigs) {
+            for (const Config config2 : displayConfigs) {
+                if (config1 != config2) {
+                    func(config1, config2);
+                }
+            }
+        }
+    }
+
+    // use the slot count usually set by SF
+    static constexpr uint32_t kBufferSlotCount = 64;
+
+    void Test_setContentType(const ContentType& contentType, const char* contentTypeStr);
+    void Test_setContentTypeForDisplay(const Display& display,
+                                       const std::vector<ContentType>& capabilities,
+                                       const ContentType& contentType, const char* contentTypeStr);
+
+    std::unique_ptr<Composer> mComposer;
+    std::unique_ptr<ComposerClient> mComposerClient;
+    sp<GraphicsComposerCallback> mComposerCallback;
+    // the first display and is assumed never to be removed
+    Display mPrimaryDisplay;
+    Display mInvalidDisplayId;
+    std::unique_ptr<CommandWriterBase> mWriter;
+    std::unique_ptr<TestCommandReader> mReader;
+
+  private:
+    Display waitForFirstDisplay() {
+        while (true) {
+            std::vector<Display> displays = mComposerCallback->getDisplays();
+            if (displays.empty()) {
+                usleep(5 * 1000);
+                continue;
+            }
+
+            return displays[0];
+        }
+    }
+};
+
+// Tests for IComposerClient::Command.
+class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
+  protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
+
+        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+
+        const Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay);
+        mDisplayWidth = mComposerClient->getDisplayAttribute_2_4(mPrimaryDisplay, activeConfig,
+                                                                 IComposerClient::Attribute::WIDTH);
+        mDisplayHeight = mComposerClient->getDisplayAttribute_2_4(
+                mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT);
+
+        mWriter = std::make_unique<CommandWriterBase>(1024);
+        mReader = std::make_unique<TestCommandReader>();
+    }
+
+    void TearDown() override {
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
+    }
+
+    const native_handle_t* allocate() {
+        return mGralloc->allocate(
+                /*width*/ 64, /*height*/ 64, /*layerCount*/ 1,
+                static_cast<common::V1_1::PixelFormat>(PixelFormat::RGBA_8888),
+                static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN));
+    }
+
+    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+    struct TestParameters {
+        nsecs_t delayForChange;
+        bool refreshMiss;
+    };
+
+    void Test_setActiveConfigWithConstraints(const TestParameters& params);
+
+    void sendRefreshFrame(const VsyncPeriodChangeTimeline*);
+
+    void waitForVsyncPeriodChange(Display display, const VsyncPeriodChangeTimeline& timeline,
+                                  int64_t desiredTimeNanos, int64_t oldPeriodNanos,
+                                  int64_t newPeriodNanos);
+
+    std::unique_ptr<CommandWriterBase> mWriter;
+    std::unique_ptr<TestCommandReader> mReader;
+    int32_t mDisplayWidth;
+    int32_t mDisplayHeight;
+
+  private:
+    std::unique_ptr<Gralloc> mGralloc;
+};
+
+TEST_P(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
+    std::vector<IComposerClient::DisplayCapability> capabilities;
+    const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities);
+    EXPECT_EQ(Error::BAD_DISPLAY, error);
+}
+
+TEST_P(GraphicsComposerHidlTest, getDisplayCapabilities) {
+    for (Display display : mComposerCallback->getDisplays()) {
+        std::vector<IComposerClient::DisplayCapability> capabilities;
+        EXPECT_EQ(Error::NONE, mComposerClient->getDisplayCapabilities(display, &capabilities));
+    }
+}
+
+TEST_P(GraphicsComposerHidlTest, getDisplayConnectionType) {
+    IComposerClient::DisplayConnectionType type;
+    EXPECT_EQ(Error::BAD_DISPLAY,
+              mComposerClient->getDisplayConnectionType(mInvalidDisplayId, &type));
+
+    for (Display display : mComposerCallback->getDisplays()) {
+        EXPECT_EQ(Error::NONE, mComposerClient->getDisplayConnectionType(display, &type));
+    }
+}
+
+TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute_2_4) {
+    std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+    for (auto config : configs) {
+        const std::array<IComposerClient::Attribute, 4> requiredAttributes = {{
+                IComposerClient::Attribute::WIDTH,
+                IComposerClient::Attribute::HEIGHT,
+                IComposerClient::Attribute::VSYNC_PERIOD,
+                IComposerClient::Attribute::CONFIG_GROUP,
+        }};
+        for (auto attribute : requiredAttributes) {
+            mComposerClient->getRaw()->getDisplayAttribute_2_4(
+                    mPrimaryDisplay, config, attribute,
+                    [&](const auto& tmpError, const auto& value) {
+                        EXPECT_EQ(Error::NONE, tmpError);
+                        EXPECT_NE(-1, value);
+                    });
+        }
+
+        const std::array<IComposerClient::Attribute, 2> optionalAttributes = {{
+                IComposerClient::Attribute::DPI_X,
+                IComposerClient::Attribute::DPI_Y,
+        }};
+        for (auto attribute : optionalAttributes) {
+            mComposerClient->getRaw()->getDisplayAttribute_2_4(
+                    mPrimaryDisplay, config, attribute, [&](const auto& tmpError, const auto&) {
+                        EXPECT_TRUE(tmpError == Error::NONE || tmpError == Error::UNSUPPORTED);
+                    });
+        }
+    }
+}
+
+TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) {
+    VsyncPeriodNanos vsyncPeriodNanos;
+    EXPECT_EQ(Error::BAD_DISPLAY,
+              mComposerClient->getDisplayVsyncPeriod(mInvalidDisplayId, &vsyncPeriodNanos));
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, getDisplayVsyncPeriod) {
+    for (Display display : mComposerCallback->getDisplays()) {
+        for (Config config : mComposerClient->getDisplayConfigs(display)) {
+            VsyncPeriodNanos expectedVsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4(
+                    display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+
+            VsyncPeriodChangeTimeline timeline;
+            IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+            constraints.desiredTimeNanos = systemTime();
+            constraints.seamlessRequired = false;
+            EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints(
+                                           display, config, constraints, &timeline));
+
+            if (timeline.refreshRequired) {
+                sendRefreshFrame(&timeline);
+            }
+            waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, 0,
+                                     expectedVsyncPeriodNanos);
+
+            VsyncPeriodNanos vsyncPeriodNanos;
+            int retryCount = 100;
+            do {
+                std::this_thread::sleep_for(10ms);
+                vsyncPeriodNanos = 0;
+                EXPECT_EQ(Error::NONE,
+                          mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+                --retryCount;
+            } while (vsyncPeriodNanos != expectedVsyncPeriodNanos && retryCount > 0);
+
+            EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos);
+
+            // Make sure that the vsync period stays the same if the active config is not changed.
+            auto timeout = 1ms;
+            for (int i = 0; i < 10; i++) {
+                std::this_thread::sleep_for(timeout);
+                timeout *= 2;
+                vsyncPeriodNanos = 0;
+                EXPECT_EQ(Error::NONE,
+                          mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+                EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos);
+            }
+        }
+    }
+}
+
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_BadDisplay) {
+    VsyncPeriodChangeTimeline timeline;
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime();
+
+    EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setActiveConfigWithConstraints(
+                                          mInvalidDisplayId, Config(0), constraints, &timeline));
+}
+
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_BadConfig) {
+    VsyncPeriodChangeTimeline timeline;
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime();
+
+    for (Display display : mComposerCallback->getDisplays()) {
+        Config invalidConfigId = GetInvalidConfigId(display);
+        EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->setActiveConfigWithConstraints(
+                                             display, invalidConfigId, constraints, &timeline));
+    }
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_SeamlessNotAllowed) {
+    VsyncPeriodChangeTimeline timeline;
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = true;
+    constraints.desiredTimeNanos = systemTime();
+
+    for (Display display : mComposerCallback->getDisplays()) {
+        forEachTwoConfigs(display, [&](Config config1, Config config2) {
+            const auto configGroup1 = mComposerClient->getDisplayAttribute_2_4(
+                    display, config1, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
+            const auto configGroup2 = mComposerClient->getDisplayAttribute_2_4(
+                    display, config2, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
+            if (configGroup1 != configGroup2) {
+                mComposerClient->setActiveConfig(display, config1);
+                sendRefreshFrame(nullptr);
+                EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED,
+                          mComposerClient->setActiveConfigWithConstraints(display, config2,
+                                                                          constraints, &timeline));
+            }
+        });
+    }
+}
+
+static inline auto toTimePoint(nsecs_t time) {
+    return std::chrono::time_point<std::chrono::steady_clock>(std::chrono::nanoseconds(time));
+}
+
+void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTimeline* timeline) {
+    if (timeline != nullptr) {
+        // Refresh time should be before newVsyncAppliedTimeNanos
+        EXPECT_LT(timeline->refreshTimeNanos, timeline->newVsyncAppliedTimeNanos);
+
+        std::this_thread::sleep_until(toTimePoint(timeline->refreshTimeNanos));
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mComposerClient->setPowerMode(mPrimaryDisplay, V2_1::IComposerClient::PowerMode::ON);
+    mComposerClient->setColorMode_2_3(mPrimaryDisplay, ColorMode::NATIVE,
+                                      RenderIntent::COLORIMETRIC);
+
+    auto handle = allocate();
+    ASSERT_NE(nullptr, handle);
+
+    IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight};
+
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+    mWriter->selectLayer(layer);
+    mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+    mWriter->setLayerDisplayFrame(displayFrame);
+    mWriter->setLayerPlaneAlpha(1);
+    mWriter->setLayerSourceCrop({0, 0, (float)mDisplayWidth, (float)mDisplayHeight});
+    mWriter->setLayerTransform(static_cast<Transform>(0));
+    mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, displayFrame));
+    mWriter->setLayerZOrder(10);
+    mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE);
+    mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, displayFrame));
+    mWriter->setLayerBuffer(0, handle, -1);
+    mWriter->setLayerDataspace(Dataspace::UNKNOWN);
+
+    mWriter->validateDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mReader->mCompositionChanges.clear();
+
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    mWriter->selectLayer(layer);
+    auto handle2 = allocate();
+    ASSERT_NE(nullptr, handle2);
+
+    mWriter->setLayerBuffer(0, handle2, -1);
+    mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, {0, 0, 10, 10}));
+    mWriter->validateDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mReader->mCompositionChanges.clear();
+
+    mWriter->presentDisplay();
+    execute();
+}
+
+void GraphicsComposerHidlCommandTest::waitForVsyncPeriodChange(
+        Display display, const VsyncPeriodChangeTimeline& timeline, int64_t desiredTimeNanos,
+        int64_t oldPeriodNanos, int64_t newPeriodNanos) {
+    const auto CHANGE_DEADLINE = toTimePoint(timeline.newVsyncAppliedTimeNanos) + 100ms;
+    while (std::chrono::steady_clock::now() <= CHANGE_DEADLINE) {
+        VsyncPeriodNanos vsyncPeriodNanos;
+        EXPECT_EQ(Error::NONE, mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+        if (systemTime() <= desiredTimeNanos) {
+            EXPECT_EQ(vsyncPeriodNanos, oldPeriodNanos);
+        } else if (vsyncPeriodNanos == newPeriodNanos) {
+            break;
+        }
+        std::this_thread::sleep_for(std::chrono::nanoseconds(oldPeriodNanos));
+    }
+}
+
+void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints(
+        const TestParameters& params) {
+    for (Display display : mComposerCallback->getDisplays()) {
+        forEachTwoConfigs(display, [&](Config config1, Config config2) {
+            mComposerClient->setActiveConfig(display, config1);
+            sendRefreshFrame(nullptr);
+
+            int32_t vsyncPeriod1 = mComposerClient->getDisplayAttribute_2_4(
+                    display, config1, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+            int32_t vsyncPeriod2 = mComposerClient->getDisplayAttribute_2_4(
+                    display, config2, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+
+            if (vsyncPeriod1 == vsyncPeriod2) {
+                return;  // continue
+            }
+
+            VsyncPeriodChangeTimeline timeline;
+            IComposerClient::VsyncPeriodChangeConstraints constraints = {
+                    .desiredTimeNanos = systemTime() + params.delayForChange,
+                    .seamlessRequired = false};
+            EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints(
+                                           display, config2, constraints, &timeline));
+
+            EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos);
+            // Refresh rate should change within a reasonable time
+            constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s;  // 1 second
+            EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <=
+                        kReasonableTimeForChange.count());
+
+            if (timeline.refreshRequired) {
+                if (params.refreshMiss) {
+                    // Miss the refresh frame on purpose to make sure the implementation sends a
+                    // callback
+                    std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) + 100ms);
+                }
+                sendRefreshFrame(&timeline);
+            }
+            waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, vsyncPeriod1,
+                                     vsyncPeriod2);
+
+            // At this point the refresh rate should have changed already, however in rare
+            // cases the implementation might have missed the deadline. In this case a new
+            // timeline should have been provided.
+            auto newTimeline = mComposerCallback->takeLastVsyncPeriodChangeTimeline();
+            if (timeline.refreshRequired && params.refreshMiss) {
+                EXPECT_TRUE(newTimeline.has_value());
+            }
+
+            if (newTimeline.has_value()) {
+                if (newTimeline->refreshRequired) {
+                    sendRefreshFrame(&newTimeline.value());
+                }
+                waitForVsyncPeriodChange(display, newTimeline.value(), constraints.desiredTimeNanos,
+                                         vsyncPeriod1, vsyncPeriod2);
+            }
+
+            VsyncPeriodNanos vsyncPeriodNanos;
+            EXPECT_EQ(Error::NONE,
+                      mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+            EXPECT_EQ(vsyncPeriodNanos, vsyncPeriod2);
+        });
+    }
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints) {
+    Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = false});
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_Delayed) {
+    Test_setActiveConfigWithConstraints({.delayForChange = 300'000'000,  // 300ms
+                                         .refreshMiss = false});
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_MissRefresh) {
+    Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = true});
+}
+
+TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyModeBadDisplay) {
+    EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, true));
+    EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, false));
+}
+
+TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyMode) {
+    for (Display display : mComposerCallback->getDisplays()) {
+        std::vector<DisplayCapability> capabilities;
+        const auto error = mComposerClient->getDisplayCapabilities(display, &capabilities);
+        EXPECT_EQ(Error::NONE, error);
+
+        const bool allmSupport =
+                std::find(capabilities.begin(), capabilities.end(),
+                          DisplayCapability::AUTO_LOW_LATENCY_MODE) != capabilities.end();
+
+        if (!allmSupport) {
+            EXPECT_EQ(Error::UNSUPPORTED,
+                      mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true));
+            EXPECT_EQ(Error::UNSUPPORTED,
+                      mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
+            GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display "
+                            << std::to_string(display) << ", skipping test";
+            return;
+        }
+
+        EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, true));
+        EXPECT_EQ(Error::NONE, mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
+    }
+}
+
+TEST_P(GraphicsComposerHidlTest, getSupportedContentTypesBadDisplay) {
+    std::vector<ContentType> supportedContentTypes;
+    const auto error =
+            mComposerClient->getSupportedContentTypes(mInvalidDisplayId, &supportedContentTypes);
+    EXPECT_EQ(Error::BAD_DISPLAY, error);
+}
+
+TEST_P(GraphicsComposerHidlTest, getSupportedContentTypes) {
+    std::vector<ContentType> supportedContentTypes;
+    for (Display display : mComposerCallback->getDisplays()) {
+        supportedContentTypes.clear();
+        const auto error =
+                mComposerClient->getSupportedContentTypes(display, &supportedContentTypes);
+        const bool noneSupported =
+                std::find(supportedContentTypes.begin(), supportedContentTypes.end(),
+                          ContentType::NONE) != supportedContentTypes.end();
+        EXPECT_EQ(Error::NONE, error);
+        EXPECT_FALSE(noneSupported);
+    }
+}
+
+TEST_P(GraphicsComposerHidlTest, setContentTypeNoneAlwaysAccepted) {
+    for (Display display : mComposerCallback->getDisplays()) {
+        const auto error = mComposerClient->setContentType(display, ContentType::NONE);
+        EXPECT_NE(Error::UNSUPPORTED, error);
+    }
+}
+
+TEST_P(GraphicsComposerHidlTest, setContentTypeBadDisplay) {
+    const auto types = {ContentType::NONE, ContentType::GRAPHICS, ContentType::PHOTO,
+                        ContentType::CINEMA, ContentType::GAME};
+    for (auto type : types) {
+        EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setContentType(mInvalidDisplayId, type));
+    }
+}
+
+void GraphicsComposerHidlTest::Test_setContentTypeForDisplay(
+        const Display& display, const std::vector<ContentType>& capabilities,
+        const ContentType& contentType, const char* contentTypeStr) {
+    const bool contentTypeSupport =
+            std::find(capabilities.begin(), capabilities.end(), contentType) != capabilities.end();
+
+    if (!contentTypeSupport) {
+        EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setContentType(display, contentType));
+        GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display "
+                        << std::to_string(display) << ", skipping test";
+        return;
+    }
+
+    EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, contentType));
+    EXPECT_EQ(Error::NONE, mComposerClient->setContentType(display, ContentType::NONE));
+}
+
+void GraphicsComposerHidlTest::Test_setContentType(const ContentType& contentType,
+                                                   const char* contentTypeStr) {
+    for (Display display : mComposerCallback->getDisplays()) {
+        std::vector<ContentType> supportedContentTypes;
+        const auto error =
+                mComposerClient->getSupportedContentTypes(display, &supportedContentTypes);
+        EXPECT_EQ(Error::NONE, error);
+
+        Test_setContentTypeForDisplay(display, supportedContentTypes, contentType, contentTypeStr);
+    }
+}
+
+TEST_P(GraphicsComposerHidlTest, setGraphicsContentType) {
+    Test_setContentType(ContentType::GRAPHICS, "GRAPHICS");
+}
+
+TEST_P(GraphicsComposerHidlTest, setPhotoContentType) {
+    Test_setContentType(ContentType::PHOTO, "PHOTO");
+}
+
+TEST_P(GraphicsComposerHidlTest, setCinemaContentType) {
+    Test_setContentType(ContentType::CINEMA, "CINEMA");
+}
+
+TEST_P(GraphicsComposerHidlTest, setGameContentType) {
+    Test_setContentType(ContentType::GAME, "GAME");
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerHidlCommandTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+TEST_P(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
+    std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+    mComposerClient->getLayerGenericMetadataKeys(&keys);
+
+    std::regex reverseDomainName("^[a-zA-Z-]{2,}(\\.[a-zA-Z0-9-]+)+$");
+    std::unordered_set<std::string> uniqueNames;
+    for (const auto& key : keys) {
+        std::string name(key.name.c_str());
+
+        // Keys must not start with 'android' or 'com.android'
+        ASSERT_FALSE(name.find("android") == 0);
+        ASSERT_FALSE(name.find("com.android") == 0);
+
+        // Keys must be in reverse domain name format
+        ASSERT_TRUE(std::regex_match(name, reverseDomainName));
+
+        // Keys must be unique within this list
+        const auto& [iter, inserted] = uniqueNames.insert(name);
+        ASSERT_TRUE(inserted);
+    }
+}
+
+}  // namespace
+}  // namespace vts
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/default/OWNERS b/graphics/mapper/2.0/default/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/mapper/2.0/default/OWNERS
+++ b/graphics/mapper/2.0/default/OWNERS
@@ -1,4 +1,4 @@
 # Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
 stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/2.0/utils/OWNERS b/graphics/mapper/2.0/utils/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/mapper/2.0/utils/OWNERS
+++ b/graphics/mapper/2.0/utils/OWNERS
@@ -1,4 +1,4 @@
 # Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
 stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/2.0/vts/OWNERS b/graphics/mapper/2.0/vts/OWNERS
index 8e86f64..11b7d21 100644
--- a/graphics/mapper/2.0/vts/OWNERS
+++ b/graphics/mapper/2.0/vts/OWNERS
@@ -1,5 +1,7 @@
 # Graphics team
-marissaw@google.com
+chrisforbes@google.com
+stoza@google.com
+vhau@google.com
 
 # VTS team
 yim@google.com
diff --git a/graphics/mapper/2.1/default/OWNERS b/graphics/mapper/2.1/default/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/mapper/2.1/default/OWNERS
+++ b/graphics/mapper/2.1/default/OWNERS
@@ -1,4 +1,4 @@
 # Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
 stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/2.1/utils/OWNERS b/graphics/mapper/2.1/utils/OWNERS
index 273cb4c..2a56b38 100644
--- a/graphics/mapper/2.1/utils/OWNERS
+++ b/graphics/mapper/2.1/utils/OWNERS
@@ -1,4 +1,4 @@
 # Graphics team
-jessehall@google.com
-marissaw@google.com
+chrisforbes@google.com
 stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/2.1/vts/OWNERS b/graphics/mapper/2.1/vts/OWNERS
index 8e86f64..11b7d21 100644
--- a/graphics/mapper/2.1/vts/OWNERS
+++ b/graphics/mapper/2.1/vts/OWNERS
@@ -1,5 +1,7 @@
 # Graphics team
-marissaw@google.com
+chrisforbes@google.com
+stoza@google.com
+vhau@google.com
 
 # VTS team
 yim@google.com
diff --git a/graphics/mapper/3.0/utils/OWNERS b/graphics/mapper/3.0/utils/OWNERS
index 96f6d51..2a56b38 100644
--- a/graphics/mapper/3.0/utils/OWNERS
+++ b/graphics/mapper/3.0/utils/OWNERS
@@ -1,3 +1,4 @@
 # Graphics team
-marissaw@google.com
+chrisforbes@google.com
 stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/3.0/vts/OWNERS b/graphics/mapper/3.0/vts/OWNERS
index 96f6d51..2a56b38 100644
--- a/graphics/mapper/3.0/vts/OWNERS
+++ b/graphics/mapper/3.0/vts/OWNERS
@@ -1,3 +1,4 @@
 # Graphics team
-marissaw@google.com
+chrisforbes@google.com
 stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/4.0/Android.bp b/graphics/mapper/4.0/Android.bp
new file mode 100644
index 0000000..42c4942
--- /dev/null
+++ b/graphics/mapper/4.0/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.mapper@4.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "types.hal",
+        "IMapper.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
new file mode 100644
index 0000000..93c85bd
--- /dev/null
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -0,0 +1,648 @@
+/*
+ * 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.
+ */
+
+package android.hardware.graphics.mapper@4.0;
+
+import android.hardware.graphics.common@1.2::BufferUsage;
+import android.hardware.graphics.common@1.2::PixelFormat;
+import android.hardware.graphics.common@1.2::Rect;
+
+interface IMapper {
+    struct BufferDescriptorInfo {
+        /**
+         * The name of the buffer. Useful for debugging/tracing.
+         */
+        string name;
+
+        /**
+         * The width specifies how many columns of pixels must be in the
+         * allocated buffer, but does not necessarily represent the offset in
+         * columns between the same column in adjacent rows. The rows may be
+         * padded.
+         */
+        uint32_t width;
+
+        /**
+         * The height specifies how many rows of pixels must be in the
+         * allocated buffer.
+         */
+        uint32_t height;
+
+        /**
+         * The number of image layers that must be in the allocated buffer.
+         */
+        uint32_t layerCount;
+
+        /**
+         * Buffer pixel format.
+         */
+        PixelFormat format;
+
+        /**
+         * Buffer usage mask; valid flags can be found in the definition of
+         * BufferUsage.
+         */
+        bitfield<BufferUsage> usage;
+
+        /**
+         * The size in bytes of the reserved region associated with the buffer.
+         * See getReservedRegion for more information.
+         */
+        uint64_t reservedSize;
+    };
+
+    struct Rect {
+        int32_t left;
+        int32_t top;
+        int32_t width;
+        int32_t height;
+    };
+
+    /**
+     * Creates a buffer descriptor. The descriptor can be used with IAllocator
+     * to allocate buffers.
+     *
+     * Since the buffer descriptor fully describes a buffer, any device
+     * dependent or device independent checks must be performed here whenever
+     * possible. When layered buffers are not supported, this function must
+     * return `UNSUPPORTED` if `description.layers` is great than 1. This
+     * function may return `UNSUPPORTED` if `description.reservedSize` is
+     * larger than a page.
+     *
+     * @param description Attributes of the descriptor.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_VALUE` if any of the specified attributes are invalid or
+     *       inconsistent.
+     *     - `NO_RESOURCES` if the creation cannot be fullfilled due to
+     *       unavailability of resources.
+     *     - `UNSUPPORTED` when any of the specified attributes are not
+     *       supported.
+     * @return descriptor Newly created buffer descriptor.
+     */
+    createDescriptor(BufferDescriptorInfo description)
+            generates (Error error,
+                       BufferDescriptor descriptor);
+
+    /**
+     * Imports a raw buffer handle to create an imported buffer handle for use
+     * with the rest of the mapper or with other in-process libraries.
+     *
+     * A buffer handle is considered raw when it is cloned (e.g., with
+     * `native_handle_clone()`) from another buffer handle locally, or when it
+     * is received from another HAL server/client or another process. A raw
+     * buffer handle must not be used to access the underlying graphic
+     * buffer. It must be imported to create an imported handle first.
+     *
+     * This function must at least validate the raw handle before creating the
+     * imported handle. It must also support importing the same raw handle
+     * multiple times to create multiple imported handles. The imported handle
+     * must be considered valid everywhere in the process, including in
+     * another instance of the mapper.
+     *
+     * Because of passthrough HALs, a raw buffer handle received from a HAL
+     * may actually have been imported in the process. importBuffer() must treat
+     * such a handle as if it is raw and must not return `BAD_BUFFER`. The
+     * returned handle is independent from the input handle as usual, and
+     * freeBuffer() must be called on it when it is no longer needed.
+     *
+     * @param rawHandle Raw buffer handle to import.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `NO_RESOURCES` if the raw handle cannot be imported due to
+     *       unavailability of resources.
+     * @return buffer Imported buffer handle that has the type
+     *     `buffer_handle_t` which is a handle type.
+     */
+    importBuffer(handle rawHandle) generates (Error error, pointer buffer);
+
+    /**
+     * Frees a buffer handle. Buffer handles returned by importBuffer() must be
+     * freed with this function when no longer needed.
+     *
+     * This function must free up all resources allocated by importBuffer() for
+     * the imported handle. For example, if the imported handle was created
+     * with `native_handle_create()`, this function must call
+     * `native_handle_close()` and `native_handle_delete()`.
+     *
+     * @param buffer Imported buffer handle.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid.
+     */
+    freeBuffer(pointer buffer) generates (Error error);
+
+    /**
+     * Validates that the buffer can be safely accessed by a caller who assumes
+     * the specified @p description and @p stride. This must at least validate
+     * that the buffer size is large enough. Validating the buffer against
+     * individual buffer attributes is optional.
+     *
+     * @param buffer Buffer to validate against.
+     * @param description Attributes of the buffer.
+     * @param stride Stride returned by IAllocator::allocate().
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid.
+     *     - `BAD_VALUE` if the buffer cannot be safely accessed.
+     */
+    validateBufferSize(pointer buffer,
+                       BufferDescriptorInfo description,
+                       uint32_t stride)
+            generates (Error error);
+
+    /**
+     * Calculates the transport size of a buffer. An imported buffer handle is a
+     * raw buffer handle with the process-local runtime data appended. This
+     * function, for example, allows a caller to omit the process-local runtime
+     * data at the tail when serializing the imported buffer handle.
+     *
+     * Note that a client might or might not omit the process-local runtime data
+     * when sending an imported buffer handle. The mapper must support both
+     * cases on the receiving end.
+     *
+     * @param buffer Buffer to get the transport size from.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid.
+     * @return numFds The number of file descriptors needed for transport.
+     * @return numInts The number of integers needed for transport.
+     */
+    getTransportSize(pointer buffer)
+            generates (Error error,
+                       uint32_t numFds,
+                       uint32_t numInts);
+
+    /**
+     * Locks the given buffer for the specified CPU usage.
+     *
+     * Locking the same buffer simultaneously from multiple threads is
+     * permitted, but if any of the threads attempt to lock the buffer for
+     * writing, the behavior is undefined, except that it must not cause
+     * process termination or block the client indefinitely. Leaving the
+     * buffer content in an indeterminate state or returning an error are both
+     * acceptable.
+     *
+     * 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must
+     * "lock in place". The buffers must be directly accessible via mapping.
+     *
+     * The client must not modify the content of the buffer outside of
+     * @p accessRegion, and the device need not guarantee that content outside
+     * of @p accessRegion is valid for reading. The result of reading or writing
+     * outside of @p accessRegion is undefined, except that it must not cause
+     * process termination.
+     *
+     * An accessRegion of all-zeros means the entire buffer. That is, it is
+     * equivalent to '(0,0)-(buffer width, buffer height)'.
+     *
+     * This function can lock both single-planar and multi-planar formats. The caller
+     * should use get() to get information about the buffer they are locking.
+     * get() can be used to get information about the planes, offsets, stride,
+     * etc.
+     *
+     * This function must also work on buffers with
+     * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well
+     * as with any other formats requested by multimedia codecs when they are
+     * configured with a flexible-YUV-compatible color format.
+     *
+     * On success, @p data must be filled with a pointer to the locked buffer
+     * memory. This address will represent the top-left corner of the entire
+     * buffer, even if @p accessRegion does not begin at the top-left corner.
+     *
+     * The locked buffer must adhere to the format requested at allocation time
+     * in the BufferDescriptorInfo.
+     *
+     * @param buffer Buffer to lock.
+     * @param cpuUsage CPU usage flags to request. See +ndk
+     *     libnativewindow#AHardwareBuffer_UsageFlags for possible values.
+     * @param accessRegion Portion of the buffer that the client intends to
+     *     access.
+     * @param acquireFence Handle containing a file descriptor referring to a
+     *     sync fence object, which will be signaled when it is safe for the
+     *     mapper to lock the buffer. @p acquireFence may be an empty fence if
+     *     it is already safe to lock.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid or is incompatible with this
+     *       function.
+     *     - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or
+     *       is incompatible with the buffer. Also if the @p accessRegion is
+     *       outside the bounds of the buffer or the accessRegion is invalid.
+     *     - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
+     *       that locking may succeed at a later time.
+     * @return data CPU-accessible pointer to the buffer data.
+     */
+    lock(pointer buffer,
+         uint64_t cpuUsage,
+         Rect accessRegion,
+         handle acquireFence)
+            generates (Error error,
+                       pointer data);
+
+    /**
+     * Unlocks a buffer to indicate all CPU accesses to the buffer have
+     * completed.
+     *
+     * @param buffer Buffer to unlock.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid or not locked.
+     * @return releaseFence Handle containing a file descriptor referring to a
+     *     sync fence object. The sync fence object will be signaled when the
+     *     mapper has completed any pending work. @p releaseFence may be an
+     *     empty fence.
+     */
+    unlock(pointer buffer) generates (Error error, handle releaseFence);
+
+    /**
+     * Flushes the contents of a locked buffer.
+     *
+     * This function flushes the CPUs caches for the range of all the buffer's
+     * planes and metadata. This should behave similarly to unlock() except the
+     * buffer should remain mapped to the CPU.
+     *
+     * The client is still responsible for calling unlock() when it is done
+     * with all CPU accesses to the buffer.
+     *
+     * If non-CPU blocks are simultaneously writing the buffer, the locked
+     * copy should still be flushed but what happens is undefined except that
+     * it should not cause any crashes.
+     *
+     * @param buffer Buffer to flush.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid or not locked.
+     * @return releaseFence Handle containing a file descriptor referring to a
+     *     sync fence object. The sync fence object will be signaled when the
+     *     mapper has completed any pending work. @p releaseFence may be an
+     *     empty fence.
+     */
+    flushLockedBuffer(pointer buffer) generates (Error error, handle releaseFence);
+
+    /**
+     * Rereads the contents of a locked buffer.
+     *
+     * This should fetch the most recent copy of the locked buffer.
+     *
+     * It may reread locked copies of the buffer in other processes.
+     *
+     * The client is still responsible for calling unlock() when it is done
+     * with all CPU accesses to the buffer.
+     *
+     * @param buffer Buffer to reread.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid or not locked.
+     *     - `NO_RESOURCES` if the buffer cannot be reread at this time. Note
+     *       that rereading may succeed at a later time.
+     */
+    rereadLockedBuffer(pointer buffer) generates(Error error);
+
+    /**
+     * Test whether the given BufferDescriptorInfo is allocatable.
+     *
+     * If this function returns true, it means that a buffer with the given
+     * description can be allocated on this implementation, unless resource
+     * exhaustion occurs. If this function returns false, it means that the
+     * allocation of the given description will never succeed.
+     *
+     * @param description the description of the buffer
+     * @return supported whether the description is supported
+     */
+    isSupported(BufferDescriptorInfo description)
+            generates (Error error,
+                       bool supported);
+
+
+    /**
+     * Description for get(...), set(...) and getFromBufferDescriptorInfo(...)
+     *
+     * ------------ Overview -----------------------------------
+     * Gralloc 4 adds support for getting and setting buffer metadata on a buffer.
+     *
+     * To get buffer metadata, the client passes in a buffer handle and a token that
+     * represents the type of buffer metadata they would like to get. IMapper returns
+     * a byte stream that contains the buffer metadata. To set the buffer metadata, the
+     * client passes in a buffer handle and a token that represents the type of buffer
+     * metadata they would like to set and a byte stream that contains the buffer metadata
+     * they are setting.
+     *
+     * Buffer metadata is global for a buffer. When the metadata is set on the buffer
+     * in a process, the updated metadata should be available to all other processes.
+     * Please see "Storing and Propagating Metadata" below for more details.
+     *
+     * The getter and setter functions have been optimized for easy vendor extension.
+     * They do not require a formal HIDL extension to add support for getting and setting
+     * vendor defined buffer metadata. In order to allow easy extension, the types used
+     * here are not typical HIDL types. See "Buffer Metadata Token" and
+     * "Buffer Metadata Stream" below for more details.
+     *
+     * ------------ Storing and Propagating Metadata -----------
+     * Buffer metadata must be global. Any changes to the metadata must be propagated
+     * to all other processes immediately. Vendors may chose how they would like support
+     * this functionality.
+     *
+     * We recommend supporting this functionality by allocating an extra page of shared
+     * memory and storing it in the buffer's native_handle_t. The buffer metadata can
+     * be stored in the extra page of shared memory. Set operations are automatically
+     * propagated to all other processes.
+     *
+     * ------------ Buffer Metadata Synchronization ------------
+     * There are no explicit buffer metadata synchronization primitives. Many devices
+     * before gralloc 4 already support getting and setting of global buffer metadata
+     * with no explicit synchronization primitives. Adding synchronization primitives
+     * would just add unnecessary complexity.
+     *
+     * The general rule is if a process has permission to write to a buffer, they
+     * have permission to write to the buffer's metadata. If a process has permission
+     * to read from a buffer, they have permission to read the buffer's metadata.
+     *
+     * There is one exception to this rule. Fences CANNOT be used to protect a buffer's
+     * metadata. A process should finish writing to a buffer's metadata before
+     * sending the buffer to another process that will read or write to the buffer.
+     * This exception is needed because sometimes userspace needs to read the
+     * buffer's metadata before the buffer's contents are ready.
+     *
+     * As a simple example: an app renders to a buffer and then displays the buffer.
+     * In this example when the app renders to the buffer, both the buffer and its
+     * metadata need to be updated. The app's process queues up its work on the GPU
+     * and gets back an acquire fence. The app's process must update the buffer's
+     * metadata before enqueuing the buffer to SurfaceFlinger. The app process CANNOT
+     * update the buffer's metadata after enqueuing the buffer. When HardwareComposer
+     * receives the buffer, it is immediately safe to read the buffer's metadata
+     * and use it to program the display driver. To read the buffer's contents,
+     * display driver must still wait on the acquire fence.
+     *
+     * ------------ Buffer Metadata Token ----------------------
+     * In order to allow arbitrary vendor defined metadata, we could not use a
+     * HIDL enum as the buffer metadata token. Extending a HIDL enum requires a full
+     * HIDL extension. We also could not use a simple non-HIDL enum because vendor
+     * defined enums from different vendors could collide. Instead we have defined
+     * a struct that has a string representing the enum type and an int that
+     * represents the enum value. The string protects different enum values from
+     * colliding.
+     *
+     * The token struct (MetadataType) is defined as a HIDL struct since it
+     * is passed into a HIDL function. The standard buffer metadata types are NOT
+     * defined as a HIDL enum because it would have required a new IMapper version
+     * just to add future standard buffer metadata types. By putting the enum in the
+     * stable AIDL (hardware/interfaces/graphics/common/aidl/android/hardware/
+     * graphics/common/StandardMetadataType.aidl), vendors will be able to optionally
+     * choose to support future standard buffer metadata types without upgrading
+     * HIDL versions. For more information see the description of "struct MetadataType".
+     *
+     * ------------ Buffer Metadata Stream ---------------------
+     * The buffer metadata is get and set as a byte stream (vec<uint8_t>). By getting
+     * and setting buffer metadata as a byte stream, vendors can use the standard
+     * getters and setter functions defined here. Vendors do NOT need to add their own
+     * getters and setter functions for each new type of buffer metadata.
+     *
+     * Converting buffer metadata into a byte stream can be non-trivial. For the standard
+     * buffer metadata types defined in StandardMetadataType.aidl, there are also
+     * support functions that will encode the buffer metadata into a byte stream
+     * and decode the buffer metadata from a byte stream. We STRONGLY recommend using
+     * these support functions. The framework will use them when getting and setting
+     * metadata. The support functions are defined in
+     * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
+     */
+
+    /**
+     * MetadataType represents the different types of buffer metadata that could be
+     * associated with a buffer. It is used by IMapper to help get and set buffer metadata
+     * on the buffer's native handle.
+     *
+     * Standard buffer metadata will have the name field set to
+     * "android.hardware.graphics.common.StandardMetadataType" and will contain values
+     * from StandardMetadataType.aidl.
+     *
+     * This struct should be "extended" by devices that use a proprietary or non-standard
+     * buffer metadata. To extend the struct, first create a custom @VendorStability vendor
+     * AIDL interface that defines the new type(s) you would like to support. Set the
+     * struct's name field to the custom aidl interface's name
+     * (eg. "vendor.mycompanyname.graphics.common.MetadataType"). Set the struct's value
+     * field to the custom @VendorStabilty vendor AIDL interface.
+     *
+     * Each company should create their own StandardMetadataType.aidl extension. The name
+     * field prevents values from different companies from colliding.
+     */
+    struct MetadataType {
+        string name;
+        int64_t value;
+    };
+
+    /**
+     * Gets the buffer metadata for a given MetadataType.
+     *
+     * Buffer metadata can be changed after allocation so clients should avoid "caching"
+     * the buffer metadata. For example, if the video resolution changes and the buffers
+     * are not reallocated, several buffer metadata values may change without warning.
+     * Clients should not expect the values to be constant. They should requery them every
+     * frame. The only exception is buffer metadata that is determined at allocation
+     * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
+     * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
+     * they are determined at allocation time.
+     *
+     * @param buffer Buffer containing desired metadata
+     * @param metadataType MetadataType for the metadata value being queried
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+     *        resources.
+     *     - `UNSUPPORTED` when metadataType is unknown/unsupported.
+     *        IMapper must support getting all StandardMetadataType.aidl values defined
+     *        at the time the device first launches.
+     * @return metadata Vector of bytes representing the buffer metadata associated with
+     *  the MetadataType.
+     */
+    get(pointer buffer, MetadataType metadataType)
+            generates (Error error,
+                       vec<uint8_t> metadata);
+
+    /**
+     * Sets the global value for a given MetadataType.
+     *
+     * Metadata fields are not required to be settable. This function can
+     * return Error::UNSUPPORTED whenever it doesn't support setting a
+     * particular Metadata field.
+     *
+     * The framework may attempt to set the following StandardMetadataType
+     * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
+     * We strongly encourage everyone to support setting as many of those fields as
+     * possible. If a device's Composer implementation supports a field, it should be
+     * supported here. Over time these metadata fields will be moved out of
+     * Composer/BufferQueue/etc. and into the buffer's Metadata fields.
+     * If a device's IMapper doesn't support setting those Metadata fields,
+     * eventually the device may not longer be able to support these fields.
+     *
+     * @param buffer Buffer receiving desired metadata
+     * @param metadataType MetadataType for the metadata value being set
+     * @param metadata Vector of bytes representing the value associated with
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `BAD_VALUE` when the field is constant and can never be set (such as
+     *       BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
+     *       USAGE)
+     *     - `NO_RESOURCES` if the set cannot be fullfilled due to unavailability of
+     *        resources.
+     *     - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
+     *       it is unsupported. Unsupported should also be returned if the metadata
+     *       is malformed.
+     */
+    set(pointer buffer, MetadataType metadataType, vec<uint8_t> metadata)
+            generates (Error error);
+
+    /**
+     * Given a BufferDescriptorInfo, gets the starting value of a given
+     * MetadataType. This can be used to query basic information about a buffer
+     * before the buffer is allocated.
+     *
+     * @param description Attributes of the descriptor.
+     * @param metadataType MetadataType for the metadata value being queried
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_VALUE` if any of the specified BufferDescriptorInfo attributes
+     *       are invalid.
+     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+     *       resources.
+     *     - `UNSUPPORTED` when any of the description attributes are unsupported or
+     *       if the metadataType is unknown/unsupported. This should also be
+     *       returned if the requested metadata is not defined until a buffer has been
+     *       allocated.
+     * @return metadata Vector of bytes representing the value associated with
+     *  the MetadataType value.
+     */
+    getFromBufferDescriptorInfo(BufferDescriptorInfo description,
+                                MetadataType metadataType)
+            generates (Error error,
+                       vec<uint8_t> metadata);
+
+    struct MetadataTypeDescription {
+        MetadataType metadataType;
+        /**
+         * description should contain a string representation of the MetadataType.
+         *
+         * For example: "MyExampleMetadataType is a 64-bit timestamp in nanoseconds
+         * that indicates when a buffer is decoded. It is set by the media HAL after
+         * a buffer is decoded. It is used by the display HAL for hardware
+         * synchronization".
+         *
+         * This field is required for any non-StandardMetadataTypes.
+         */
+        string description;
+        /**
+         * isGettable represents if the MetadataType can be get.
+         */
+        bool isGettable;
+        /**
+         * isSettable represents if the MetadataType can be set.
+         */
+        bool isSettable;
+    };
+
+    /**
+     * Lists all the MetadataTypes supported by IMapper as well as a description
+     * of each supported MetadataType. For StandardMetadataTypes, the description
+     * string can be left empty.
+     *
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+     *       resources.
+     * @return descriptions Vector of MetadataTypeDescriptions that represent the
+     *  MetadataTypes supported by the device.
+     */
+    listSupportedMetadataTypes()
+            generates (Error error, vec<MetadataTypeDescription> descriptions);
+
+    struct MetadataDump {
+        /**
+         * The type of metadata being dumped.
+         */
+        MetadataType metadataType;
+        /**
+         * The byte stream representation of the metadata. If the metadata is not
+         * gettable, the vector must be empty.
+         */
+        vec<uint8_t> metadata;
+    };
+
+    struct BufferDump {
+        /**
+         * A vector of all the metadata that is being dumped for a particular buffer.
+         */
+        vec<MetadataDump> metadataDump;
+    };
+
+    /**
+     * Dumps a buffer's metadata.
+     *
+     * @param buffer Buffer that is being dumped
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the raw handle is invalid.
+     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+     *       resources.
+     * @return bufferDump Struct representing the metadata being dumped
+     */
+    dumpBuffer(pointer buffer)
+            generates (Error error, BufferDump bufferDump);
+
+    /**
+     * Dumps the metadata for all the buffers in the current process.
+     *
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `NO_RESOURCES` if the get cannot be fullfilled due to unavailability of
+     *       resources.
+     * @return bufferDumps Vector of structs representing the buffers being dumped
+     */
+    dumpBuffers()
+            generates (Error error, vec<BufferDump> bufferDumps);
+
+    /**
+     * Returns the region of shared memory associated with the buffer that is
+     * reserved for client use.
+     *
+     * The shared memory may be allocated from any shared memory allocator.
+     * The shared memory must be CPU-accessible and virtually contiguous. The
+     * starting address must be word-aligned.
+     *
+     * This function may only be called after importBuffer() has been called by the
+     * client. The reserved region must remain accessible until freeBuffer() has
+     * been called. After freeBuffer() has been called, the client must not access
+     * the reserved region.
+     *
+     * This reserved memory may be used in future versions of Android to
+     * help clients implement backwards compatible features without requiring
+     * IAllocator/IMapper updates.
+     *
+     * @param buffer Imported buffer handle.
+     * @return error Error status of the call, which may be
+     *     - `NONE` upon success.
+     *     - `BAD_BUFFER` if the buffer is invalid.
+     * @return reservedRegion CPU-accessible pointer to the reserved region
+     * @return reservedSize the size of the reservedRegion that was requested
+     *    in the BufferDescriptorInfo.
+     */
+    getReservedRegion(pointer buffer)
+            generates (Error error,
+                       pointer reservedRegion,
+                       uint64_t reservedSize);
+};
+
diff --git a/graphics/mapper/4.0/types.hal b/graphics/mapper/4.0/types.hal
new file mode 100644
index 0000000..00b6607
--- /dev/null
+++ b/graphics/mapper/4.0/types.hal
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package android.hardware.graphics.mapper@4.0;
+
+/**
+ * Error values that may be returned by a method of IAllocator or IMapper.
+ */
+enum Error : int32_t {
+    /**
+     * No error.
+     */
+    NONE            = 0,
+    /**
+     * Invalid BufferDescriptor.
+     */
+    BAD_DESCRIPTOR  = 1,
+    /**
+     * Invalid buffer handle.
+     */
+    BAD_BUFFER      = 2,
+    /**
+     * Invalid HardwareBufferDescription.
+     */
+    BAD_VALUE       = 3,
+    /**
+     * Resource unavailable.
+     */
+    NO_RESOURCES    = 5,
+    /**
+     * Permanent failure.
+     */
+    UNSUPPORTED     = 7,
+};
+
+/**
+ * A buffer descriptor is an implementation-defined opaque data returned by
+ * createDescriptor(). It describes the properties of a buffer and is consumed
+ * by the allocator.
+ */
+typedef vec<uint8_t> BufferDescriptor;
+
diff --git a/graphics/mapper/4.0/utils/OWNERS b/graphics/mapper/4.0/utils/OWNERS
new file mode 100644
index 0000000..2a56b38
--- /dev/null
+++ b/graphics/mapper/4.0/utils/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+chrisforbes@google.com
+stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
new file mode 100644
index 0000000..56ff116
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -0,0 +1,37 @@
+//
+// 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_library_static {
+    name: "android.hardware.graphics.mapper@4.0-vts",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["MapperVts.cpp"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@4.0",
+        "android.hardware.graphics.mapper@4.0",
+    ],
+    shared_libs: [
+        "libgralloctypes",
+    ],
+    export_static_lib_headers: [
+        "android.hardware.graphics.allocator@4.0",
+        "android.hardware.graphics.mapper@4.0",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
new file mode 100644
index 0000000..5b2a94e
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -0,0 +1,353 @@
+/*
+ * 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.
+ */
+
+#include <gralloctypes/Gralloc4.h>
+#include <mapper-vts/4.0/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V4_0 {
+namespace vts {
+
+Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName,
+                 bool errOnFailure) {
+    if (errOnFailure) {
+        init(allocatorServiceName, mapperServiceName);
+    } else {
+        initNoErr(allocatorServiceName, mapperServiceName);
+    }
+}
+
+void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
+    mAllocator = IAllocator::getService(allocatorServiceName);
+    ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+
+    mMapper = IMapper::getService(mapperServiceName);
+    ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
+    ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+}
+
+void Gralloc::initNoErr(const std::string& allocatorServiceName,
+                        const std::string& mapperServiceName) {
+    mAllocator = IAllocator::getService(allocatorServiceName);
+
+    mMapper = IMapper::getService(mapperServiceName);
+    if (mMapper.get()) {
+        ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+    }
+}
+
+Gralloc::~Gralloc() {
+    for (auto bufferHandle : mClonedBuffers) {
+        auto buffer = const_cast<native_handle_t*>(bufferHandle);
+        native_handle_close(buffer);
+        native_handle_delete(buffer);
+    }
+    mClonedBuffers.clear();
+
+    for (auto bufferHandle : mImportedBuffers) {
+        auto buffer = const_cast<native_handle_t*>(bufferHandle);
+        EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer)) << "failed to free buffer " << buffer;
+    }
+    mImportedBuffers.clear();
+}
+
+sp<IAllocator> Gralloc::getAllocator() const {
+    return mAllocator;
+}
+
+const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle,
+                                            enum Tolerance /*tolerance*/) {
+    const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
+    EXPECT_NE(nullptr, bufferHandle);
+
+    if (bufferHandle) {
+        mClonedBuffers.insert(bufferHandle);
+    }
+
+    return bufferHandle;
+}
+
+std::vector<const native_handle_t*> Gralloc::allocate(const BufferDescriptor& descriptor,
+                                                      uint32_t count, bool import,
+                                                      enum Tolerance tolerance,
+                                                      uint32_t* outStride) {
+    std::vector<const native_handle_t*> bufferHandles;
+    bufferHandles.reserve(count);
+    mAllocator->allocate(descriptor, count,
+                         [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
+                             if (canTolerate(tolerance, tmpError)) {
+                                 return;
+                             }
+
+                             ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
+                             ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
+
+                             for (uint32_t i = 0; i < count; i++) {
+                                 const native_handle_t* bufferHandle = nullptr;
+                                 if (import) {
+                                     ASSERT_NO_FATAL_FAILURE(
+                                             bufferHandle = importBuffer(tmpBuffers[i], tolerance));
+                                 } else {
+                                     ASSERT_NO_FATAL_FAILURE(
+                                             bufferHandle = cloneBuffer(tmpBuffers[i], tolerance));
+                                 }
+                                 if (bufferHandle) {
+                                     bufferHandles.push_back(bufferHandle);
+                                 }
+                             }
+
+                             if (outStride) {
+                                 *outStride = tmpStride;
+                             }
+                         });
+
+    if (::testing::Test::HasFatalFailure()) {
+        bufferHandles.clear();
+    }
+
+    return bufferHandles;
+}
+
+const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                         bool import, enum Tolerance tolerance,
+                                         uint32_t* outStride) {
+    BufferDescriptor descriptor = createDescriptor(descriptorInfo);
+    if (::testing::Test::HasFatalFailure()) {
+        return nullptr;
+    }
+
+    auto buffers = allocate(descriptor, 1, import, tolerance, outStride);
+    if (::testing::Test::HasFatalFailure()) {
+        return nullptr;
+    }
+
+    if (buffers.size() != 1) {
+        return nullptr;
+    }
+    return buffers[0];
+}
+
+sp<IMapper> Gralloc::getMapper() const {
+    return mMapper;
+}
+
+BufferDescriptor Gralloc::createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+    BufferDescriptor descriptor;
+    mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
+        descriptor = tmpDescriptor;
+    });
+
+    return descriptor;
+}
+
+const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle,
+                                             enum Tolerance tolerance) {
+    const native_handle_t* bufferHandle = nullptr;
+    mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+        if (!canTolerate(tolerance, tmpError)) {
+            ASSERT_EQ(Error::NONE, tmpError)
+                    << "failed to import buffer %p" << rawHandle.getNativeHandle();
+        }
+        bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
+    });
+
+    if (bufferHandle) {
+        mImportedBuffers.insert(bufferHandle);
+    }
+
+    return bufferHandle;
+}
+
+void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
+    if (bufferHandle == nullptr) {
+        return;
+    }
+
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    if (mImportedBuffers.erase(bufferHandle)) {
+        Error error = mMapper->freeBuffer(buffer);
+        ASSERT_EQ(Error::NONE, error) << "failed to free buffer " << buffer;
+    } else {
+        mClonedBuffers.erase(bufferHandle);
+        native_handle_close(buffer);
+        native_handle_delete(buffer);
+    }
+}
+
+void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                    const IMapper::Rect& accessRegion, int acquireFence) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+    hidl_handle acquireFenceHandle;
+    if (acquireFence >= 0) {
+        auto h = native_handle_init(acquireFenceStorage, 1, 0);
+        h->data[0] = acquireFence;
+        acquireFenceHandle = h;
+    }
+
+    void* data = nullptr;
+    mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+                  [&](const auto& tmpError, const auto& tmpData) {
+                      ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer;
+                      data = tmpData;
+                  });
+
+    if (acquireFence >= 0) {
+        close(acquireFence);
+    }
+
+    return data;
+}
+
+int Gralloc::unlock(const native_handle_t* bufferHandle) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    int releaseFence = -1;
+    mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock buffer " << buffer;
+
+        auto fenceHandle = tmpReleaseFence.getNativeHandle();
+        if (fenceHandle) {
+            ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle " << fenceHandle;
+            if (fenceHandle->numFds == 1) {
+                releaseFence = dup(fenceHandle->data[0]);
+                ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
+            } else {
+                ASSERT_EQ(0, fenceHandle->numFds) << " invalid fence handle " << fenceHandle;
+            }
+        }
+    });
+
+    return releaseFence;
+}
+
+int Gralloc::flushLockedBuffer(const native_handle_t* bufferHandle) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    int releaseFence = -1;
+    mMapper->flushLockedBuffer(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to flush locked buffer " << buffer;
+
+        auto fenceHandle = tmpReleaseFence.getNativeHandle();
+        if (fenceHandle) {
+            ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle " << fenceHandle;
+            if (fenceHandle->numFds == 1) {
+                releaseFence = dup(fenceHandle->data[0]);
+                ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
+            } else {
+                ASSERT_EQ(0, fenceHandle->numFds) << " invalid fence handle " << fenceHandle;
+            }
+        }
+    });
+
+    return releaseFence;
+}
+
+void Gralloc::rereadLockedBuffer(const native_handle_t* bufferHandle) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    ASSERT_EQ(Error::NONE, mMapper->rereadLockedBuffer(buffer));
+}
+
+bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle,
+                                 const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                 uint32_t stride) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    Error error = mMapper->validateBufferSize(buffer, descriptorInfo, stride);
+    return error == Error::NONE;
+}
+
+void Gralloc::getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+                               uint32_t* outNumInts) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    *outNumFds = 0;
+    *outNumInts = 0;
+    mMapper->getTransportSize(buffer, [&](const auto& tmpError, const auto& tmpNumFds,
+                                          const auto& tmpNumInts) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get transport size";
+        ASSERT_GE(bufferHandle->numFds, int(tmpNumFds)) << "invalid numFds " << tmpNumFds;
+        ASSERT_GE(bufferHandle->numInts, int(tmpNumInts)) << "invalid numInts " << tmpNumInts;
+
+        *outNumFds = tmpNumFds;
+        *outNumInts = tmpNumInts;
+    });
+}
+
+bool Gralloc::isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+    bool supported = false;
+    mMapper->isSupported(descriptorInfo, [&](const auto& tmpError, const auto& tmpSupported) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to check is supported";
+        supported = tmpSupported;
+    });
+    return supported;
+}
+
+Error Gralloc::get(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+                   hidl_vec<uint8_t>* outVec) {
+    Error err;
+    mMapper->get(const_cast<native_handle_t*>(bufferHandle), metadataType,
+                 [&](const auto& tmpError, const hidl_vec<uint8_t>& tmpVec) {
+                     err = tmpError;
+                     *outVec = tmpVec;
+                 });
+    return err;
+}
+
+Error Gralloc::set(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+                   const hidl_vec<uint8_t>& vec) {
+    return mMapper->set(const_cast<native_handle_t*>(bufferHandle), metadataType, vec);
+}
+
+Error Gralloc::getFromBufferDescriptorInfo(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                           const IMapper::MetadataType& metadataType,
+                                           hidl_vec<uint8_t>* outVec) {
+    Error err;
+    mMapper->getFromBufferDescriptorInfo(
+            descriptorInfo, metadataType,
+            [&](const auto& tmpError, const hidl_vec<uint8_t>& tmpVec) {
+                err = tmpError;
+                *outVec = tmpVec;
+            });
+    return err;
+}
+
+Error Gralloc::getReservedRegion(const native_handle_t* bufferHandle, void** outReservedRegion,
+                                 uint64_t* outReservedSize) {
+    Error err;
+    mMapper->getReservedRegion(
+            const_cast<native_handle_t*>(bufferHandle),
+            [&](const auto& tmpError, const auto& tmpReservedRegion, const auto& tmpReservedSize) {
+                err = tmpError;
+                *outReservedRegion = tmpReservedRegion;
+                *outReservedSize = tmpReservedSize;
+            });
+    return err;
+}
+
+}  // namespace vts
+}  // namespace V4_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
new file mode 100644
index 0000000..22a935f
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <gtest/gtest.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V4_0 {
+namespace vts {
+
+using android::hardware::graphics::allocator::V4_0::IAllocator;
+
+// A wrapper to IAllocator and IMapper.
+class Gralloc {
+  public:
+    enum class Tolerance : uint32_t {
+        kToleranceStrict = 0x0U,
+        kToleranceBadDescriptor = 0x1U << std::underlying_type_t<Error>(Error::BAD_DESCRIPTOR),
+        kToleranceBadBuffer = 0x1U << std::underlying_type_t<Error>(Error::BAD_BUFFER),
+        kToleranceBadValue = 0x1U << std::underlying_type_t<Error>(Error::BAD_VALUE),
+        kToleranceNoResource = 0x1U << std::underlying_type_t<Error>(Error::NO_RESOURCES),
+        kToleranceUnSupported = 0x1U << std::underlying_type_t<Error>(Error::UNSUPPORTED),
+        kToleranceAllErrors = ~0x0U,
+    };
+
+    Gralloc(const std::string& allocatorServiceName = "default",
+            const std::string& mapperServiceName = "default", bool errOnFailure = true);
+    ~Gralloc();
+
+    // IAllocator methods
+
+    sp<IAllocator> getAllocator() const;
+
+    // When import is false, this simply calls IAllocator::allocate. When import
+    // is true, the returned buffers are also imported into the mapper.
+    //
+    // Either case, the returned buffers must be freed with freeBuffer.
+    std::vector<const native_handle_t*> allocate(
+            const BufferDescriptor& descriptor, uint32_t count, bool import = true,
+            enum Tolerance tolerance = Tolerance::kToleranceStrict, uint32_t* outStride = nullptr);
+
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import, enum Tolerance tolerance, uint32_t* outStride);
+
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import) {
+        return allocate(descriptorInfo, import, Tolerance::kToleranceStrict);
+    }
+
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import, enum Tolerance tolerance) {
+        return allocate(descriptorInfo, import, tolerance, nullptr);
+    }
+
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import, uint32_t* outStride) {
+        return allocate(descriptorInfo, import, Tolerance::kToleranceStrict, outStride);
+    }
+
+    // IMapper methods
+
+    sp<IMapper> getMapper() const;
+
+    BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
+    const native_handle_t* importBuffer(const hidl_handle& rawHandle, enum Tolerance tolerance);
+    const native_handle_t* importBuffer(const hidl_handle& rawHandle) {
+        return importBuffer(rawHandle, Tolerance::kToleranceStrict);
+    }
+
+    void freeBuffer(const native_handle_t* bufferHandle);
+
+    // We use fd instead of hidl_handle in these functions to pass fences
+    // in and out of the mapper.  The ownership of the fd is always transferred
+    // with each of these functions.
+    void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+               const IMapper::Rect& accessRegion, int acquireFence);
+    int unlock(const native_handle_t* bufferHandle);
+
+    int flushLockedBuffer(const native_handle_t* bufferHandle);
+    void rereadLockedBuffer(const native_handle_t* bufferHandle);
+
+    bool validateBufferSize(const native_handle_t* bufferHandle,
+                            const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride);
+    void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+                          uint32_t* outNumInts);
+
+    bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
+    Error get(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+              hidl_vec<uint8_t>* outVec);
+
+    Error set(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
+              const hidl_vec<uint8_t>& vec);
+
+    Error getFromBufferDescriptorInfo(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                      const IMapper::MetadataType& metadataType,
+                                      hidl_vec<uint8_t>* outVec);
+
+    Error getReservedRegion(const native_handle_t* bufferHandle, void** outReservedRegion,
+                            uint64_t* outReservedSize);
+
+  private:
+    bool canTolerate(Tolerance tolerance, Error error) {
+        return (std::underlying_type_t<Tolerance>(tolerance) &
+                0x1U << std::underlying_type_t<Error>(error)) != 0;
+    }
+
+    void init(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+
+    // initialize without checking for failure to get service
+    void initNoErr(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+    const native_handle_t* cloneBuffer(const hidl_handle& rawHandle, enum Tolerance tolerance);
+    const native_handle_t* cloneBuffer(const hidl_handle& rawHandle) {
+        return cloneBuffer(rawHandle, Tolerance::kToleranceStrict);
+    }
+
+    sp<IAllocator> mAllocator;
+    sp<IMapper> mMapper;
+
+    // Keep track of all cloned and imported handles.  When a test fails with
+    // ASSERT_*, the destructor will free the handles for the test.
+    std::unordered_set<const native_handle_t*> mClonedBuffers;
+    std::unordered_set<const native_handle_t*> mImportedBuffers;
+};
+
+}  // namespace vts
+}  // namespace V4_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/4.0/vts/OWNERS b/graphics/mapper/4.0/vts/OWNERS
new file mode 100644
index 0000000..2a56b38
--- /dev/null
+++ b/graphics/mapper/4.0/vts/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+chrisforbes@google.com
+stoza@google.com
+vhau@google.com
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
new file mode 100644
index 0000000..3542a6e
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -0,0 +1,41 @@
+//
+// 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.
+//
+
+cc_test {
+    name: "VtsHalGraphicsMapperV4_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.mapper@4.0-vts",
+        "libgralloctypes",
+        "libsync",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.allocator@4.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.graphics.mapper@4.0",
+    ],
+    header_libs: [
+        "libsystem_headers",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
new file mode 100644
index 0000000..bb775dc
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -0,0 +1,2609 @@
+/*
+ * 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 "VtsHalGraphicsMapperV4_0TargetTest"
+
+#include <unistd.h>
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <android/sync.h>
+#include <gralloctypes/Gralloc4.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <mapper-vts/4.0/MapperVts.h>
+#include <system/graphics.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V4_0 {
+namespace vts {
+namespace {
+
+using ::android::base::unique_fd;
+using android::hardware::graphics::common::V1_2::BufferUsage;
+using android::hardware::graphics::common::V1_2::PixelFormat;
+using Tolerance = ::android::hardware::graphics::mapper::V4_0::vts::Gralloc::Tolerance;
+using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
+using aidl::android::hardware::graphics::common::BlendMode;
+using aidl::android::hardware::graphics::common::Cta861_3;
+using aidl::android::hardware::graphics::common::Dataspace;
+using aidl::android::hardware::graphics::common::ExtendableType;
+using aidl::android::hardware::graphics::common::PlaneLayout;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using aidl::android::hardware::graphics::common::Smpte2086;
+using aidl::android::hardware::graphics::common::StandardMetadataType;
+
+using DecodeFunction = std::function<void(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                          const hidl_vec<uint8_t>& vec)>;
+
+class GraphicsMapperHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+  protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+                                                                     std::get<1>(GetParam())));
+        ASSERT_NE(nullptr, mGralloc->getAllocator().get());
+        ASSERT_NE(nullptr, mGralloc->getMapper().get());
+
+        mDummyDescriptorInfo.name = "dummy";
+        mDummyDescriptorInfo.width = 64;
+        mDummyDescriptorInfo.height = 64;
+        mDummyDescriptorInfo.layerCount = 1;
+        mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
+        mDummyDescriptorInfo.usage =
+                static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+        mDummyDescriptorInfo.reservedSize = 0;
+    }
+
+    void TearDown() override {}
+
+    void testGet(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                 const MetadataType& metadataType, DecodeFunction decode) {
+        const native_handle_t* bufferHandle = nullptr;
+        ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(descriptorInfo, true));
+
+        hidl_vec<uint8_t> vec;
+        ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &vec));
+
+        ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec));
+    }
+
+    void testSet(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                 const MetadataType& metadataType, const hidl_vec<uint8_t>& metadata,
+                 DecodeFunction decode) {
+        const native_handle_t* bufferHandle = nullptr;
+        ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(descriptorInfo, true));
+
+        Error err = mGralloc->set(bufferHandle, metadataType, metadata);
+        if (err == Error::UNSUPPORTED) {
+            GTEST_SUCCEED() << "setting this metadata is unsupported";
+            return;
+        }
+        ASSERT_EQ(err, Error::NONE);
+
+        hidl_vec<uint8_t> vec;
+        ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &vec));
+
+        ASSERT_NO_FATAL_FAILURE(decode(descriptorInfo, vec));
+    }
+
+    void verifyRGBA8888PlaneLayouts(const std::vector<PlaneLayout>& planeLayouts) {
+        ASSERT_EQ(1, planeLayouts.size());
+
+        const auto& planeLayout = planeLayouts.front();
+
+        ASSERT_EQ(4, planeLayout.components.size());
+
+        int64_t offsetInBitsR = -1;
+        int64_t offsetInBitsG = -1;
+        int64_t offsetInBitsB = -1;
+        int64_t offsetInBitsA = -1;
+
+        for (const auto& component : planeLayout.components) {
+            if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) {
+                continue;
+            }
+            EXPECT_EQ(8, component.sizeInBits);
+            if (component.type.value == gralloc4::PlaneLayoutComponentType_R.value) {
+                offsetInBitsR = component.offsetInBits;
+            }
+            if (component.type.value == gralloc4::PlaneLayoutComponentType_G.value) {
+                offsetInBitsG = component.offsetInBits;
+            }
+            if (component.type.value == gralloc4::PlaneLayoutComponentType_B.value) {
+                offsetInBitsB = component.offsetInBits;
+            }
+            if (component.type.value == gralloc4::PlaneLayoutComponentType_A.value) {
+                offsetInBitsA = component.offsetInBits;
+            }
+        }
+
+        EXPECT_EQ(0, offsetInBitsR);
+        EXPECT_EQ(8, offsetInBitsG);
+        EXPECT_EQ(16, offsetInBitsB);
+        EXPECT_EQ(24, offsetInBitsA);
+
+        EXPECT_EQ(0, planeLayout.offsetInBytes);
+        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);
+        EXPECT_LE(planeLayout.widthInSamples * planeLayout.heightInSamples * 4,
+                  planeLayout.totalSizeInBytes);
+        EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+        EXPECT_EQ(1, planeLayout.verticalSubsampling);
+    }
+
+    void verifyBufferDump(const IMapper::BufferDump& bufferDump,
+                          const native_handle_t* bufferHandle = nullptr) {
+        std::set<StandardMetadataType> foundMetadataTypes;
+
+        const std::vector<IMapper::MetadataDump> metadataDump = bufferDump.metadataDump;
+
+        for (const auto& dump : metadataDump) {
+            const auto& metadataType = dump.metadataType;
+            const auto& metadata = dump.metadata;
+
+            if (!gralloc4::isStandardMetadataType(metadataType)) {
+                continue;
+            }
+
+            StandardMetadataType type = gralloc4::getStandardMetadataTypeValue(metadataType);
+
+            if (sRequiredMetadataTypes.find(type) == sRequiredMetadataTypes.end()) {
+                continue;
+            }
+
+            ASSERT_EQ(foundMetadataTypes.find(type), foundMetadataTypes.end());
+            foundMetadataTypes.insert(type);
+
+            if (!bufferHandle) {
+                continue;
+            }
+
+            hidl_vec<uint8_t> metadataFromGet;
+            ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, metadataType, &metadataFromGet));
+
+            ASSERT_EQ(metadataFromGet, metadata);
+        }
+
+        EXPECT_EQ(sRequiredMetadataTypes, foundMetadataTypes);
+    }
+
+    void getAndroidYCbCr(const native_handle_t* bufferHandle, uint8_t* data,
+                         android_ycbcr* outYCbCr, int64_t* hSubsampling, int64_t* vSubsampling) {
+        hidl_vec<uint8_t> vec;
+        ASSERT_EQ(Error::NONE,
+                  mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+        std::vector<PlaneLayout> planeLayouts;
+        ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+        outYCbCr->y = nullptr;
+        outYCbCr->cb = nullptr;
+        outYCbCr->cr = nullptr;
+        outYCbCr->ystride = 0;
+        outYCbCr->cstride = 0;
+        outYCbCr->chroma_step = 0;
+
+        for (const auto& planeLayout : planeLayouts) {
+            for (const auto& planeLayoutComponent : planeLayout.components) {
+                if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
+                    continue;
+                }
+                ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+
+                uint8_t* tmpData =
+                        data + planeLayout.offsetInBytes + (planeLayoutComponent.offsetInBits / 8);
+                uint64_t sampleIncrementInBytes;
+
+                auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
+                switch (type) {
+                    case PlaneLayoutComponentType::Y:
+                        ASSERT_EQ(nullptr, outYCbCr->y);
+                        ASSERT_EQ(8, planeLayoutComponent.sizeInBits);
+                        ASSERT_EQ(8, planeLayout.sampleIncrementInBits);
+                        outYCbCr->y = tmpData;
+                        outYCbCr->ystride = planeLayout.strideInBytes;
+                        break;
+
+                    case PlaneLayoutComponentType::CB:
+                    case PlaneLayoutComponentType::CR:
+                        ASSERT_EQ(0, planeLayout.sampleIncrementInBits % 8);
+
+                        sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
+                        ASSERT_TRUE(sampleIncrementInBytes == 1 || sampleIncrementInBytes == 2);
+
+                        if (outYCbCr->cstride == 0 && outYCbCr->chroma_step == 0) {
+                            outYCbCr->cstride = planeLayout.strideInBytes;
+                            outYCbCr->chroma_step = sampleIncrementInBytes;
+                        } else {
+                            ASSERT_EQ(outYCbCr->cstride, planeLayout.strideInBytes);
+                            ASSERT_EQ(outYCbCr->chroma_step, sampleIncrementInBytes);
+                        }
+
+                        if (*hSubsampling == 0 && *vSubsampling == 0) {
+                            *hSubsampling = planeLayout.horizontalSubsampling;
+                            *vSubsampling = planeLayout.verticalSubsampling;
+                        } else {
+                            ASSERT_EQ(*hSubsampling, planeLayout.horizontalSubsampling);
+                            ASSERT_EQ(*vSubsampling, planeLayout.verticalSubsampling);
+                        }
+
+                        if (type == PlaneLayoutComponentType::CB) {
+                            ASSERT_EQ(nullptr, outYCbCr->cb);
+                            outYCbCr->cb = tmpData;
+                        } else {
+                            ASSERT_EQ(nullptr, outYCbCr->cr);
+                            outYCbCr->cr = tmpData;
+                        }
+                        break;
+                    default:
+                        break;
+                };
+            }
+        }
+
+        ASSERT_NE(nullptr, outYCbCr->y);
+        ASSERT_NE(nullptr, outYCbCr->cb);
+        ASSERT_NE(nullptr, outYCbCr->cr);
+    }
+
+    void fillRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes,
+                      uint32_t seed = 0) {
+        for (uint32_t y = 0; y < height; y++) {
+            memset(data, y + seed, widthInBytes);
+            data += strideInBytes;
+        }
+    }
+
+    void verifyRGBA8888(const native_handle_t* bufferHandle, const uint8_t* data, uint32_t height,
+                        size_t strideInBytes, size_t widthInBytes, uint32_t seed = 0) {
+        hidl_vec<uint8_t> vec;
+        ASSERT_EQ(Error::NONE,
+                  mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+        std::vector<PlaneLayout> planeLayouts;
+        ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+        verifyRGBA8888PlaneLayouts(planeLayouts);
+
+        for (uint32_t y = 0; y < height; y++) {
+            for (size_t i = 0; i < widthInBytes; i++) {
+                EXPECT_EQ(static_cast<uint8_t>(y + seed), data[i]);
+            }
+            data += strideInBytes;
+        }
+    }
+
+    void traverseYCbCr888Data(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+                              int64_t hSubsampling, int64_t vSubsampling,
+                              std::function<void(uint8_t*, uint8_t)> traverseFuncion) {
+        auto yData = static_cast<uint8_t*>(yCbCr.y);
+        auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+        auto crData = static_cast<uint8_t*>(yCbCr.cr);
+        auto yStride = yCbCr.ystride;
+        auto cStride = yCbCr.cstride;
+        auto chromaStep = yCbCr.chroma_step;
+
+        for (uint32_t y = 0; y < height; y++) {
+            for (uint32_t x = 0; x < width; x++) {
+                auto val = static_cast<uint8_t>(height * y + x);
+
+                traverseFuncion(yData + yStride * y + x, val);
+
+                if (y % vSubsampling == 0 && x % hSubsampling == 0) {
+                    uint32_t subSampleX = x / hSubsampling;
+                    uint32_t subSampleY = y / vSubsampling;
+                    const auto subSampleOffset = cStride * subSampleY + chromaStep * subSampleX;
+                    const auto subSampleVal =
+                            static_cast<uint8_t>(height * subSampleY + subSampleX);
+
+                    traverseFuncion(cbData + subSampleOffset, subSampleVal);
+                    traverseFuncion(crData + subSampleOffset, subSampleVal + 1);
+                }
+            }
+        }
+    }
+
+    void fillYCbCr888Data(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+                          int64_t hSubsampling, int64_t vSubsampling) {
+        traverseYCbCr888Data(yCbCr, width, height, hSubsampling, vSubsampling,
+                             [](auto address, auto fillingData) { *address = fillingData; });
+    }
+
+    void verifyYCbCr888Data(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+                            int64_t hSubsampling, int64_t vSubsampling) {
+        traverseYCbCr888Data(
+                yCbCr, width, height, hSubsampling, vSubsampling,
+                [](auto address, auto expectedData) { EXPECT_EQ(*address, expectedData); });
+    }
+
+    bool isEqual(float a, float b) { return abs(a - b) < 0.0001; }
+
+    std::unique_ptr<Gralloc> mGralloc;
+    IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
+    static const std::set<StandardMetadataType> sRequiredMetadataTypes;
+};
+
+const std::set<StandardMetadataType> GraphicsMapperHidlTest::sRequiredMetadataTypes{
+        StandardMetadataType::BUFFER_ID,
+        StandardMetadataType::NAME,
+        StandardMetadataType::WIDTH,
+        StandardMetadataType::HEIGHT,
+        StandardMetadataType::LAYER_COUNT,
+        StandardMetadataType::PIXEL_FORMAT_REQUESTED,
+        StandardMetadataType::PIXEL_FORMAT_FOURCC,
+        StandardMetadataType::PIXEL_FORMAT_MODIFIER,
+        StandardMetadataType::USAGE,
+        StandardMetadataType::ALLOCATION_SIZE,
+        StandardMetadataType::PROTECTED_CONTENT,
+        StandardMetadataType::COMPRESSION,
+        StandardMetadataType::INTERLACED,
+        StandardMetadataType::CHROMA_SITING,
+        StandardMetadataType::PLANE_LAYOUTS,
+        StandardMetadataType::DATASPACE,
+        StandardMetadataType::BLEND_MODE,
+};
+
+/**
+ * Test IAllocator::allocate with valid buffer descriptors.
+ */
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
+    BufferDescriptor descriptor;
+    ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
+
+    for (uint32_t count = 0; count < 5; count++) {
+        std::vector<const native_handle_t*> bufferHandles;
+        uint32_t stride;
+        ASSERT_NO_FATAL_FAILURE(bufferHandles =
+                                        mGralloc->allocate(descriptor, count, false,
+                                                           Tolerance::kToleranceStrict, &stride));
+
+        if (count >= 1) {
+            EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride";
+        }
+
+        for (auto bufferHandle : bufferHandles) {
+            mGralloc->freeBuffer(bufferHandle);
+        }
+    }
+}
+
+/**
+ * Test IAllocator::allocate with invalid buffer descriptors.
+ */
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
+    // this assumes any valid descriptor is non-empty
+    BufferDescriptor descriptor;
+    mGralloc->getAllocator()->allocate(descriptor, 1,
+                                       [&](const auto& tmpError, const auto&, const auto&) {
+                                           EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
+                                       });
+}
+
+/**
+ * Test IAllocator::allocate does not leak.
+ */
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
+    auto info = mDummyDescriptorInfo;
+    info.width = 1024;
+    info.height = 1024;
+
+    for (int i = 0; i < 2048; i++) {
+        auto bufferHandle = mGralloc->allocate(info, false);
+        mGralloc->freeBuffer(bufferHandle);
+    }
+}
+
+/**
+ * Test that IAllocator::allocate is thread-safe.
+ */
+TEST_P(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
+    BufferDescriptor descriptor;
+    ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
+
+    std::atomic<bool> timeUp(false);
+    std::atomic<uint64_t> allocationCount(0);
+    auto threadLoop = [&]() {
+        while (!timeUp) {
+            mGralloc->getAllocator()->allocate(
+                    descriptor, 1,
+                    [&](const auto&, const auto&, const auto&) { allocationCount++; });
+        }
+    };
+
+    std::vector<std::thread> threads;
+    for (int i = 0; i < 8; i++) {
+        threads.push_back(std::thread(threadLoop));
+    }
+
+    std::this_thread::sleep_for(std::chrono::seconds(3));
+    timeUp = true;
+    LOG(VERBOSE) << "Made " << allocationCount << " threaded allocations";
+
+    for (auto& thread : threads) {
+        thread.join();
+    }
+}
+
+/**
+ * Test IMapper::createDescriptor with valid descriptor info.
+ */
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorBasic) {
+    ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
+}
+
+/**
+ * Test IMapper::createDescriptor with invalid descriptor info.
+ */
+TEST_P(GraphicsMapperHidlTest, CreateDescriptorNegative) {
+    auto info = mDummyDescriptorInfo;
+    info.width = 0;
+    mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_VALUE, tmpError) << "createDescriptor did not fail with BAD_VALUE";
+    });
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
+ */
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
+    const native_handle_t* bufferHandle;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
+ */
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferClone) {
+    const native_handle_t* clonedBufferHandle;
+    ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+
+    // A cloned handle is a raw handle. Check that we can import it multiple
+    // times.
+    const native_handle_t* importedBufferHandles[2];
+    ASSERT_NO_FATAL_FAILURE(importedBufferHandles[0] = mGralloc->importBuffer(clonedBufferHandle));
+    ASSERT_NO_FATAL_FAILURE(importedBufferHandles[1] = mGralloc->importBuffer(clonedBufferHandle));
+    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[0]));
+    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[1]));
+
+    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(clonedBufferHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
+ */
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
+    const native_handle_t* rawHandle;
+    ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+
+    native_handle_t* importedHandle = nullptr;
+    mGralloc->getMapper()->importBuffer(rawHandle, [&](const auto& tmpError, const auto& buffer) {
+        ASSERT_EQ(Error::NONE, tmpError);
+        importedHandle = static_cast<native_handle_t*>(buffer);
+    });
+
+    // free the imported handle with another mapper
+    std::unique_ptr<Gralloc> anotherGralloc;
+    ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+                                                                       std::get<1>(GetParam())));
+    Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
+    ASSERT_EQ(Error::NONE, error);
+
+    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
+ */
+TEST_P(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
+    auto info = mDummyDescriptorInfo;
+    info.width = 1024;
+    info.height = 1024;
+
+    for (int i = 0; i < 2048; i++) {
+        auto bufferHandle = mGralloc->allocate(info, true);
+        mGralloc->freeBuffer(bufferHandle);
+    }
+}
+
+/**
+ * Test IMapper::importBuffer with invalid buffers.
+ */
+TEST_P(GraphicsMapperHidlTest, ImportBufferNegative) {
+    native_handle_t* invalidHandle = nullptr;
+    mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+                << "importBuffer with nullptr did not fail with BAD_BUFFER";
+    });
+
+    invalidHandle = native_handle_create(0, 0);
+    mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+                << "importBuffer with invalid handle did not fail with BAD_BUFFER";
+    });
+    native_handle_delete(invalidHandle);
+}
+
+/**
+ * Test IMapper::freeBuffer with invalid buffers.
+ */
+TEST_P(GraphicsMapperHidlTest, FreeBufferNegative) {
+    native_handle_t* invalidHandle = nullptr;
+    Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+    EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER";
+
+    invalidHandle = native_handle_create(0, 0);
+    error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+    EXPECT_EQ(Error::BAD_BUFFER, error)
+            << "freeBuffer with invalid handle did not fail with BAD_BUFFER";
+    native_handle_delete(invalidHandle);
+
+    const native_handle_t* clonedBufferHandle;
+    ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+    error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+    EXPECT_EQ(Error::BAD_BUFFER, error)
+            << "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
+
+    mGralloc->freeBuffer(clonedBufferHandle);
+}
+
+/**
+ * Test IMapper::lock and IMapper::unlock.
+ */
+TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) {
+    const auto& info = mDummyDescriptorInfo;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(
+            bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
+
+    // lock buffer for writing
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+    uint8_t* data;
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+                                                                        region, fence.release())));
+
+    // RGBA_8888
+    fillRGBA8888(data, info.height, stride * 4, info.width * 4);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+                                                                        region, fence.release())));
+
+    ASSERT_NO_FATAL_FAILURE(
+            verifyRGBA8888(bufferHandle, data, info.height, stride * 4, info.width * 4));
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
+/**
+ *  Test multiple operations associated with different color formats
+ */
+TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::YCRCB_420_SP;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(
+                                    info, true, Tolerance::kToleranceUnSupported, &stride));
+    if (bufferHandle == nullptr) {
+        GTEST_SUCCEED() << "YCRCB_420_SP format is unsupported";
+        return;
+    }
+
+    // lock buffer for writing
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+    uint8_t* data;
+
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+                                                                        region, fence.release())));
+
+    android_ycbcr yCbCr;
+    int64_t hSubsampling = 0;
+    int64_t vSubsampling = 0;
+    ASSERT_NO_FATAL_FAILURE(
+            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+    ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+    auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+    auto crData = static_cast<uint8_t*>(yCbCr.cr);
+    ASSERT_EQ(crData + 1, cbData);
+    ASSERT_EQ(2, yCbCr.chroma_step);
+
+    fillYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+                                                                        region, fence.release())));
+
+    ASSERT_NO_FATAL_FAILURE(
+            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    verifyYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
+TEST_P(GraphicsMapperHidlTest, YV12SubsampleMetadata) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::YV12;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(
+            bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
+
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+    ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release()));
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+    std::vector<PlaneLayout> planeLayouts;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+    ASSERT_EQ(3, planeLayouts.size());
+
+    auto yPlane = planeLayouts[0];
+    auto crPlane = planeLayouts[1];
+    auto cbPlane = planeLayouts[2];
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    EXPECT_EQ(kCbCrSubSampleFactor, crPlane.horizontalSubsampling);
+    EXPECT_EQ(kCbCrSubSampleFactor, crPlane.verticalSubsampling);
+
+    EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.horizontalSubsampling);
+    EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.verticalSubsampling);
+
+    const long chromaSampleWidth = info.width / kCbCrSubSampleFactor;
+    const long chromaSampleHeight = info.height / kCbCrSubSampleFactor;
+
+    EXPECT_EQ(info.width, yPlane.widthInSamples);
+    EXPECT_EQ(info.height, yPlane.heightInSamples);
+
+    EXPECT_EQ(chromaSampleWidth, crPlane.widthInSamples);
+    EXPECT_EQ(chromaSampleHeight, crPlane.heightInSamples);
+
+    EXPECT_EQ(chromaSampleWidth, cbPlane.widthInSamples);
+    EXPECT_EQ(chromaSampleHeight, cbPlane.heightInSamples);
+
+    EXPECT_LE(crPlane.widthInSamples, crPlane.strideInBytes);
+    EXPECT_LE(cbPlane.widthInSamples, cbPlane.strideInBytes);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
+TEST_P(GraphicsMapperHidlTest, Lock_YV12) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::YV12;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(
+            bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
+
+    // lock buffer for writing
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+    uint8_t* data;
+
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+                                                                        region, fence.release())));
+
+    android_ycbcr yCbCr;
+    int64_t hSubsampling = 0;
+    int64_t vSubsampling = 0;
+    ASSERT_NO_FATAL_FAILURE(
+            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+    ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+    auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+    auto crData = static_cast<uint8_t*>(yCbCr.cr);
+    ASSERT_EQ(crData + yCbCr.cstride * info.height / vSubsampling, cbData);
+    ASSERT_EQ(1, yCbCr.chroma_step);
+
+    fillYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+                                                                        region, fence.release())));
+
+    ASSERT_NO_FATAL_FAILURE(
+            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    verifyYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
+TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::YCBCR_420_888;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(
+            bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
+
+    // lock buffer for writing
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+    uint8_t* data;
+
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+                                                                        region, fence.release())));
+
+    android_ycbcr yCbCr;
+    int64_t hSubsampling = 0;
+    int64_t vSubsampling = 0;
+    ASSERT_NO_FATAL_FAILURE(
+            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    constexpr uint32_t kCbCrSubSampleFactor = 2;
+    ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+    ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+    fillYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+                                                                        region, fence.release())));
+
+    ASSERT_NO_FATAL_FAILURE(
+            getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+    verifyYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
+TEST_P(GraphicsMapperHidlTest, Lock_RAW10) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::RAW10;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(
+                                    info, true, Tolerance::kToleranceUnSupported, &stride));
+    if (bufferHandle == nullptr) {
+        GTEST_SUCCEED() << "RAW10 format is unsupported";
+        return;
+    }
+
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+
+    ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release()));
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+    std::vector<PlaneLayout> planeLayouts;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+    ASSERT_EQ(1, planeLayouts.size());
+    auto planeLayout = planeLayouts[0];
+
+    EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
+    EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+    EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+    ASSERT_EQ(1, planeLayout.components.size());
+    auto planeLayoutComponent = planeLayout.components[0];
+
+    EXPECT_EQ(PlaneLayoutComponentType::RAW,
+              static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
+    EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+    EXPECT_EQ(-1, planeLayoutComponent.sizeInBits);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
+TEST_P(GraphicsMapperHidlTest, Lock_RAW12) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::RAW12;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(
+                                    info, true, Tolerance::kToleranceUnSupported, &stride));
+    if (bufferHandle == nullptr) {
+        GTEST_SUCCEED() << "RAW12 format is unsupported";
+        return;
+    }
+
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+
+    ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release()));
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+    std::vector<PlaneLayout> planeLayouts;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+    ASSERT_EQ(1, planeLayouts.size());
+    auto planeLayout = planeLayouts[0];
+
+    EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
+    EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+    EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+    ASSERT_EQ(1, planeLayout.components.size());
+    auto planeLayoutComponent = planeLayout.components[0];
+
+    EXPECT_EQ(PlaneLayoutComponentType::RAW,
+              static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
+    EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+    EXPECT_EQ(-1, planeLayoutComponent.sizeInBits);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
+/**
+ * Test IMapper::unlock with bad access region
+ */
+TEST_P(GraphicsMapperHidlTest, LockBadAccessRegion) {
+    const auto& info = mDummyDescriptorInfo;
+
+    const native_handle_t* bufferHandle;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));
+
+    const IMapper::Rect accessRegion{0, 0, static_cast<int32_t>(info.width * 2),
+                                     static_cast<int32_t>(info.height * 2)};
+    int acquireFence = -1;
+
+    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+    hidl_handle acquireFenceHandle;
+    if (acquireFence >= 0) {
+        auto h = native_handle_init(acquireFenceStorage, 1, 0);
+        h->data[0] = acquireFence;
+        acquireFenceHandle = h;
+    }
+
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    mGralloc->getMapper()->lock(buffer, info.usage, accessRegion, acquireFenceHandle,
+                                [&](const auto& tmpError, const auto& /*tmpData*/) {
+                                    EXPECT_EQ(Error::BAD_VALUE, tmpError)
+                                            << "locking with a bad access region should fail";
+                                });
+
+    if (::testing::Test::HasFailure()) {
+        if (acquireFence >= 0) {
+            close(acquireFence);
+        }
+
+        int releaseFence = -1;
+        ASSERT_NO_FATAL_FAILURE(releaseFence = mGralloc->unlock(bufferHandle));
+
+        if (releaseFence >= 0) {
+            close(releaseFence);
+        }
+    }
+}
+
+/**
+ * Test IMapper::unlock with invalid buffers.
+ */
+TEST_P(GraphicsMapperHidlTest, UnlockNegative) {
+    native_handle_t* invalidHandle = nullptr;
+    mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+                << "unlock with nullptr did not fail with BAD_BUFFER";
+    });
+
+    invalidHandle = native_handle_create(0, 0);
+    mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+                << "unlock with invalid handle did not fail with BAD_BUFFER";
+    });
+    native_handle_delete(invalidHandle);
+
+    ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
+                                    mGralloc->allocate(mDummyDescriptorInfo, false)));
+    mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+                << "unlock with un-imported handle did not fail with BAD_BUFFER";
+    });
+    mGralloc->freeBuffer(invalidHandle);
+
+// disabled as it fails on many existing drivers
+#if 0
+  ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
+                              mGralloc->allocate(mDummyDescriptorInfo, true)));
+  mGralloc->getMapper()->unlock(
+      invalidHandle, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+            << "unlock with unlocked handle did not fail with BAD_BUFFER";
+      });
+  mGralloc->freeBuffer(invalidHandle);
+#endif
+}
+
+/**
+ * Test IMapper::flush and IMapper::reread.
+ */
+TEST_P(GraphicsMapperHidlTest, FlushRereadBasic) {
+    const auto& info = mDummyDescriptorInfo;
+
+    const native_handle_t* rawHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false,
+                                                           Tolerance::kToleranceStrict, &stride));
+
+    const native_handle_t* writeBufferHandle;
+    const native_handle_t* readBufferHandle;
+    ASSERT_NO_FATAL_FAILURE(writeBufferHandle = mGralloc->importBuffer(rawHandle));
+    ASSERT_NO_FATAL_FAILURE(readBufferHandle = mGralloc->importBuffer(rawHandle));
+
+    // lock buffer for writing
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    uint8_t* writeData;
+    ASSERT_NO_FATAL_FAILURE(
+            writeData = static_cast<uint8_t*>(mGralloc->lock(
+                    writeBufferHandle, static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN), region,
+                    -1)));
+
+    uint8_t* readData;
+    ASSERT_NO_FATAL_FAILURE(
+            readData = static_cast<uint8_t*>(mGralloc->lock(
+                    readBufferHandle, static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN), region,
+                    -1)));
+
+    fillRGBA8888(writeData, info.height, stride * 4, info.width * 4);
+
+    unique_fd fence;
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->flushLockedBuffer(writeBufferHandle)));
+    if (fence >= 0) {
+        ASSERT_EQ(0, sync_wait(fence, 3500));
+    }
+
+    ASSERT_NO_FATAL_FAILURE(mGralloc->rereadLockedBuffer(readBufferHandle));
+
+    ASSERT_NO_FATAL_FAILURE(
+            verifyRGBA8888(readBufferHandle, readData, info.height, stride * 4, info.width * 4));
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(readBufferHandle)));
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(writeBufferHandle)));
+}
+
+/**
+ * Test IMapper::flushLockedBuffer with bad buffer
+ */
+TEST_P(GraphicsMapperHidlTest, FlushLockedBufferBadBuffer) {
+    ASSERT_NO_FATAL_FAILURE(mGralloc->getMapper()->flushLockedBuffer(
+            nullptr, [&](const auto& tmpError, const auto& /*tmpReleaseFence*/) {
+                ASSERT_EQ(Error::BAD_BUFFER, tmpError);
+            }));
+}
+
+/**
+ * Test IMapper::rereadLockedBuffer with bad buffer
+ */
+TEST_P(GraphicsMapperHidlTest, RereadLockedBufferBadBuffer) {
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->getMapper()->rereadLockedBuffer(nullptr));
+}
+
+/**
+ * Test IMapper::isSupported with required format RGBA_8888
+ */
+TEST_P(GraphicsMapperHidlTest, IsSupportedRGBA8888) {
+    const auto& info = mDummyDescriptorInfo;
+    bool supported = false;
+
+    ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+    ASSERT_TRUE(supported);
+}
+
+/**
+ * Test IMapper::isSupported with required format YV12
+ */
+TEST_P(GraphicsMapperHidlTest, IsSupportedYV12) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::YV12;
+    bool supported = false;
+
+    ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+    ASSERT_TRUE(supported);
+}
+
+/**
+ * Test IMapper::isSupported with optional format Y16
+ */
+TEST_P(GraphicsMapperHidlTest, IsSupportedY16) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::Y16;
+    bool supported = false;
+
+    ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+}
+
+/**
+ * Test IMapper::get(BufferId)
+ */
+TEST_P(GraphicsMapperHidlTest, GetBufferId) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BufferId,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint64_t bufferId = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeBufferId(vec, &bufferId));
+            });
+}
+
+/**
+ * Test IMapper::get(Name)
+ */
+TEST_P(GraphicsMapperHidlTest, GetName) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Name,
+            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+                std::string name;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeName(vec, &name));
+                EXPECT_EQ(info.name, name);
+            });
+}
+
+/**
+ * Test IMapper::get(Width)
+ */
+TEST_P(GraphicsMapperHidlTest, GetWidth) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Width,
+            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+                uint64_t width = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeWidth(vec, &width));
+                EXPECT_EQ(info.width, width);
+            });
+}
+
+/**
+ * Test IMapper::get(Height)
+ */
+TEST_P(GraphicsMapperHidlTest, GetHeight) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Height,
+            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+                uint64_t height = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeHeight(vec, &height));
+                EXPECT_EQ(info.height, height);
+            });
+}
+
+/**
+ * Test IMapper::get(LayerCount)
+ */
+TEST_P(GraphicsMapperHidlTest, GetLayerCount) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_LayerCount,
+            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+                uint64_t layerCount = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeLayerCount(vec, &layerCount));
+                EXPECT_EQ(info.layerCount, layerCount);
+            });
+}
+
+/**
+ * Test IMapper::get(PixelFormatRequested)
+ */
+TEST_P(GraphicsMapperHidlTest, GetPixelFormatRequested) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatRequested,
+            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+                PixelFormat pixelFormatRequested = PixelFormat::BLOB;
+                ASSERT_EQ(NO_ERROR,
+                          gralloc4::decodePixelFormatRequested(vec, &pixelFormatRequested));
+                EXPECT_EQ(info.format, pixelFormatRequested);
+            });
+}
+
+/**
+ * Test IMapper::get(PixelFormatFourCC)
+ */
+TEST_P(GraphicsMapperHidlTest, GetPixelFormatFourCC) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint32_t pixelFormatFourCC = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &pixelFormatFourCC));
+            });
+}
+
+/**
+ * Test IMapper::get(PixelFormatModifier)
+ */
+TEST_P(GraphicsMapperHidlTest, GetPixelFormatModifier) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint64_t pixelFormatModifier = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, &pixelFormatModifier));
+            });
+}
+
+/**
+ * Test IMapper::get(Usage)
+ */
+TEST_P(GraphicsMapperHidlTest, GetUsage) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage,
+            [](const IMapper::BufferDescriptorInfo& info, const hidl_vec<uint8_t>& vec) {
+                uint64_t usage = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &usage));
+                EXPECT_EQ(info.usage, usage);
+            });
+}
+
+/**
+ * Test IMapper::get(AllocationSize)
+ */
+TEST_P(GraphicsMapperHidlTest, GetAllocationSize) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint64_t allocationSize = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &allocationSize));
+            });
+}
+
+/**
+ * Test IMapper::get(ProtectedContent)
+ */
+TEST_P(GraphicsMapperHidlTest, GetProtectedContent) {
+    auto info = mDummyDescriptorInfo;
+    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+    const native_handle_t* bufferHandle = nullptr;
+    bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceAllErrors);
+    if (!bufferHandle) {
+        GTEST_SUCCEED() << "unable to allocate protected content";
+        return;
+    }
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec));
+
+    uint64_t protectedContent = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &protectedContent));
+    EXPECT_EQ(1, protectedContent);
+}
+
+/**
+ * Test IMapper::get(Compression)
+ */
+TEST_P(GraphicsMapperHidlTest, GetCompression) {
+    auto info = mDummyDescriptorInfo;
+    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+    testGet(info, gralloc4::MetadataType_Compression,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                ExtendableType compression = gralloc4::Compression_DisplayStreamCompression;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &compression));
+
+                EXPECT_EQ(gralloc4::Compression_None.name, compression.name);
+                EXPECT_EQ(gralloc4::Compression_None.value, compression.value);
+            });
+}
+
+/**
+ * Test IMapper::get(Interlaced)
+ */
+TEST_P(GraphicsMapperHidlTest, GetInterlaced) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                ExtendableType interlaced = gralloc4::Interlaced_TopBottom;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &interlaced));
+
+                EXPECT_EQ(gralloc4::Interlaced_None.name, interlaced.name);
+                EXPECT_EQ(gralloc4::Interlaced_None.value, interlaced.value);
+            });
+}
+
+/**
+ * Test IMapper::get(ChromaSiting)
+ */
+TEST_P(GraphicsMapperHidlTest, GetChromaSiting) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_ChromaSiting,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                ExtendableType chromaSiting = gralloc4::ChromaSiting_Unknown;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &chromaSiting));
+
+                EXPECT_EQ(gralloc4::ChromaSiting_None.name, chromaSiting.name);
+                EXPECT_EQ(gralloc4::ChromaSiting_None.value, chromaSiting.value);
+            });
+}
+
+/**
+ * Test IMapper::get(PlaneLayouts)
+ */
+TEST_P(GraphicsMapperHidlTest, GetPlaneLayouts) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+
+    std::vector<PlaneLayout> planeLayouts;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+    ASSERT_NO_FATAL_FAILURE(verifyRGBA8888PlaneLayouts(planeLayouts));
+}
+
+/**
+ * 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) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                Dataspace dataspace = Dataspace::DISPLAY_P3;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &dataspace));
+                EXPECT_EQ(Dataspace::UNKNOWN, dataspace);
+            });
+}
+
+/**
+ * Test IMapper::get(BlendMode)
+ */
+TEST_P(GraphicsMapperHidlTest, GetBlendMode) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                BlendMode blendMode = BlendMode::NONE;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &blendMode));
+                EXPECT_EQ(BlendMode::INVALID, blendMode);
+            });
+}
+
+/**
+ * Test IMapper::get(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, GetSmpte2086) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<Smpte2086> smpte2086;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086));
+                EXPECT_FALSE(smpte2086.has_value());
+            });
+}
+
+/**
+ * Test IMapper::get(Cta861_3)
+ */
+TEST_P(GraphicsMapperHidlTest, GetCta861_3) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<Cta861_3> cta861_3;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3));
+                EXPECT_FALSE(cta861_3.has_value());
+            });
+}
+
+/**
+ * Test IMapper::get(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, GetSmpte2094_40) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<std::vector<uint8_t>> smpte2094_40;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40));
+                EXPECT_FALSE(smpte2094_40.has_value());
+            });
+}
+
+/**
+ * Test IMapper::get(metadata) with a bad buffer
+ */
+TEST_P(GraphicsMapperHidlTest, GetMetadataBadValue) {
+    const native_handle_t* bufferHandle = nullptr;
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_BufferId, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Name, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Width, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Height, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_LayerCount, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->get(bufferHandle, gralloc4::MetadataType_Usage, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_AllocationSize, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_Compression, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_Interlaced, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_ChromaSiting, &vec));
+    ASSERT_EQ(0, vec.size());
+    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());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2086, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_Cta861_3, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, &vec));
+    ASSERT_EQ(0, vec.size());
+}
+
+/**
+ * Test IMapper::get(metadata) for unsupported metadata
+ */
+TEST_P(GraphicsMapperHidlTest, GetUnsupportedMetadata) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+    MetadataType metadataTypeFake = {"FAKE", 1};
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->get(bufferHandle, metadataTypeFake, &vec));
+    ASSERT_EQ(0, vec.size());
+}
+
+/**
+ * Test IMapper::get(metadata) for unsupported standard metadata
+ */
+TEST_P(GraphicsMapperHidlTest, GetUnsupportedStandardMetadata) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+    MetadataType metadataTypeFake = {GRALLOC4_STANDARD_METADATA_TYPE, 9999};
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->get(bufferHandle, metadataTypeFake, &vec));
+    ASSERT_EQ(0, vec.size());
+}
+
+/**
+ * Test IMapper::set(PixelFormatFourCC)
+ */
+TEST_P(GraphicsMapperHidlTest, SetPixelFormatFourCC) {
+    uint32_t pixelFormatFourCC = 0x34324142;  // DRM_FORMAT_BGRA8888
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatFourCC(pixelFormatFourCC, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint32_t realPixelFormatFourCC = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &realPixelFormatFourCC));
+                EXPECT_EQ(pixelFormatFourCC, realPixelFormatFourCC);
+            });
+}
+
+/**
+ * Test IMapper::set(PixelFormatModifier)
+ */
+TEST_P(GraphicsMapperHidlTest, SetPixelFormatModifier) {
+    uint64_t pixelFormatModifier = 10;
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatModifier(pixelFormatModifier, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint64_t realPixelFormatModifier = 0;
+                ASSERT_EQ(NO_ERROR,
+                          gralloc4::decodePixelFormatModifier(vec, &realPixelFormatModifier));
+                EXPECT_EQ(pixelFormatModifier, realPixelFormatModifier);
+            });
+}
+
+/**
+ * Test IMapper::set(AllocationSize)
+ */
+TEST_P(GraphicsMapperHidlTest, SetAllocationSize) {
+    uint64_t allocationSize = 1000000;
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeAllocationSize(allocationSize, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_AllocationSize, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint64_t realAllocationSize = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &realAllocationSize));
+                EXPECT_EQ(allocationSize, realAllocationSize);
+            });
+}
+
+/**
+ * Test IMapper::set(ProtectedContent)
+ */
+TEST_P(GraphicsMapperHidlTest, SetProtectedContent) {
+    const native_handle_t* bufferHandle = nullptr;
+    auto info = mDummyDescriptorInfo;
+    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+    bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceAllErrors);
+    if (!bufferHandle) {
+        GTEST_SUCCEED() << "unable to allocate protected content";
+        return;
+    }
+
+    uint64_t protectedContent = 0;
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeProtectedContent(protectedContent, &vec));
+
+    Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec);
+    ASSERT_EQ(err, Error::UNSUPPORTED);
+    vec.resize(0);
+
+    uint64_t realProtectedContent = 0;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_ProtectedContent, &vec));
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &realProtectedContent));
+    EXPECT_EQ(1, realProtectedContent);
+}
+
+/**
+ * Test IMapper::set(Compression)
+ */
+TEST_P(GraphicsMapperHidlTest, SetCompression) {
+    auto info = mDummyDescriptorInfo;
+    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+    ExtendableType compression = gralloc4::Compression_DisplayStreamCompression;
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeCompression(compression, &vec));
+
+    testSet(info, gralloc4::MetadataType_Compression, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                ExtendableType realCompression = gralloc4::Compression_None;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &realCompression));
+
+                EXPECT_EQ(compression.name, realCompression.name);
+                EXPECT_EQ(compression.value, realCompression.value);
+            });
+}
+
+/**
+ * Test IMapper::set(Interlaced)
+ */
+TEST_P(GraphicsMapperHidlTest, SetInterlaced) {
+    ExtendableType interlaced = gralloc4::Interlaced_RightLeft;
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeInterlaced(interlaced, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                ExtendableType realInterlaced = gralloc4::Interlaced_None;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &realInterlaced));
+
+                EXPECT_EQ(interlaced.name, realInterlaced.name);
+                EXPECT_EQ(interlaced.value, realInterlaced.value);
+            });
+}
+
+/**
+ * Test IMapper::set(ChromaSiting)
+ */
+TEST_P(GraphicsMapperHidlTest, SetChromaSiting) {
+    ExtendableType chromaSiting = gralloc4::ChromaSiting_SitedInterstitial;
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeChromaSiting(chromaSiting, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_ChromaSiting, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                ExtendableType realChromaSiting = gralloc4::ChromaSiting_None;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &realChromaSiting));
+
+                EXPECT_EQ(chromaSiting.name, realChromaSiting.name);
+                EXPECT_EQ(chromaSiting.value, realChromaSiting.value);
+            });
+}
+
+/**
+ * Test IMapper::set(PlaneLayouts)
+ */
+TEST_P(GraphicsMapperHidlTest, SetPlaneLayouts) {
+    const native_handle_t* bufferHandle = nullptr;
+    auto info = mDummyDescriptorInfo;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));
+
+    std::vector<PlaneLayout> planeLayouts;
+    PlaneLayout planeLayoutA;
+    PlaneLayout planeLayoutRGB;
+    PlaneLayoutComponent component;
+
+    planeLayoutA.offsetInBytes = 0;
+    planeLayoutA.sampleIncrementInBits = 8;
+    planeLayoutA.strideInBytes = info.width + 20;
+    planeLayoutA.widthInSamples = info.width;
+    planeLayoutA.heightInSamples = info.height;
+    planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * info.height;
+    planeLayoutA.horizontalSubsampling = 1;
+    planeLayoutA.verticalSubsampling = 1;
+
+    component.type = gralloc4::PlaneLayoutComponentType_A;
+    component.offsetInBits = 0;
+    component.sizeInBits = 8;
+    planeLayoutA.components.push_back(component);
+
+    planeLayouts.push_back(planeLayoutA);
+
+    planeLayoutRGB.offsetInBytes = 0;
+    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;
+
+    component.type = gralloc4::PlaneLayoutComponentType_R;
+    planeLayoutRGB.components.push_back(component);
+    component.type = gralloc4::PlaneLayoutComponentType_G;
+    planeLayoutRGB.components.push_back(component);
+    component.type = gralloc4::PlaneLayoutComponentType_B;
+    planeLayoutRGB.components.push_back(component);
+
+    planeLayouts.push_back(planeLayoutRGB);
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodePlaneLayouts(planeLayouts, &vec));
+
+    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);
+
+    std::vector<PlaneLayout> realPlaneLayouts;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &realPlaneLayouts));
+
+    ASSERT_EQ(planeLayouts.size(), realPlaneLayouts.size());
+
+    for (int i = 0; i < realPlaneLayouts.size(); i++) {
+        const auto& planeLayout = planeLayouts[i];
+        const auto& realPlaneLayout = realPlaneLayouts[i];
+
+        EXPECT_EQ(planeLayout.offsetInBytes, realPlaneLayout.offsetInBytes);
+        EXPECT_EQ(planeLayout.sampleIncrementInBits, realPlaneLayout.sampleIncrementInBits);
+        EXPECT_EQ(planeLayout.strideInBytes, realPlaneLayout.strideInBytes);
+        EXPECT_EQ(planeLayout.widthInSamples, realPlaneLayout.widthInSamples);
+        EXPECT_EQ(planeLayout.heightInSamples, realPlaneLayout.heightInSamples);
+        EXPECT_LE(planeLayout.totalSizeInBytes, realPlaneLayout.totalSizeInBytes);
+        EXPECT_EQ(planeLayout.horizontalSubsampling, realPlaneLayout.horizontalSubsampling);
+        EXPECT_EQ(planeLayout.verticalSubsampling, realPlaneLayout.verticalSubsampling);
+
+        ASSERT_EQ(planeLayout.components.size(), realPlaneLayout.components.size());
+
+        for (int j = 0; j < realPlaneLayout.components.size(); j++) {
+            const auto& component = planeLayout.components[j];
+            const auto& realComponent = realPlaneLayout.components[j];
+
+            EXPECT_EQ(component.type.name, realComponent.type.name);
+            EXPECT_EQ(component.type.value, realComponent.type.value);
+            EXPECT_EQ(component.sizeInBits, realComponent.sizeInBits);
+            EXPECT_EQ(component.offsetInBits, realComponent.offsetInBits);
+        }
+    }
+}
+
+/**
+ * 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) {
+    Dataspace dataspace = Dataspace::SRGB_LINEAR;
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                Dataspace realDataspace = Dataspace::UNKNOWN;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &realDataspace));
+                EXPECT_EQ(dataspace, realDataspace);
+            });
+}
+
+/**
+ * Test IMapper::set(BlendMode)
+ */
+TEST_P(GraphicsMapperHidlTest, SetBlendMode) {
+    BlendMode blendMode = BlendMode::PREMULTIPLIED;
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeBlendMode(blendMode, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                BlendMode realBlendMode = BlendMode::INVALID;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &realBlendMode));
+                EXPECT_EQ(blendMode, realBlendMode);
+            });
+}
+
+/**
+ * Test IMapper::set(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, SetSmpte2086) {
+    /**
+     * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
+     * the D65 white point and the SRGB transfer functions.
+     * Rendering Intent: Colorimetric
+     * Primaries:
+     *                  x       y
+     *  green           0.265   0.690
+     *  blue            0.150   0.060
+     *  red             0.680   0.320
+     *  white (D65)     0.3127  0.3290
+     */
+    Smpte2086 smpte2086;
+    smpte2086.primaryRed.x = 0.680;
+    smpte2086.primaryRed.y = 0.320;
+    smpte2086.primaryGreen.x = 0.265;
+    smpte2086.primaryGreen.y = 0.690;
+    smpte2086.primaryBlue.x = 0.150;
+    smpte2086.primaryBlue.y = 0.060;
+    smpte2086.whitePoint.x = 0.3127;
+    smpte2086.whitePoint.y = 0.3290;
+    smpte2086.maxLuminance = 100.0;
+    smpte2086.minLuminance = 0.1;
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(smpte2086, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<Smpte2086> realSmpte2086;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &realSmpte2086));
+                ASSERT_TRUE(realSmpte2086.has_value());
+                EXPECT_TRUE(isEqual(smpte2086.primaryRed.x, realSmpte2086->primaryRed.x));
+                EXPECT_TRUE(isEqual(smpte2086.primaryRed.y, realSmpte2086->primaryRed.y));
+                EXPECT_TRUE(isEqual(smpte2086.primaryGreen.x, realSmpte2086->primaryGreen.x));
+                EXPECT_TRUE(isEqual(smpte2086.primaryGreen.y, realSmpte2086->primaryGreen.y));
+                EXPECT_TRUE(isEqual(smpte2086.primaryBlue.x, realSmpte2086->primaryBlue.x));
+                EXPECT_TRUE(isEqual(smpte2086.primaryBlue.y, realSmpte2086->primaryBlue.y));
+                EXPECT_TRUE(isEqual(smpte2086.whitePoint.x, realSmpte2086->whitePoint.x));
+                EXPECT_TRUE(isEqual(smpte2086.whitePoint.y, realSmpte2086->whitePoint.y));
+                EXPECT_TRUE(isEqual(smpte2086.maxLuminance, realSmpte2086->maxLuminance));
+                EXPECT_TRUE(isEqual(smpte2086.minLuminance, realSmpte2086->minLuminance));
+            });
+}
+
+/**
+ * Test IMapper::set(Cta8613)
+ */
+TEST_P(GraphicsMapperHidlTest, SetCta861_3) {
+    Cta861_3 cta861_3;
+    cta861_3.maxContentLightLevel = 78.0;
+    cta861_3.maxFrameAverageLightLevel = 62.0;
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(cta861_3, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<Cta861_3> realCta861_3;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &realCta861_3));
+                ASSERT_TRUE(realCta861_3.has_value());
+                EXPECT_TRUE(
+                        isEqual(cta861_3.maxContentLightLevel, realCta861_3->maxContentLightLevel));
+                EXPECT_TRUE(isEqual(cta861_3.maxFrameAverageLightLevel,
+                                    realCta861_3->maxFrameAverageLightLevel));
+            });
+}
+
+/**
+ * Test IMapper::set(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, SetSmpte2094_40) {
+    hidl_vec<uint8_t> vec;
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<std::vector<uint8_t>> realSmpte2094_40;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40));
+                EXPECT_FALSE(realSmpte2094_40.has_value());
+            });
+}
+
+/**
+ * Test IMapper::set(metadata) with a bad buffer
+ */
+TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) {
+    const native_handle_t* bufferHandle = nullptr;
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec));
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, vec));
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_AllocationSize, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Compression, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Interlaced, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              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,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, vec));
+}
+
+/**
+ * Test get::metadata with cloned native_handle
+ */
+TEST_P(GraphicsMapperHidlTest, GetMetadataClonedHandle) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+    const auto dataspace = Dataspace::SRGB_LINEAR;
+    {
+        hidl_vec<uint8_t> metadata;
+        ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &metadata));
+
+        Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, metadata);
+        if (err == Error::UNSUPPORTED) {
+            GTEST_SUCCEED() << "setting this metadata is unsupported";
+            return;
+        }
+        ASSERT_EQ(Error::NONE, err);
+    }
+
+    const native_handle_t* importedHandle;
+    {
+        auto clonedHandle = native_handle_clone(bufferHandle);
+        ASSERT_NO_FATAL_FAILURE(importedHandle = mGralloc->importBuffer(clonedHandle));
+        native_handle_close(clonedHandle);
+        native_handle_delete(clonedHandle);
+    }
+
+    Dataspace realSpace = Dataspace::UNKNOWN;
+    {
+        hidl_vec<uint8_t> metadata;
+        ASSERT_EQ(Error::NONE,
+                  mGralloc->get(importedHandle, gralloc4::MetadataType_Dataspace, &metadata));
+        ASSERT_NO_FATAL_FAILURE(gralloc4::decodeDataspace(metadata, &realSpace));
+    }
+
+    EXPECT_EQ(dataspace, realSpace);
+}
+
+/**
+ * Test set::metadata with cloned native_handle
+ */
+TEST_P(GraphicsMapperHidlTest, SetMetadataClonedHandle) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+    const native_handle_t* importedHandle;
+    {
+        auto clonedHandle = native_handle_clone(bufferHandle);
+        ASSERT_NO_FATAL_FAILURE(importedHandle = mGralloc->importBuffer(clonedHandle));
+        native_handle_close(clonedHandle);
+        native_handle_delete(clonedHandle);
+    }
+
+    const auto dataspace = Dataspace::SRGB_LINEAR;
+    {
+        hidl_vec<uint8_t> metadata;
+        ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &metadata));
+
+        Error err = mGralloc->set(importedHandle, gralloc4::MetadataType_Dataspace, metadata);
+        if (err == Error::UNSUPPORTED) {
+            GTEST_SUCCEED() << "setting this metadata is unsupported";
+            return;
+        }
+        ASSERT_EQ(Error::NONE, err);
+    }
+
+    Dataspace realSpace = Dataspace::UNKNOWN;
+    {
+        hidl_vec<uint8_t> metadata;
+        ASSERT_EQ(Error::NONE,
+                  mGralloc->get(bufferHandle, gralloc4::MetadataType_Dataspace, &metadata));
+        ASSERT_NO_FATAL_FAILURE(gralloc4::decodeDataspace(metadata, &realSpace));
+    }
+
+    EXPECT_EQ(dataspace, realSpace);
+}
+
+/**
+ * Test IMapper::set(metadata) for constant metadata
+ */
+TEST_P(GraphicsMapperHidlTest, SetConstantMetadata) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+    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_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_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));
+}
+
+/**
+ * Test IMapper::set(metadata) for bad metadata
+ */
+TEST_P(GraphicsMapperHidlTest, SetBadMetadata) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+    hidl_vec<uint8_t> 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_AllocationSize, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_ProtectedContent, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Compression, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Interlaced, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              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,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(BufferId)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBufferId) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                    gralloc4::MetadataType_BufferId, &vec));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Name)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoName) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Name, &vec));
+
+    std::string name;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeName(vec, &name));
+    EXPECT_EQ(mDummyDescriptorInfo.name, name);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Width)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoWidth) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Width, &vec));
+
+    uint64_t width = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeWidth(vec, &width));
+    EXPECT_EQ(mDummyDescriptorInfo.width, width);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Height)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoHeight) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Height, &vec));
+
+    uint64_t height = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeHeight(vec, &height));
+    EXPECT_EQ(mDummyDescriptorInfo.height, height);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(PixelFormatRequested)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatRequested) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getFromBufferDescriptorInfo(
+                      mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatRequested, &vec));
+
+    PixelFormat pixelFormatRequested = PixelFormat::BLOB;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatRequested(vec, &pixelFormatRequested));
+    EXPECT_EQ(mDummyDescriptorInfo.format, pixelFormatRequested);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(PixelFormatFourCC)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatFourCC) {
+    hidl_vec<uint8_t> vec;
+    Error err = mGralloc->getFromBufferDescriptorInfo(
+            mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatFourCC, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    uint32_t pixelFormatFourCC = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatFourCC(vec, &pixelFormatFourCC));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(PixelFormatModifier)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPixelFormatModifier) {
+    hidl_vec<uint8_t> vec;
+    Error err = mGralloc->getFromBufferDescriptorInfo(
+            mDummyDescriptorInfo, gralloc4::MetadataType_PixelFormatModifier, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    uint64_t pixelFormatModifier = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePixelFormatModifier(vec, &pixelFormatModifier));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Usage)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUsage) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Usage, &vec));
+
+    uint64_t usage = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &usage));
+    EXPECT_EQ(mDummyDescriptorInfo.usage, usage);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(AllocationSize)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoAllocationSize) {
+    hidl_vec<uint8_t> vec;
+    Error err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                      gralloc4::MetadataType_AllocationSize, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    uint64_t allocationSize = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeAllocationSize(vec, &allocationSize));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(ProtectedContent)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoProtectedContent) {
+    auto info = mDummyDescriptorInfo;
+    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+    hidl_vec<uint8_t> vec;
+    auto err = mGralloc->getFromBufferDescriptorInfo(info, gralloc4::MetadataType_ProtectedContent,
+                                                     &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    uint64_t protectedContent = 0;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeProtectedContent(vec, &protectedContent));
+    EXPECT_EQ(1, protectedContent);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Compression)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCompression) {
+    auto info = mDummyDescriptorInfo;
+    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+    hidl_vec<uint8_t> vec;
+    auto err =
+            mGralloc->getFromBufferDescriptorInfo(info, gralloc4::MetadataType_Compression, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    ExtendableType compression = gralloc4::Compression_DisplayStreamCompression;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeCompression(vec, &compression));
+
+    EXPECT_EQ(gralloc4::Compression_None.name, compression.name);
+    EXPECT_EQ(gralloc4::Compression_None.value, compression.value);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Interlaced)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) {
+    hidl_vec<uint8_t> vec;
+    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                     gralloc4::MetadataType_Interlaced, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    ExtendableType interlaced = gralloc4::Interlaced_TopBottom;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeInterlaced(vec, &interlaced));
+
+    EXPECT_EQ(gralloc4::Interlaced_None.name, interlaced.name);
+    EXPECT_EQ(gralloc4::Interlaced_None.value, interlaced.value);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(ChromaSiting)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) {
+    hidl_vec<uint8_t> vec;
+    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                     gralloc4::MetadataType_ChromaSiting, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    ExtendableType chromaSiting = gralloc4::ChromaSiting_CositedHorizontal;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeChromaSiting(vec, &chromaSiting));
+
+    EXPECT_EQ(gralloc4::ChromaSiting_None.name, chromaSiting.name);
+    EXPECT_EQ(gralloc4::ChromaSiting_None.value, chromaSiting.value);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(PlaneLayouts)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoPlaneLayouts) {
+    hidl_vec<uint8_t> vec;
+    const auto ret = mGralloc->getFromBufferDescriptorInfo(
+            mDummyDescriptorInfo, gralloc4::MetadataType_PlaneLayouts, &vec);
+    if (ret == Error::NONE) {
+        std::vector<PlaneLayout> planeLayouts;
+        ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+        ASSERT_NO_FATAL_FAILURE(verifyRGBA8888PlaneLayouts(planeLayouts));
+    } else {
+        ASSERT_EQ(Error::UNSUPPORTED, ret);
+    }
+}
+
+/**
+ * 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;
+    auto err = mGralloc->getFromBufferDescriptorInfo(info, gralloc4::MetadataType_Crop, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    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) {
+    hidl_vec<uint8_t> vec;
+    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                     gralloc4::MetadataType_Dataspace, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    Dataspace dataspace = Dataspace::DISPLAY_P3;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeDataspace(vec, &dataspace));
+    EXPECT_EQ(Dataspace::UNKNOWN, dataspace);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(BlendMode)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoBlendMode) {
+    hidl_vec<uint8_t> vec;
+    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                     gralloc4::MetadataType_BlendMode, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    BlendMode blendMode = BlendMode::COVERAGE;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeBlendMode(vec, &blendMode));
+    EXPECT_EQ(BlendMode::INVALID, blendMode);
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2086) {
+    hidl_vec<uint8_t> vec;
+    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                     gralloc4::MetadataType_Smpte2086, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    std::optional<Smpte2086> smpte2086;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086));
+    EXPECT_FALSE(smpte2086.has_value());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Cta861_3)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCta861_3) {
+    hidl_vec<uint8_t> vec;
+    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                     gralloc4::MetadataType_Cta861_3, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    std::optional<Cta861_3> cta861_3;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3));
+    EXPECT_FALSE(cta861_3.has_value());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2094_40) {
+    hidl_vec<uint8_t> vec;
+    auto err = mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                     gralloc4::MetadataType_Smpte2094_40, &vec);
+    if (err == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "setting this metadata is unsupported";
+        return;
+    }
+    ASSERT_EQ(err, Error::NONE);
+
+    std::optional<std::vector<uint8_t>> smpte2094_40;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40));
+    EXPECT_FALSE(smpte2094_40.has_value());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) {
+    MetadataType metadataTypeFake = {"FAKE", 1};
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, metadataTypeFake, &vec));
+    ASSERT_EQ(0, vec.size());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported standard metadata
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedStandardMetadata) {
+    MetadataType metadataTypeFake = {GRALLOC4_STANDARD_METADATA_TYPE, 9999};
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo, metadataTypeFake, &vec));
+    ASSERT_EQ(0, vec.size());
+}
+
+/**
+ * Test IMapper::listSupportedMetadataTypes()
+ */
+TEST_P(GraphicsMapperHidlTest, ListSupportedMetadataTypes) {
+    hidl_vec<IMapper::MetadataTypeDescription> descriptions;
+    mGralloc->getMapper()->listSupportedMetadataTypes(
+            [&](const auto& tmpError, const auto& tmpDescriptions) {
+                ASSERT_EQ(Error::NONE, tmpError);
+                descriptions = tmpDescriptions;
+            });
+
+    std::set<StandardMetadataType> foundMetadataTypes;
+
+    std::set<StandardMetadataType> notSettableMetadataTypes{
+            StandardMetadataType::BUFFER_ID,   StandardMetadataType::NAME,
+            StandardMetadataType::WIDTH,       StandardMetadataType::HEIGHT,
+            StandardMetadataType::LAYER_COUNT, StandardMetadataType::PIXEL_FORMAT_REQUESTED,
+            StandardMetadataType::USAGE};
+
+    ASSERT_LE(sRequiredMetadataTypes.size(), descriptions.size());
+
+    for (const auto& description : descriptions) {
+        const auto& metadataType = description.metadataType;
+
+        if (!gralloc4::isStandardMetadataType(metadataType)) {
+            EXPECT_GT(description.description.size(), 0);
+            continue;
+        }
+
+        StandardMetadataType type = gralloc4::getStandardMetadataTypeValue(metadataType);
+
+        if (sRequiredMetadataTypes.find(type) == sRequiredMetadataTypes.end()) {
+            continue;
+        }
+
+        ASSERT_EQ(foundMetadataTypes.find(type), foundMetadataTypes.end());
+        foundMetadataTypes.insert(type);
+
+        ASSERT_TRUE(description.isGettable);
+
+        if (notSettableMetadataTypes.find(type) != notSettableMetadataTypes.end()) {
+            ASSERT_FALSE(description.isSettable);
+        }
+    }
+
+    ASSERT_EQ(sRequiredMetadataTypes, foundMetadataTypes);
+}
+
+/**
+ * Test IMapper::dumpBuffer()
+ */
+TEST_P(GraphicsMapperHidlTest, DumpBuffer) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    IMapper::BufferDump bufferDump;
+    mGralloc->getMapper()->dumpBuffer(buffer, [&](const auto& tmpError, const auto& tmpBufferDump) {
+        ASSERT_EQ(Error::NONE, tmpError);
+        bufferDump = tmpBufferDump;
+    });
+
+    ASSERT_NO_FATAL_FAILURE(verifyBufferDump(bufferDump, buffer));
+}
+
+/**
+ * Test IMapper::dumpBuffer() with an invalid buffer
+ */
+TEST_P(GraphicsMapperHidlTest, DumpBufferNullBuffer) {
+    native_handle_t* bufferHandle = nullptr;
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    mGralloc->getMapper()->dumpBuffer(buffer,
+                                      [&](const auto& tmpError, const auto& /*tmpBufferDump*/) {
+                                          ASSERT_EQ(Error::BAD_BUFFER, tmpError);
+                                      });
+}
+
+/**
+ * Test IMapper::dumpBuffer() multiple
+ */
+TEST_P(GraphicsMapperHidlTest, DumpBuffers) {
+    size_t bufferCount = 10;
+
+    for (int i = 0; i < bufferCount; i++) {
+        ASSERT_NO_FATAL_FAILURE(mGralloc->allocate(mDummyDescriptorInfo, true));
+    }
+
+    hidl_vec<IMapper::BufferDump> bufferDump;
+    mGralloc->getMapper()->dumpBuffers([&](const auto& tmpError, const auto& tmpBufferDump) {
+        ASSERT_EQ(Error::NONE, tmpError);
+        bufferDump = tmpBufferDump;
+    });
+
+    ASSERT_EQ(bufferCount, bufferDump.size());
+
+    for (const auto& dump : bufferDump) {
+        ASSERT_NO_FATAL_FAILURE(verifyBufferDump(dump));
+    }
+}
+
+/**
+ * Test IMapper::getReservedRegion()
+ */
+TEST_P(GraphicsMapperHidlTest, GetReservedRegion) {
+    const native_handle_t* bufferHandle = nullptr;
+    auto info = mDummyDescriptorInfo;
+
+    const int pageSize = getpagesize();
+    ASSERT_GE(pageSize, 0);
+    std::vector<uint64_t> requestedReservedSizes{1, 10, 333, static_cast<uint64_t>(pageSize) / 2,
+                                                 static_cast<uint64_t>(pageSize)};
+
+    for (auto requestedReservedSize : requestedReservedSizes) {
+        info.reservedSize = requestedReservedSize;
+
+        ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));
+
+        void* reservedRegion = nullptr;
+        uint64_t reservedSize = 0;
+        ASSERT_EQ(Error::NONE,
+                  mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize));
+        ASSERT_NE(nullptr, reservedRegion);
+        ASSERT_EQ(requestedReservedSize, reservedSize);
+
+        uint8_t testValue = 1;
+        memset(reservedRegion, testValue, reservedSize);
+        for (uint64_t i = 0; i < reservedSize; i++) {
+            ASSERT_EQ(testValue, static_cast<uint8_t*>(reservedRegion)[i]);
+        }
+    }
+}
+
+/**
+ * Test IMapper::getReservedRegion() request over a page
+ */
+TEST_P(GraphicsMapperHidlTest, GetLargeReservedRegion) {
+    const native_handle_t* bufferHandle = nullptr;
+    auto info = mDummyDescriptorInfo;
+
+    const int pageSize = getpagesize();
+    ASSERT_GE(pageSize, 0);
+    std::vector<uint64_t> requestedReservedSizes{static_cast<uint64_t>(pageSize) * 2,
+                                                 static_cast<uint64_t>(pageSize) * 10,
+                                                 static_cast<uint64_t>(pageSize) * 1000};
+
+    for (auto requestedReservedSize : requestedReservedSizes) {
+        info.reservedSize = requestedReservedSize;
+
+        BufferDescriptor descriptor;
+        ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(info));
+
+        Error err;
+        mGralloc->getAllocator()->allocate(
+                descriptor, 1, [&](const auto& tmpError, const auto&, const auto& tmpBuffers) {
+                    err = tmpError;
+                    if (err == Error::NONE) {
+                        ASSERT_EQ(1, tmpBuffers.size());
+                        ASSERT_NO_FATAL_FAILURE(bufferHandle =
+                                                        mGralloc->importBuffer(tmpBuffers[0]));
+                    }
+                });
+        if (err == Error::UNSUPPORTED) {
+            continue;
+        }
+        ASSERT_EQ(Error::NONE, err);
+
+        void* reservedRegion = nullptr;
+        uint64_t reservedSize = 0;
+        err = mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize);
+
+        ASSERT_EQ(Error::NONE, err);
+        ASSERT_NE(nullptr, reservedRegion);
+        ASSERT_EQ(requestedReservedSize, reservedSize);
+    }
+}
+
+/**
+ * Test IMapper::getReservedRegion() across multiple mappers
+ */
+TEST_P(GraphicsMapperHidlTest, GetReservedRegionMultiple) {
+    const native_handle_t* bufferHandle = nullptr;
+    auto info = mDummyDescriptorInfo;
+
+    const int pageSize = getpagesize();
+    ASSERT_GE(pageSize, 0);
+    info.reservedSize = pageSize;
+
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true));
+
+    void* reservedRegion1 = nullptr;
+    uint64_t reservedSize1 = 0;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getReservedRegion(bufferHandle, &reservedRegion1, &reservedSize1));
+    ASSERT_NE(nullptr, reservedRegion1);
+    ASSERT_EQ(info.reservedSize, reservedSize1);
+
+    std::unique_ptr<Gralloc> anotherGralloc;
+    ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
+                                                                       std::get<1>(GetParam())));
+
+    void* reservedRegion2 = nullptr;
+    uint64_t reservedSize2 = 0;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getReservedRegion(bufferHandle, &reservedRegion2, &reservedSize2));
+    ASSERT_EQ(reservedRegion1, reservedRegion2);
+    ASSERT_EQ(reservedSize1, reservedSize2);
+}
+
+/**
+ * Test IMapper::getReservedRegion() with a bad buffer
+ */
+TEST_P(GraphicsMapperHidlTest, GetReservedRegionBadBuffer) {
+    const native_handle_t* bufferHandle = nullptr;
+
+    void* reservedRegion = nullptr;
+    uint64_t reservedSize = 0;
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->getReservedRegion(bufferHandle, &reservedRegion, &reservedSize));
+    ASSERT_EQ(nullptr, reservedRegion);
+    ASSERT_EQ(0, reservedSize);
+}
+
+INSTANTIATE_TEST_CASE_P(
+        PerInstance, GraphicsMapperHidlTest,
+        testing::Combine(
+                testing::ValuesIn(
+                        android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+                testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
+        android::hardware::PrintInstanceTupleNameToString<>);
+
+}  // namespace
+}  // namespace vts
+}  // namespace V4_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
index 0f27a72..f7ec7c5 100644
--- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
+++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
@@ -33,6 +33,7 @@
 using ::std::string;
 using ::std::tuple;
 using ::std::vector;
+using ::std::pair;
 
 // ---------------------------------------------------------------------------
 // Miscellaneous utilities.
@@ -119,6 +120,12 @@
 optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
         const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId);
 
+// Like createEcKeyPairAndAttestation() but allows you to choose the public key.
+//
+optional<vector<vector<uint8_t>>> createAttestationForEcPublicKey(
+        const vector<uint8_t>& publicKey, const vector<uint8_t>& challenge,
+        const vector<uint8_t>& applicationId);
+
 // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
 // PKCS#8 encoded key-pair.
 //
@@ -155,6 +162,12 @@
 //
 optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data);
 
+// Like signEcDsa() but instead of taking the data to be signed, takes a digest
+// of it instead.
+//
+optional<vector<uint8_t>> signEcDsaDigest(const vector<uint8_t>& key,
+                                          const vector<uint8_t>& dataDigest);
+
 // Calculates the HMAC with SHA-256 for |data| using |key|. The calculated HMAC
 // is returned and will be 32 bytes.
 //
@@ -175,6 +188,27 @@
 //
 optional<vector<uint8_t>> certificateChainGetTopMostKey(const vector<uint8_t>& certificateChain);
 
+// Extracts the public-key from the top-most certificate in |certificateChain|
+// (which should be a concatenated chain of DER-encoded X.509 certificates).
+//
+// Return offset and size of the public-key
+//
+optional<pair<size_t, size_t>> certificateFindPublicKey(const vector<uint8_t>& x509Certificate);
+
+// Extracts the TbsCertificate from the top-most certificate in |certificateChain|
+// (which should be a concatenated chain of DER-encoded X.509 certificates).
+//
+// Return offset and size of the TbsCertificate
+//
+optional<pair<size_t, size_t>> certificateTbsCertificate(const vector<uint8_t>& x509Certificate);
+
+// Extracts the Signature from the top-most certificate in |certificateChain|
+// (which should be a concatenated chain of DER-encoded X.509 certificates).
+//
+// Return offset and size of the Signature
+//
+optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate);
+
 // Generates a X.509 certificate for |publicKey| (which must be in the format
 // returned by ecKeyPairGetPublicKey()).
 //
@@ -231,6 +265,11 @@
 //
 bool certificateChainValidate(const vector<uint8_t>& certificateChain);
 
+// Returns true if |certificate| is signed by |publicKey|.
+//
+bool certificateSignedByPublicKey(const vector<uint8_t>& certificate,
+                                  const vector<uint8_t>& publicKey);
+
 // Signs |data| and |detachedContent| with |key| (which must be in the format
 // returned by ecKeyPairGetPrivateKey()).
 //
@@ -243,6 +282,21 @@
                                         const vector<uint8_t>& detachedContent,
                                         const vector<uint8_t>& certificateChain);
 
+// Creates a COSE_Signature1 where |signatureToBeSigned| is the ECDSA signature
+// of the ToBeSigned CBOR from RFC 8051 "4.4. Signing and Verification Process".
+//
+// The |signatureToBeSigned| is expected to be 64 bytes and contain the R value,
+// then the S value.
+//
+// The |data| parameter will be included in the COSE_Sign1 CBOR.
+//
+// If |certificateChain| is non-empty it's included in the 'x5chain'
+// protected header element (as as described in'draft-ietf-cose-x509-04').
+//
+optional<vector<uint8_t>> coseSignEcDsaWithSignature(const vector<uint8_t>& signatureToBeSigned,
+                                                     const vector<uint8_t>& data,
+                                                     const vector<uint8_t>& certificateChain);
+
 // Checks that |signatureCoseSign1| (in COSE_Sign1 format) is a valid signature
 // made with |public_key| (which must be in the format returned by
 // ecKeyPairGetPublicKey()) where |detachedContent| is the detached content.
@@ -251,9 +305,23 @@
                              const vector<uint8_t>& detachedContent,
                              const vector<uint8_t>& publicKey);
 
+// Converts a DER-encoded signature to the format used in 'signature' bstr in COSE_Sign1.
+bool ecdsaSignatureDerToCose(const vector<uint8_t>& ecdsaDerSignature,
+                             vector<uint8_t>& ecdsaCoseSignature);
+
+// Converts from the format in in 'signature' bstr in COSE_Sign1 to DER encoding.
+bool ecdsaSignatureCoseToDer(const vector<uint8_t>& ecdsaCoseSignature,
+                             vector<uint8_t>& ecdsaDerSignature);
+
 // Extracts the payload from a COSE_Sign1.
 optional<vector<uint8_t>> coseSignGetPayload(const vector<uint8_t>& signatureCoseSign1);
 
+// Extracts the signature (of the ToBeSigned CBOR) from a COSE_Sign1.
+optional<vector<uint8_t>> coseSignGetSignature(const vector<uint8_t>& signatureCoseSign1);
+
+// Extracts the signature algorithm from a COSE_Sign1.
+optional<int> coseSignGetAlg(const vector<uint8_t>& signatureCoseSign1);
+
 // Extracts the X.509 certificate chain, if present. Returns the data as a
 // concatenated chain of DER-encoded X.509 certificates
 //
@@ -269,6 +337,16 @@
 optional<vector<uint8_t>> coseMac0(const vector<uint8_t>& key, const vector<uint8_t>& data,
                                    const vector<uint8_t>& detachedContent);
 
+// Creates a COSE_Mac0 where |digestToBeMaced| is the HMAC-SHA256
+// of the ToBeMaced CBOR from RFC 8051 "6.3. How to Compute and Verify a MAC".
+//
+// The |digestToBeMaced| is expected to be 32 bytes.
+//
+// The |data| parameter will be included in the COSE_Mac0 CBOR.
+//
+optional<vector<uint8_t>> coseMacWithDigest(const vector<uint8_t>& digestToBeMaced,
+                                            const vector<uint8_t>& data);
+
 // ---------------------------------------------------------------------------
 // Utility functions specific to IdentityCredential.
 // ---------------------------------------------------------------------------
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index e9d5d6c..8e099e7 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -24,6 +24,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <time.h>
+#include <chrono>
 #include <iomanip>
 
 #include <openssl/aes.h>
@@ -684,6 +685,48 @@
     return true;
 }
 
+bool certificateSignedByPublicKey(const vector<uint8_t>& certificate,
+                                  const vector<uint8_t>& publicKey) {
+    const unsigned char* p = certificate.data();
+    auto x509 = X509_Ptr(d2i_X509(nullptr, &p, certificate.size()));
+    if (x509 == nullptr) {
+        LOG(ERROR) << "Error parsing X509 certificate";
+        return false;
+    }
+
+    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+    auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+    if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) !=
+        1) {
+        LOG(ERROR) << "Error decoding publicKey";
+        return false;
+    }
+    auto ecKey = EC_KEY_Ptr(EC_KEY_new());
+    auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
+    if (ecKey.get() == nullptr || pkey.get() == nullptr) {
+        LOG(ERROR) << "Memory allocation failed";
+        return false;
+    }
+    if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
+        LOG(ERROR) << "Error setting group";
+        return false;
+    }
+    if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
+        LOG(ERROR) << "Error setting point";
+        return false;
+    }
+    if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) {
+        LOG(ERROR) << "Error setting key";
+        return false;
+    }
+
+    if (X509_verify(x509.get(), pkey.get()) != 1) {
+        return false;
+    }
+
+    return true;
+}
+
 // TODO: Right now the only check we perform is to check that each certificate
 //       is signed by its successor. We should - but currently don't - also check
 //       things like valid dates etc.
@@ -770,7 +813,8 @@
     return ret;
 }
 
-optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data) {
+optional<vector<uint8_t>> signEcDsaDigest(const vector<uint8_t>& key,
+                                          const vector<uint8_t>& dataDigest) {
     auto bn = BIGNUM_Ptr(BN_bin2bn(key.data(), key.size(), nullptr));
     if (bn.get() == nullptr) {
         LOG(ERROR) << "Error creating BIGNUM";
@@ -783,8 +827,7 @@
         return {};
     }
 
-    auto digest = sha256(data);
-    ECDSA_SIG* sig = ECDSA_do_sign(digest.data(), digest.size(), ec_key.get());
+    ECDSA_SIG* sig = ECDSA_do_sign(dataDigest.data(), dataDigest.size(), ec_key.get());
     if (sig == nullptr) {
         LOG(ERROR) << "Error signing digest";
         return {};
@@ -798,6 +841,10 @@
     return signature;
 }
 
+optional<vector<uint8_t>> signEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data) {
+    return signEcDsaDigest(key, sha256(data));
+}
+
 optional<vector<uint8_t>> hmacSha256(const vector<uint8_t>& key, const vector<uint8_t>& data) {
     HMAC_CTX ctx;
     HMAC_CTX_init(&ctx);
@@ -955,6 +1002,51 @@
     return make_pair(keyPair, attestationCert.value());
 }
 
+optional<vector<vector<uint8_t>>> createAttestationForEcPublicKey(
+        const vector<uint8_t>& publicKey, const vector<uint8_t>& challenge,
+        const vector<uint8_t>& applicationId) {
+    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+    auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+    if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) !=
+        1) {
+        LOG(ERROR) << "Error decoding publicKey";
+        return {};
+    }
+    auto ecKey = EC_KEY_Ptr(EC_KEY_new());
+    auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
+    if (ecKey.get() == nullptr || pkey.get() == nullptr) {
+        LOG(ERROR) << "Memory allocation failed";
+        return {};
+    }
+    if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
+        LOG(ERROR) << "Error setting group";
+        return {};
+    }
+    if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
+        LOG(ERROR) << "Error setting point";
+        return {};
+    }
+    if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) {
+        LOG(ERROR) << "Error setting key";
+        return {};
+    }
+
+    uint64_t now = (std::chrono::duration_cast<std::chrono::nanoseconds>(
+                    std::chrono::system_clock::now().time_since_epoch()).
+                    count()/ 1000000000);
+    uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
+    uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+
+    optional<vector<vector<uint8_t>>> attestationCert =
+            createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+    if (!attestationCert) {
+        LOG(ERROR) << "Error create attestation from key and challenge";
+        return {};
+    }
+
+    return attestationCert.value();
+}
+
 optional<vector<uint8_t>> createEcKeyPair() {
     auto ec_key = EC_KEY_Ptr(EC_KEY_new());
     auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
@@ -1477,6 +1569,120 @@
     return publicKey;
 }
 
+optional<pair<size_t, size_t>> certificateFindPublicKey(const vector<uint8_t>& x509Certificate) {
+    vector<X509_Ptr> certs;
+    if (!parseX509Certificates(x509Certificate, certs)) {
+        return {};
+    }
+    if (certs.size() < 1) {
+        LOG(ERROR) << "No certificates in chain";
+        return {};
+    }
+
+    auto pkey = EVP_PKEY_Ptr(X509_get_pubkey(certs[0].get()));
+    if (pkey.get() == nullptr) {
+        LOG(ERROR) << "No public key";
+        return {};
+    }
+
+    auto ecKey = EC_KEY_Ptr(EVP_PKEY_get1_EC_KEY(pkey.get()));
+    if (ecKey.get() == nullptr) {
+        LOG(ERROR) << "Failed getting EC key";
+        return {};
+    }
+
+    auto ecGroup = EC_KEY_get0_group(ecKey.get());
+    auto ecPoint = EC_KEY_get0_public_key(ecKey.get());
+    int size = EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0,
+                                  nullptr);
+    if (size == 0) {
+        LOG(ERROR) << "Error generating public key encoding";
+        return {};
+    }
+    vector<uint8_t> publicKey;
+    publicKey.resize(size);
+    EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(),
+                       publicKey.size(), nullptr);
+
+    size_t publicKeyOffset = 0;
+    size_t publicKeySize = (size_t)size;
+    void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(),
+                            (const void*)publicKey.data(), publicKey.size());
+
+    if (location == NULL) {
+        LOG(ERROR) << "Error finding publicKey from x509Certificate";
+        return {};
+    }
+    publicKeyOffset = (size_t)((const char*)location - (const char*)x509Certificate.data());
+
+    return std::make_pair(publicKeyOffset, publicKeySize);
+}
+
+optional<pair<size_t, size_t>> certificateTbsCertificate(const vector<uint8_t>& x509Certificate) {
+    vector<X509_Ptr> certs;
+    if (!parseX509Certificates(x509Certificate, certs)) {
+        return {};
+    }
+    if (certs.size() < 1) {
+        LOG(ERROR) << "No certificates in chain";
+        return {};
+    }
+
+    unsigned char* buf = NULL;
+    int len = i2d_re_X509_tbs(certs[0].get(), &buf);
+    if ((len < 0) || (buf == NULL)) {
+        LOG(ERROR) << "fail to extract tbsCertificate in x509Certificate";
+        return {};
+    }
+
+    vector<uint8_t> tbsCertificate(len);
+    memcpy(tbsCertificate.data(), buf, len);
+
+    size_t tbsCertificateOffset = 0;
+    size_t tbsCertificateSize = (size_t)len;
+    void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(),
+                            (const void*)tbsCertificate.data(), tbsCertificate.size());
+
+    if (location == NULL) {
+        LOG(ERROR) << "Error finding tbsCertificate from x509Certificate";
+        return {};
+    }
+    tbsCertificateOffset = (size_t)((const char*)location - (const char*)x509Certificate.data());
+
+    return std::make_pair(tbsCertificateOffset, tbsCertificateSize);
+}
+
+optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate) {
+    vector<X509_Ptr> certs;
+    if (!parseX509Certificates(x509Certificate, certs)) {
+        return {};
+    }
+    if (certs.size() < 1) {
+        LOG(ERROR) << "No certificates in chain";
+        return {};
+    }
+
+    ASN1_BIT_STRING* psig;
+    X509_ALGOR* palg;
+    X509_get0_signature((const ASN1_BIT_STRING**)&psig, (const X509_ALGOR**)&palg, certs[0].get());
+
+    vector<char> signature(psig->length);
+    memcpy(signature.data(), psig->data, psig->length);
+
+    size_t signatureOffset = 0;
+    size_t signatureSize = (size_t)psig->length;
+    void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(),
+                            (const void*)signature.data(), signature.size());
+
+    if (location == NULL) {
+        LOG(ERROR) << "Error finding signature from x509Certificate";
+        return {};
+    }
+    signatureOffset = (size_t)((const char*)location - (const char*)x509Certificate.data());
+
+    return std::make_pair(signatureOffset, signatureSize);
+}
+
 // ---------------------------------------------------------------------------
 // COSE Utility Functions
 // ---------------------------------------------------------------------------
@@ -1574,6 +1780,55 @@
     return true;
 }
 
+optional<vector<uint8_t>> coseSignEcDsaWithSignature(const vector<uint8_t>& signatureToBeSigned,
+                                                     const vector<uint8_t>& data,
+                                                     const vector<uint8_t>& certificateChain) {
+    if (signatureToBeSigned.size() != 64) {
+        LOG(ERROR) << "Invalid size for signatureToBeSigned, expected 64 got "
+                   << signatureToBeSigned.size();
+        return {};
+    }
+
+    cppbor::Map unprotectedHeaders;
+    cppbor::Map protectedHeaders;
+
+    protectedHeaders.add(COSE_LABEL_ALG, COSE_ALG_ECDSA_256);
+
+    if (certificateChain.size() != 0) {
+        optional<vector<vector<uint8_t>>> certs = support::certificateChainSplit(certificateChain);
+        if (!certs) {
+            LOG(ERROR) << "Error splitting certificate chain";
+            return {};
+        }
+        if (certs.value().size() == 1) {
+            unprotectedHeaders.add(COSE_LABEL_X5CHAIN, certs.value()[0]);
+        } else {
+            cppbor::Array certArray;
+            for (const vector<uint8_t>& cert : certs.value()) {
+                certArray.add(cert);
+            }
+            unprotectedHeaders.add(COSE_LABEL_X5CHAIN, std::move(certArray));
+        }
+    }
+
+    vector<uint8_t> encodedProtectedHeaders = coseEncodeHeaders(protectedHeaders);
+
+    cppbor::Array coseSign1;
+    coseSign1.add(encodedProtectedHeaders);
+    coseSign1.add(std::move(unprotectedHeaders));
+    if (data.size() == 0) {
+        cppbor::Null nullValue;
+        coseSign1.add(std::move(nullValue));
+    } else {
+        coseSign1.add(data);
+    }
+    coseSign1.add(signatureToBeSigned);
+    vector<uint8_t> signatureCoseSign1;
+    signatureCoseSign1 = coseSign1.encode();
+
+    return signatureCoseSign1;
+}
+
 optional<vector<uint8_t>> coseSignEcDsa(const vector<uint8_t>& key, const vector<uint8_t>& data,
                                         const vector<uint8_t>& detachedContent,
                                         const vector<uint8_t>& certificateChain) {
@@ -1709,6 +1964,35 @@
     return true;
 }
 
+// Extracts the signature (of the ToBeSigned CBOR) from a COSE_Sign1.
+optional<vector<uint8_t>> coseSignGetSignature(const vector<uint8_t>& signatureCoseSign1) {
+    auto [item, _, message] = cppbor::parse(signatureCoseSign1);
+    if (item == nullptr) {
+        LOG(ERROR) << "Passed-in COSE_Sign1 is not valid CBOR: " << message;
+        return {};
+    }
+    const cppbor::Array* array = item->asArray();
+    if (array == nullptr) {
+        LOG(ERROR) << "Value for COSE_Sign1 is not an array";
+        return {};
+    }
+    if (array->size() != 4) {
+        LOG(ERROR) << "Value for COSE_Sign1 is not an array of size 4";
+        return {};
+    }
+
+    vector<uint8_t> signature;
+    const cppbor::Bstr* signatureAsBstr = (*array)[3]->asBstr();
+    if (signatureAsBstr == nullptr) {
+        LOG(ERROR) << "Value for signature is not a bstr";
+        return {};
+    }
+    // Copy payload into |data|
+    signature = signatureAsBstr->value();
+
+    return signature;
+}
+
 optional<vector<uint8_t>> coseSignGetPayload(const vector<uint8_t>& signatureCoseSign1) {
     auto [item, _, message] = cppbor::parse(signatureCoseSign1);
     if (item == nullptr) {
@@ -1746,6 +2030,59 @@
     return data;
 }
 
+optional<int> coseSignGetAlg(const vector<uint8_t>& signatureCoseSign1) {
+    auto [item, _, message] = cppbor::parse(signatureCoseSign1);
+    if (item == nullptr) {
+        LOG(ERROR) << "Passed-in COSE_Sign1 is not valid CBOR: " << message;
+        return {};
+    }
+    const cppbor::Array* array = item->asArray();
+    if (array == nullptr) {
+        LOG(ERROR) << "Value for COSE_Sign1 is not an array";
+        return {};
+    }
+    if (array->size() != 4) {
+        LOG(ERROR) << "Value for COSE_Sign1 is not an array of size 4";
+        return {};
+    }
+
+    const cppbor::Bstr* protectedHeadersBytes = (*array)[0]->asBstr();
+    if (protectedHeadersBytes == nullptr) {
+        LOG(ERROR) << "Value for protectedHeaders is not a bstr";
+        return {};
+    }
+    auto [item2, _2, message2] = cppbor::parse(protectedHeadersBytes->value());
+    if (item2 == nullptr) {
+        LOG(ERROR) << "Error parsing protectedHeaders: " << message2;
+        return {};
+    }
+    const cppbor::Map* protectedHeaders = item2->asMap();
+    if (protectedHeaders == nullptr) {
+        LOG(ERROR) << "Decoded CBOR for protectedHeaders is not a map";
+        return {};
+    }
+
+    for (size_t n = 0; n < protectedHeaders->size(); n++) {
+        auto [keyItem, valueItem] = (*protectedHeaders)[n];
+        const cppbor::Int* number = keyItem->asInt();
+        if (number == nullptr) {
+            LOG(ERROR) << "Key item in top-level map is not a number";
+            return {};
+        }
+        int label = number->value();
+        if (label == COSE_LABEL_ALG) {
+            const cppbor::Int* number = valueItem->asInt();
+            if (number != nullptr) {
+                return number->value();
+            }
+            LOG(ERROR) << "Value for COSE_LABEL_ALG label is not a number";
+            return {};
+        }
+    }
+    LOG(ERROR) << "Did not find COSE_LABEL_ALG label in protected headers";
+    return {};
+}
+
 optional<vector<uint8_t>> coseSignGetX5Chain(const vector<uint8_t>& signatureCoseSign1) {
     auto [item, _, message] = cppbor::parse(signatureCoseSign1);
     if (item == nullptr) {
@@ -1861,6 +2198,28 @@
     return array.encode();
 }
 
+optional<vector<uint8_t>> coseMacWithDigest(const vector<uint8_t>& digestToBeMaced,
+                                            const vector<uint8_t>& data) {
+    cppbor::Map unprotectedHeaders;
+    cppbor::Map protectedHeaders;
+
+    protectedHeaders.add(COSE_LABEL_ALG, COSE_ALG_HMAC_256_256);
+
+    vector<uint8_t> encodedProtectedHeaders = coseEncodeHeaders(protectedHeaders);
+
+    cppbor::Array array;
+    array.add(encodedProtectedHeaders);
+    array.add(std::move(unprotectedHeaders));
+    if (data.size() == 0) {
+        cppbor::Null nullValue;
+        array.add(std::move(nullValue));
+    } else {
+        array.add(data);
+    }
+    array.add(digestToBeMaced);
+    return array.encode();
+}
+
 // ---------------------------------------------------------------------------
 // Utility functions specific to IdentityCredential.
 // ---------------------------------------------------------------------------
diff --git a/input/classifier/1.0/vts/functional/Android.bp b/input/classifier/1.0/vts/functional/Android.bp
index dca7f59..150324b 100644
--- a/input/classifier/1.0/vts/functional/Android.bp
+++ b/input/classifier/1.0/vts/functional/Android.bp
@@ -23,5 +23,8 @@
         "android.hardware.input.classifier@1.0",
         "android.hardware.input.common@1.0",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
index f033c2a..ee529c7 100644
--- a/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
+++ b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
@@ -16,11 +16,12 @@
 
 #define LOG_TAG "input_classifier_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/input/classifier/1.0/IInputClassifier.h>
 #include <android/hardware/input/common/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <input/InputDevice.h>
 #include <unistd.h>
 
@@ -72,27 +73,11 @@
     return event;
 }
 
-// Test environment for Input Classifier HIDL HAL.
-class InputClassifierHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-  public:
-    // get the test environment singleton
-    static InputClassifierHidlEnvironment* Instance() {
-        static InputClassifierHidlEnvironment* instance = new InputClassifierHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IInputClassifier>(); }
-
-  private:
-    InputClassifierHidlEnvironment() {}
-};
-
 // The main test class for INPUT CLASSIFIER HIDL HAL 1.0.
-class InputClassifierHidlTest_1_0 : public ::testing::VtsHalHidlTargetTestBase {
+class InputClassifierHidlTest_1_0 : public ::testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
-        classifier = ::testing::VtsHalHidlTargetTestBase::getService<IInputClassifier>(
-                InputClassifierHidlEnvironment::Instance()->getServiceName<IInputClassifier>());
+        classifier = IInputClassifier::getService(GetParam());
         ASSERT_NE(classifier, nullptr);
     }
 
@@ -105,7 +90,7 @@
  * Call resetDevice(..) for a few common device id values, and make sure that the HAL
  * can handle the resets gracefully.
  */
-TEST_F(InputClassifierHidlTest_1_0, ResetDevice) {
+TEST_P(InputClassifierHidlTest_1_0, ResetDevice) {
     EXPECT_TRUE(classifier->resetDevice(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID).isOk());
     EXPECT_TRUE(classifier->resetDevice(ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID).isOk());
     EXPECT_TRUE(classifier->resetDevice(1).isOk());
@@ -115,14 +100,14 @@
 /**
  * Call reset() on the HAL to ensure no fatal failure there.
  */
-TEST_F(InputClassifierHidlTest_1_0, ResetHal) {
+TEST_P(InputClassifierHidlTest_1_0, ResetHal) {
     EXPECT_TRUE(classifier->reset().isOk());
 }
 
 /**
  * Classify an event without any video frames.
  */
-TEST_F(InputClassifierHidlTest_1_0, Classify_NoVideoFrame) {
+TEST_P(InputClassifierHidlTest_1_0, Classify_NoVideoFrame) {
     // Create a MotionEvent that does not have any video data
     MotionEvent event = getSimpleMotionEvent();
 
@@ -137,7 +122,7 @@
 /**
  * Classify an event with one video frame. Should be the most common scenario.
  */
-TEST_F(InputClassifierHidlTest_1_0, Classify_OneVideoFrame) {
+TEST_P(InputClassifierHidlTest_1_0, Classify_OneVideoFrame) {
     MotionEvent event = getSimpleMotionEvent();
     VideoFrame frame;
     frame.data = {1, 2, 3, 4};
@@ -163,7 +148,7 @@
  * monotonically increasing timestamps. Still, we provide consistent timestamps here since that
  * is the most realistic mode of operation.
  */
-TEST_F(InputClassifierHidlTest_1_0, Classify_TwoVideoFrames) {
+TEST_P(InputClassifierHidlTest_1_0, Classify_TwoVideoFrames) {
     MotionEvent event = getSimpleMotionEvent();
     VideoFrame frame1;
     frame1.data = {1, 2, 3, 4};
@@ -183,11 +168,7 @@
     classifier->reset();
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(InputClassifierHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    InputClassifierHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, InputClassifierHidlTest_1_0,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IInputClassifier::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/keymaster/4.1/support/Keymaster.cpp b/keymaster/4.1/support/Keymaster.cpp
index b55bfcc..ea6604e 100644
--- a/keymaster/4.1/support/Keymaster.cpp
+++ b/keymaster/4.1/support/Keymaster.cpp
@@ -82,8 +82,7 @@
 }
 
 template <typename Wrapper>
-std::vector<std::unique_ptr<Keymaster>> enumerateDevices(
-        const sp<IServiceManager>& serviceManager) {
+Keymaster::KeymasterSet enumerateDevices(const sp<IServiceManager>& serviceManager) {
     Keymaster::KeymasterSet result;
 
     bool foundDefault = false;
@@ -94,7 +93,7 @@
             auto device = Wrapper::WrappedIKeymasterDevice::getService(name);
             CHECK(device) << "Failed to get service for " << descriptor << " with interface name "
                           << name;
-            result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, name)));
+            result.push_back(new Wrapper(device, name));
         }
     });
 
@@ -102,7 +101,7 @@
         // "default" wasn't provided by listManifestByInterface.  Maybe there's a passthrough
         // implementation.
         auto device = Wrapper::WrappedIKeymasterDevice::getService("default");
-        if (device) result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, "default")));
+        if (device) result.push_back(new Wrapper(device, "default"));
     }
 
     return result;
diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp
index 63bf854..598b6b5 100644
--- a/keymaster/4.1/support/attestation_record.cpp
+++ b/keymaster/4.1/support/attestation_record.cpp
@@ -296,6 +296,10 @@
 std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert) {
     const uint8_t* p = cert.data();
     X509_Ptr x509(d2i_X509(nullptr, &p, cert.size()));
+    if (!x509.get()) {
+        LOG(ERROR) << "Error converting DER";
+        return {ErrorCode::INVALID_ARGUMENT, {}};
+    }
 
     ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
     if (!oid.get()) {
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
index 2266636..1f49e18 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
@@ -40,7 +40,7 @@
  */
 class Keymaster : public IKeymasterDevice {
   public:
-    using KeymasterSet = std::vector<std::unique_ptr<Keymaster>>;
+    using KeymasterSet = std::vector<android::sp<Keymaster>>;
 
     Keymaster(const hidl_string& descriptor, const hidl_string& instanceName)
         : descriptor_(descriptor), instanceName_(instanceName) {}
diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
index a9a8b1a..728a523 100644
--- a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "keymaster_hidl_hal_test"
+#include <cutils/log.h>
+
 #include "Keymaster4_1HidlTest.h"
 
 #include <cutils/properties.h>
@@ -23,6 +26,10 @@
 #include <keymasterV4_1/attestation_record.h>
 #include <keymasterV4_1/authorization_set.h>
 
+// Not to dump the attestation by default. Can enable by specify the parameter
+// "--dump_attestations" on lunching VTS
+static bool dumpAttestations = false;
+
 namespace android::hardware::keymaster::V4_0 {
 
 bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
@@ -57,6 +64,10 @@
     return retval;
 }
 
+inline void dumpContent(string content) {
+    std::cout << content << std::endl;
+}
+
 struct AuthorizationSetDifferences {
     string aName;
     string bName;
@@ -126,6 +137,23 @@
     }
 }
 
+bool tag_in_list(const KeyParameter& entry) {
+    // Attestations don't contain everything in key authorization lists, so we need to filter
+    // the key lists to produce the lists that we expect to match the attestations.
+    auto tag_list = {
+            Tag::INCLUDE_UNIQUE_ID, Tag::BLOB_USAGE_REQUIREMENTS, Tag::EC_CURVE,
+            Tag::HARDWARE_TYPE,     Tag::VENDOR_PATCHLEVEL,       Tag::BOOT_PATCHLEVEL,
+            Tag::CREATION_DATETIME,
+    };
+    return std::find(tag_list.begin(), tag_list.end(), (V4_1::Tag)entry.tag) != tag_list.end();
+}
+
+AuthorizationSet filter_tags(const AuthorizationSet& set) {
+    AuthorizationSet filtered;
+    std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list);
+    return filtered;
+}
+
 void check_attestation_record(AttestationRecord attestation, const HidlBuf& challenge,
                               AuthorizationSet expected_sw_enforced,
                               AuthorizationSet expected_hw_enforced,
@@ -144,9 +172,9 @@
     attestation.software_enforced.Sort();
     attestation.hardware_enforced.Sort();
 
-    EXPECT_EQ(expected_sw_enforced, attestation.software_enforced)
+    EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(attestation.software_enforced))
             << DIFFERENCE(expected_sw_enforced, attestation.software_enforced);
-    EXPECT_EQ(expected_hw_enforced, attestation.hardware_enforced)
+    EXPECT_EQ(filter_tags(expected_hw_enforced), filter_tags(attestation.hardware_enforced))
             << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced);
 }
 
@@ -155,8 +183,8 @@
 using std::string;
 using DeviceUniqueAttestationTest = Keymaster4_1HidlTest;
 
-TEST_P(DeviceUniqueAttestationTest, StrongBoxOnly) {
-    if (SecLevel() != SecurityLevel::STRONGBOX) return;
+TEST_P(DeviceUniqueAttestationTest, NonStrongBoxOnly) {
+    if (SecLevel() == SecurityLevel::STRONGBOX) return;
 
     ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
                                                          .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -195,11 +223,11 @@
     if (SecLevel() != SecurityLevel::STRONGBOX) return;
     ASSERT_EQ(ErrorCode::OK,
               convert(GenerateKey(AuthorizationSetBuilder()
-                                          .Authorization(TAG_NO_AUTH_REQUIRED)
-                                          .RsaSigningKey(2048, 65537)
-                                          .Digest(Digest::SHA_2_256)
-                                          .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
-                                          .Authorization(TAG_CREATION_DATETIME, 1))));
+                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                  .RsaSigningKey(2048, 65537)
+                                  .Digest(Digest::SHA_2_256)
+                                  .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+                                  .Authorization(TAG_INCLUDE_UNIQUE_ID))));
 
     hidl_vec<hidl_vec<uint8_t>> cert_chain;
     HidlBuf challenge("challenge");
@@ -211,14 +239,14 @@
                                         .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
                                 &cert_chain)));
 
-    EXPECT_EQ(1U, cert_chain.size());
+    EXPECT_EQ(2U, cert_chain.size());
+    if (dumpAttestations) dumpContent(bin2hex(cert_chain[0]));
     auto [err, attestation] = parse_attestation_record(cert_chain[0]);
-    EXPECT_EQ(ErrorCode::OK, err);
+    ASSERT_EQ(ErrorCode::OK, err);
 
     check_attestation_record(attestation, challenge,
                              /* sw_enforced */
                              AuthorizationSetBuilder()
-                                     .Authorization(TAG_CREATION_DATETIME, 1)
                                      .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
                              /* hw_enforced */
                              AuthorizationSetBuilder()
@@ -240,7 +268,7 @@
                                           .Authorization(TAG_NO_AUTH_REQUIRED)
                                           .EcdsaSigningKey(256)
                                           .Digest(Digest::SHA_2_256)
-                                          .Authorization(TAG_CREATION_DATETIME, 1))));
+                                          .Authorization(TAG_INCLUDE_UNIQUE_ID))));
 
     hidl_vec<hidl_vec<uint8_t>> cert_chain;
     HidlBuf challenge("challenge");
@@ -252,29 +280,42 @@
                                         .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
                                 &cert_chain)));
 
-    EXPECT_EQ(1U, cert_chain.size());
+    EXPECT_EQ(2U, cert_chain.size());
+    if (dumpAttestations) dumpContent(bin2hex(cert_chain[0]));
     auto [err, attestation] = parse_attestation_record(cert_chain[0]);
-    EXPECT_EQ(ErrorCode::OK, err);
+    ASSERT_EQ(ErrorCode::OK, err);
 
     check_attestation_record(attestation, challenge,
-                             /* sw_enforced */
-                             AuthorizationSetBuilder()
-                                     .Authorization(TAG_CREATION_DATETIME, 1)
-                                     .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
-                             /* hw_enforced */
-                             AuthorizationSetBuilder()
-                                     .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
-                                     .Authorization(TAG_NO_AUTH_REQUIRED)
-                                     .EcdsaSigningKey(256)
-                                     .Digest(Digest::SHA_2_256)
-                                     .Authorization(TAG_EC_CURVE, EcCurve::P_256)
-                                     .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
-                                     .Authorization(TAG_OS_VERSION, os_version())
-                                     .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
-                             SecLevel());
+            /* sw_enforced */
+            AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+            /* hw_enforced */
+            AuthorizationSetBuilder()
+                    .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .EcdsaSigningKey(256)
+                    .Digest(Digest::SHA_2_256)
+                    .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+                    .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+                    .Authorization(TAG_OS_VERSION, os_version())
+                    .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
+            SecLevel());
 }
 
 INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest);
 
 }  // namespace test
 }  // namespace android::hardware::keymaster::V4_1
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    for (int i = 1; i < argc; ++i) {
+        if (argv[i][0] == '-') {
+            if (std::string(argv[i]) == "--dump_attestations") {
+                dumpAttestations = true;
+            }
+        }
+    }
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
index 5b3e918..f8c1fad 100644
--- a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
@@ -115,7 +115,9 @@
     ErrorCode UseHmacKey(const HidlBuf& hmacKeyBlob) {
         auto [result, mac, out_params] =
                 ProcessMessage(hmacKeyBlob, KeyPurpose::SIGN, "1234567890123456",
-                               AuthorizationSetBuilder().Authorization(TAG_MAC_LENGTH, 128));
+                               AuthorizationSetBuilder()
+                                       .Authorization(TAG_MAC_LENGTH, 128)
+                                       .Digest(Digest::SHA_2_256));
         return result;
     }
 
diff --git a/media/c2/1.1/Android.bp b/media/c2/1.1/Android.bp
new file mode 100644
index 0000000..a3d31df
--- /dev/null
+++ b/media/c2/1.1/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.media.c2@1.1",
+    root: "android.hardware",
+    srcs: [
+        "IComponent.hal",
+        "IComponentStore.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.omx@1.0",
+        "android.hardware.media@1.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/media/c2/1.1/IComponent.hal b/media/c2/1.1/IComponent.hal
new file mode 100644
index 0000000..97382dd
--- /dev/null
+++ b/media/c2/1.1/IComponent.hal
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package android.hardware.media.c2@1.1;
+
+import android.hardware.media.c2@1.0::IComponent;
+import android.hardware.media.c2@1.0::Status;
+
+/**
+ * Interface for a Codec2 component corresponding to API level 1.0 or below.
+ * Components have two states: stopped and running. The running state has three
+ * sub-states: executing, tripped and error.
+ *
+ * All methods in `IComponent` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status.
+ *
+ * @note This is an extension of version 1.0 of `IComponent`. The purpose of the
+ * extension is to add support for tunneling.
+ */
+interface IComponent extends @1.0::IComponent {
+    /**
+      * Configures a component for a tunneled playback mode.
+      *
+      * A successful call to this method puts the component in the *tunneled*
+      * mode. In this mode, the output `Worklet`s returned in
+      * IComponentListener::onWorkDone() may not contain any buffers. The output
+      * buffers are passed directly to the consumer end of a buffer queue whose
+      * producer side is configured with the returned @p sidebandStream passed
+      * to IGraphicBufferProducer::setSidebandStream().
+      *
+      * The component is initially in the non-tunneled mode by default. The
+      * tunneled mode can be toggled on only before the component starts
+      * processing. Once the component is put into the tunneled mode, it shall
+      * stay in the tunneled mode until and only until reset() is called.
+      *
+      * @param avSyncHwId A resource ID for hardware sync. The generator of sync
+      *     IDs must ensure that this number is unique among all services at any
+      *     given time. For example, if both the audio HAL and the tuner HAL
+      *     support this feature, sync IDs from the audio HAL must not clash
+      *     with sync IDs from the tuner HAL.
+      * @return status Status of the call, which may be
+      *   - `OK`        - The operation completed successfully. In this case,
+      *                   @p sidebandHandle shall not be a null handle.
+      *   - `OMITTED`   - The component does not support video tunneling.
+      *   - `BAD_STATE` - The component is already running.
+      *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+      *   - `CORRUPTED` - Some unknown error occurred.
+      * @return sidebandHandle Codec-allocated sideband stream handle. This can
+      *     be passed to IGraphicBufferProducer::setSidebandStream() to
+      *     establish a direct channel to the consumer.
+      */
+     configureVideoTunnel(
+             uint32_t avSyncHwId
+         ) generates (
+             Status status,
+             handle sidebandHandle
+         );
+};
diff --git a/media/c2/1.1/IComponentStore.hal b/media/c2/1.1/IComponentStore.hal
new file mode 100644
index 0000000..38e0fc6
--- /dev/null
+++ b/media/c2/1.1/IComponentStore.hal
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+package android.hardware.media.c2@1.1;
+
+import android.hardware.media.bufferpool@2.0::IClientManager;
+import android.hardware.media.c2@1.0::IComponentListener;
+import android.hardware.media.c2@1.0::IComponentStore;
+import android.hardware.media.c2@1.0::Status;
+
+import IComponent;
+
+/**
+ * Entry point for Codec2 HAL.
+ *
+ * All methods in `IComponentStore` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status. The only exceptions are getPoolClientManager() and getConfigurable(),
+ * which must always return immediately.
+ *
+ * @note This is an extension of version 1.0 of `IComponentStore`. The purpose
+ * of the extension is to add support for tunneling.
+ */
+interface IComponentStore extends @1.0::IComponentStore {
+    /**
+     * Creates a component by name.
+     *
+     * @param name Name of the component to create. This must match one of the
+     *     names returned by listComponents().
+     * @param listener Callback receiver.
+     * @param pool `IClientManager` object of the BufferPool in the client
+     *     process. This may be null if the client does not own a BufferPool.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The component was created successfully.
+     *   - `NOT_FOUND` - There is no component with the given name.
+     *   - `NO_MEMORY` - Not enough memory to create the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return comp The created component if @p status is `OK`.
+     *
+     * @sa IComponentListener.
+     */
+    createComponent_1_1(
+            string name,
+            IComponentListener listener,
+            IClientManager pool
+        ) generates (
+            Status status,
+            IComponent comp
+        );
+};
diff --git a/media/omx/1.0/vts/functional/common/Android.bp b/media/omx/1.0/vts/functional/common/Android.bp
index 7e7463a..3845b9f 100644
--- a/media/omx/1.0/vts/functional/common/Android.bp
+++ b/media/omx/1.0/vts/functional/common/Android.bp
@@ -74,5 +74,6 @@
     shared_libs: [
         "libnativehelper",
         "libstagefright_foundation",
+        "libstagefright_omx_utils",
     ],
 }
diff --git a/media/omx/1.0/vts/functional/master/Android.bp b/media/omx/1.0/vts/functional/master/Android.bp
index 8e58821..5953eb5 100644
--- a/media/omx/1.0/vts/functional/master/Android.bp
+++ b/media/omx/1.0/vts/functional/master/Android.bp
@@ -19,6 +19,7 @@
     defaults: ["VtsHalMediaOmxV1_0Defaults"],
     srcs: ["VtsHalMediaOmxV1_0TargetMasterTest.cpp"],
     test_suites: [
+        "general-tests",
         "vts",
     ],
 }
diff --git a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
index c14f1da..68ee900 100644
--- a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
+++ b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp
@@ -20,6 +20,7 @@
 #endif
 
 #include <android-base/logging.h>
+#include <android-base/strings.h>
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
@@ -32,22 +33,24 @@
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
+#include <media/stagefright/omx/OMXUtils.h>
 
-using ::android::hardware::media::omx::V1_0::IOmx;
-using ::android::hardware::media::omx::V1_0::IOmxObserver;
-using ::android::hardware::media::omx::V1_0::IOmxNode;
-using ::android::hardware::media::omx::V1_0::IOmxStore;
-using ::android::hardware::media::omx::V1_0::Message;
-using ::android::hardware::media::omx::V1_0::CodecBuffer;
-using ::android::hardware::media::omx::V1_0::PortMode;
-using ::android::hidl::allocator::V1_0::IAllocator;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::android::hidl::memory::V1_0::IMapper;
+using ::android::sp;
+using ::android::base::Join;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
+using ::android::hardware::media::omx::V1_0::CodecBuffer;
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::IOmxNode;
+using ::android::hardware::media::omx::V1_0::IOmxObserver;
+using ::android::hardware::media::omx::V1_0::IOmxStore;
+using ::android::hardware::media::omx::V1_0::Message;
+using ::android::hardware::media::omx::V1_0::PortMode;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMapper;
+using ::android::hidl::memory::V1_0::IMemory;
 
 #include <getopt.h>
 #include <media_hidl_test_common.h>
@@ -70,6 +73,11 @@
     }
 };
 
+struct AttributePattern {
+    const testing::internal::RE key;
+    const testing::internal::RE value;
+};
+
 void displayComponentInfo(hidl_vec<IOmx::ComponentInfo>& nodeList) {
     for (size_t i = 0; i < nodeList.size(); i++) {
         printf("%s | ", nodeList[i].mName.c_str());
@@ -80,6 +88,44 @@
     }
 }
 
+void validateAttributes(
+        const std::map<const std::string, const testing::internal::RE>& knownPatterns,
+        const std::vector<const struct AttributePattern>& unknownPatterns,
+        hidl_vec<IOmxStore::Attribute> attributes) {
+    std::set<const std::string> attributeKeys;
+    for (const auto& attr : attributes) {
+        // Make sure there are no duplicates
+        const auto [nodeIter, inserted] = attributeKeys.insert(attr.key);
+        EXPECT_EQ(inserted, true) << "Attribute \"" << attr.key << "\" has duplicates.";
+
+        // Check the value against the corresponding regular
+        // expression.
+        const auto knownPattern = knownPatterns.find(attr.key);
+        if (knownPattern != knownPatterns.end()) {
+            EXPECT_EQ(testing::internal::RE::FullMatch(attr.value, knownPattern->second), true)
+                    << "Attribute \"" << attr.key << "\" has invalid value \"" << attr.value << ".";
+            ;
+        } else {
+            // Failed to find exact attribute, check against
+            // possible patterns.
+            bool keyFound = false;
+            for (const auto& unknownPattern : unknownPatterns) {
+                if (testing::internal::RE::PartialMatch(attr.key, unknownPattern.key)) {
+                    keyFound = true;
+                    EXPECT_EQ(testing::internal::RE::FullMatch(attr.value, unknownPattern.value),
+                              true)
+                            << "Attribute \"" << attr.key << "\" has invalid value \"" << attr.value
+                            << ".";
+                }
+            }
+            if (!keyFound) {
+                std::cout << "Warning, Unrecognized attribute \"" << attr.key << "\" with value \""
+                          << attr.value << "\"." << std::endl;
+            }
+        }
+    }
+}
+
 // Make sure IOmx and IOmxStore have the same set of instances.
 TEST(MasterHidlTest, instanceMatchValidation) {
     auto omxInstances = android::hardware::getAllHalInstanceNames(IOmx::descriptor);
@@ -91,7 +137,7 @@
     }
 }
 
-// list service attributes
+// list service attributes and verify expected formats
 TEST_P(MasterHidlTest, ListServiceAttr) {
     description("list service attributes");
     android::hardware::media::omx::V1_0::Status status;
@@ -105,7 +151,36 @@
                     })
                     .isOk());
     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
-    if (attributes.size() == 0) ALOGV("Warning, Attribute list empty");
+    if (attributes.size() == 0) {
+        std::cout << "Warning, Attribute list empty" << std::endl;
+    } else {
+        /*
+         * knownPatterns is a map whose keys are the known "key" for a service
+         * attribute pair (see IOmxStore::Attribute), and whose values are the
+         * corresponding regular expressions that will have to match with the
+         * "value" of the attribute pair. If listServiceAttributes() returns an
+         * attribute that has a matching key but an unmatched value, the test
+         * will fail.
+         */
+        const std::map<const std::string, const testing::internal::RE> knownPatterns = {
+                {"max-video-encoder-input-buffers", "0|[1-9][0-9]*"},
+                {"supports-multiple-secure-codecs", "0|1"},
+                {"supports-secure-with-non-secure-codec", "0|1"},
+        };
+        /*
+         * unknownPatterns is a vector of pairs of regular expressions.
+         * For each attribute whose key is not known (i.e., does not match any
+         * of the keys in the "knownPatterns" variable defined above), that key will be
+         * tried for a match with the first element of each pair of the variable
+         * "unknownPatterns". If a match occurs, the value of that same attribute will be
+         * tried for a match with the second element of the pair. If this second
+         * match fails, the test will fail.
+         */
+        const std::vector<const struct AttributePattern> unknownPatterns = {
+                {"supports-[a-z0-9-]*", "0|1"}};
+
+        validateAttributes(knownPatterns, unknownPatterns, attributes);
+    }
 }
 
 // get node prefix
@@ -114,17 +189,184 @@
     hidl_string prefix;
     omxStore->getNodePrefix(
         [&prefix](hidl_string const& _nl) { prefix = _nl; });
-    if (prefix.empty()) ALOGV("Warning, Node Prefix empty");
+    if (prefix.empty()) std::cout << "Warning, Node Prefix empty" << std::endl;
 }
 
-// list roles
+// list roles and validate all RoleInfo objects
 TEST_P(MasterHidlTest, ListRoles) {
     description("list roles");
     hidl_vec<IOmxStore::RoleInfo> roleList;
     omxStore->listRoles([&roleList](hidl_vec<IOmxStore::RoleInfo> const& _nl) {
         roleList = _nl;
     });
-    if (roleList.size() == 0) ALOGV("Warning, RoleInfo list empty");
+    if (roleList.size() == 0) {
+        GTEST_SKIP() << "Warning, RoleInfo list empty";
+        return;
+    }
+
+    // Basic patterns for matching
+    const std::string toggle = "(0|1)";
+    const std::string string = "(.*)";
+    const std::string num = "(0|([1-9][0-9]*))";
+    const std::string size = "(" + num + "x" + num + ")";
+    const std::string ratio = "(" + num + ":" + num + ")";
+    const std::string range_num = "((" + num + "-" + num + ")|" + num + ")";
+    const std::string range_size = "((" + size + "-" + size + ")|" + size + ")";
+    const std::string range_ratio = "((" + ratio + "-" + ratio + ")|" + ratio + ")";
+    const std::string list_range_num = "(" + range_num + "(," + range_num + ")*)";
+
+    // Matching rules for node attributes with fixed keys
+    const std::map<const std::string, const testing::internal::RE> knownPatterns = {
+            {"alignment", size},
+            {"bitrate-range", range_num},
+            {"block-aspect-ratio-range", range_ratio},
+            {"block-count-range", range_num},
+            {"block-size", size},
+            {"blocks-per-second-range", range_num},
+            {"complexity-default", num},
+            {"complexity-range", range_num},
+            {"feature-adaptive-playback", toggle},
+            {"feature-bitrate-control", "(VBR|CBR|CQ)[,(VBR|CBR|CQ)]*"},
+            {"feature-can-swap-width-height", toggle},
+            {"feature-intra-refresh", toggle},
+            {"feature-partial-frame", toggle},
+            {"feature-secure-playback", toggle},
+            {"feature-tunneled-playback", toggle},
+            {"frame-rate-range", range_num},
+            {"max-channel-count", num},
+            {"max-concurrent-instances", num},
+            {"max-supported-instances", num},
+            {"pixel-aspect-ratio-range", range_ratio},
+            {"quality-default", num},
+            {"quality-range", range_num},
+            {"quality-scale", string},
+            {"sample-rate-ranges", list_range_num},
+            {"size-range", range_size},
+    };
+
+    // Strings for matching rules for node attributes with key patterns
+    const std::vector<const struct AttributePattern> unknownPatterns = {
+            {"measured-frame-rate-" + size + "-range", range_num},
+            {"feature-[a-zA-Z0-9_-]+", string},
+    };
+
+    // Matching rules for node names and owners
+    const testing::internal::RE nodeNamePattern = "[a-zA-Z0-9._-]+";
+    const testing::internal::RE nodeOwnerPattern = "[a-zA-Z0-9._-]+";
+
+    std::set<const std::string> roleKeys;
+    std::map<const std::string, std::set<const std::string>> nodeToRoles;
+    std::map<const std::string, std::set<const std::string>> ownerToNodes;
+    for (const IOmxStore::RoleInfo& role : roleList) {
+        // Make sure there are no duplicates
+        const auto [roleIter, inserted] = roleKeys.insert(role.role);
+        EXPECT_EQ(inserted, true) << "Role \"" << role.role << "\" has duplicates.";
+
+        // Make sure role name follows expected format based on type and
+        // isEncoder
+        const std::string role_name(
+                ::android::GetComponentRole(role.isEncoder, role.type.c_str()));
+        EXPECT_EQ(role_name, role.role) << "Role \"" << role.role << "\" does not match "
+                                        << (role.isEncoder ? "an encoder " : "a decoder ")
+                                        << "for mime type \"" << role.type << ".";
+
+        // Check the nodes for this role
+        std::set<const std::string> nodeKeys;
+        for (const IOmxStore::NodeInfo& node : role.nodes) {
+            // Make sure there are no duplicates
+            const auto [nodeIter, inserted] = nodeKeys.insert(node.name);
+            EXPECT_EQ(inserted, true) << "Node \"" << node.name << "\" has duplicates.";
+
+            // Check the format of node name
+            EXPECT_EQ(testing::internal::RE::FullMatch(node.name, nodeNamePattern), true)
+                    << "Node name \"" << node.name << " is invalid.";
+            // Check the format of node owner
+            EXPECT_EQ(testing::internal::RE::FullMatch(node.owner, nodeOwnerPattern), true)
+                    << "Node owner \"" << node.owner << " is invalid.";
+
+            validateAttributes(knownPatterns, unknownPatterns, node.attributes);
+
+            ownerToNodes[node.owner].insert(node.name);
+            nodeToRoles[node.name].insert(role.role);
+        }
+    }
+
+    // Verify the information with IOmx::listNodes().
+    // IOmxStore::listRoles() and IOmx::listNodes() should give consistent
+    // information about nodes and roles.
+    for (const auto& [owner, nodes] : ownerToNodes) {
+        // Obtain the IOmx instance for each "owner"
+        const sp<IOmx> omx = omxStore->getOmx(owner);
+        EXPECT_NE(nullptr, omx);
+
+        // Invoke IOmx::listNodes()
+        android::hardware::media::omx::V1_0::Status status;
+        hidl_vec<IOmx::ComponentInfo> nodeList;
+        EXPECT_TRUE(
+                omx->listNodes([&status, &nodeList](android::hardware::media::omx::V1_0::Status _s,
+                                                    hidl_vec<IOmx::ComponentInfo> const& _nl) {
+                       status = _s;
+                       nodeList = _nl;
+                   }).isOk());
+        ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
+
+        // Verify that roles for each node match with the information from
+        // IOmxStore::listRoles().
+        std::set<const std::string> nodeKeys;
+        for (IOmx::ComponentInfo node : nodeList) {
+            // Make sure there are no duplicates
+            const auto [nodeIter, inserted] = nodeKeys.insert(node.mName);
+            EXPECT_EQ(inserted, true)
+                    << "IOmx::listNodes() lists duplicate nodes \"" << node.mName << "\".";
+
+            // Skip "hidden" nodes, i.e. those that are not advertised by
+            // IOmxStore::listRoles().
+            if (nodes.find(node.mName) == nodes.end()) {
+                std::cout << "Warning, IOmx::listNodes() lists unknown node \"" << node.mName
+                          << "\" for IOmx instance \"" << owner << "\"." << std::endl;
+                continue;
+            }
+
+            // All the roles advertised by IOmxStore::listRoles() for this
+            // node must be included in roleKeys.
+            std::set<const std::string> difference;
+            std::set_difference(nodeToRoles[node.mName].begin(), nodeToRoles[node.mName].end(),
+                                roleKeys.begin(), roleKeys.end(),
+                                std::inserter(difference, difference.begin()));
+            EXPECT_EQ(difference.empty(), true) << "IOmx::listNodes() for IOmx "
+                                                   "instance \""
+                                                << owner
+                                                << "\" does not report some "
+                                                   "expected nodes: "
+                                                << android::base::Join(difference, ", ") << ".";
+        }
+        // Check that all nodes obtained from IOmxStore::listRoles() are
+        // supported by the their corresponding IOmx instances.
+        std::set<const std::string> difference;
+        std::set_difference(nodes.begin(), nodes.end(), nodeKeys.begin(), nodeKeys.end(),
+                            std::inserter(difference, difference.begin()));
+        EXPECT_EQ(difference.empty(), true) << "IOmx::listNodes() for IOmx "
+                                               "instance \""
+                                            << owner
+                                            << "\" does not report some "
+                                               "expected nodes: "
+                                            << android::base::Join(difference, ", ") << ".";
+    }
+
+    if (!nodeToRoles.empty()) {
+        // Check that the prefix is a sensible string.
+        hidl_string prefix;
+        omxStore->getNodePrefix([&prefix](hidl_string const& _nl) { prefix = _nl; });
+        EXPECT_EQ(testing::internal::RE::PartialMatch(prefix, nodeNamePattern), true)
+                << "\"" << prefix << "\" is not a valid prefix for node names.";
+
+        // Check that all node names have the said prefix.
+        for (const auto& node : nodeToRoles) {
+            EXPECT_NE(node.first.rfind(prefix, 0), std::string::npos)
+                    << "Node \"" << node.first << "\" does not start with prefix \"" << prefix
+                    << "\".";
+        }
+    }
 }
 
 // list components and roles.
@@ -143,7 +385,7 @@
             .isOk());
     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
     if (nodeList.size() == 0)
-        ALOGV("Warning, ComponentInfo list empty");
+        std::cout << "Warning, ComponentInfo list empty" << std::endl;
     else {
         // displayComponentInfo(nodeList);
         for (size_t i = 0; i < nodeList.size(); i++) {
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index 6583dfe..3375602 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -476,7 +476,7 @@
         case OperandType::TENSOR_QUANT8_ASYMM:
             return {-1, 256};
         case OperandType::TENSOR_QUANT8_SYMM:
-          return {-129, -1, 1, 128};
+            return {-129, -1, 1, 128};
         case OperandType::TENSOR_QUANT16_ASYMM:
             return {-1, 65536};
         case OperandType::TENSOR_QUANT16_SYMM:
@@ -1008,15 +1008,15 @@
                 }
             }
         }
-        // BIDIRECTIONAL_SEQUENCE_LSTM and BIDIRECTIONAL_SEQUENCE_RNN can have
-        // either one or two outputs depending on their mergeOutputs parameter.
+        // 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 ||
             operation.type == OperationType::BIDIRECTIONAL_SEQUENCE_RNN) {
-          for (const size_t outOprand : operation.outputs) {
-            if (operand == outOprand) {
-              return true;
+            for (const size_t outOprand : operation.outputs) {
+                if (operand == outOprand) {
+                    return true;
+                }
             }
-          }
         }
     }
     return false;
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index 0b8e68e..b17d445 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -78,5 +78,8 @@
     header_libs: [
         "libneuralnetworks_headers",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
index b2734e7..d011c30 100644
--- a/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
+++ b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
@@ -19,6 +19,8 @@
 
 #include <cutils/properties.h>
 
+#include <android-base/file.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <android/hardware/power/1.0/IPower.h>
 #include <gtest/gtest.h>
@@ -73,26 +75,16 @@
 TEST_P(PowerHidlTest, TryDifferentGovernors) {
   Return<void> ret;
 
-  unique_fd fd1(open(CPU_GOVERNOR_PATH, O_RDWR));
-  unique_fd fd2(open(AVAILABLE_GOVERNORS_PATH, O_RDONLY));
-  if (fd1 < 0 || fd2 < 0) {
+  std::string old_governor, governors;
+  if (!android::base::ReadFileToString(CPU_GOVERNOR_PATH, &old_governor) ||
+      !android::base::ReadFileToString(AVAILABLE_GOVERNORS_PATH, &governors)) {
     // Files don't exist, so skip the rest of the test case
     SUCCEED();
     return;
   }
-
-  char old_governor[80];
-  ASSERT_LE(0, read(fd1, old_governor, 80));
-
-  char governors[1024];
-  unsigned len = read(fd2, governors, 1024);
-  ASSERT_LE(0u, len);
-  governors[len] = '\0';
-
-  char *saveptr;
-  char *name = strtok_r(governors, " \n", &saveptr);
-  while (name) {
-    ASSERT_LE(0, write(fd1, name, strlen(name)));
+  auto all_governors = android::base::Split(governors, " \n");
+  for (const auto &governor : all_governors) {
+      ASSERT_TRUE(android::base::WriteStringToFile(governor, CPU_GOVERNOR_PATH));
     ret = power->setInteractive(true);
     ASSERT_TRUE(ret.isOk());
 
@@ -104,11 +96,9 @@
 
     power->powerHint(PowerHint::LAUNCH, 1);
     power->powerHint(PowerHint::LAUNCH, 0);
-
-    name = strtok_r(NULL, " \n", &saveptr);
   }
 
-  ASSERT_LE(0, write(fd1, old_governor, strlen(old_governor)));
+  ASSERT_TRUE(android::base::WriteStringToFile(old_governor, CPU_GOVERNOR_PATH));
 }
 
 // Validate Power::powerHint on good and bad inputs.
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
index e428f0d..3f96473 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
@@ -644,7 +644,7 @@
     LOG(DEBUG) << "nvResetConfig";
     serial = GetRandomSerialNumber();
 
-    radio->nvResetConfig(serial, ResetNvType::ERASE);
+    radio->nvResetConfig(serial, ResetNvType::FACTORY_RESET);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
     EXPECT_EQ(serial, radioRsp->rspInfo.serial);
diff --git a/radio/1.0/vts/functional/vts_hal_radio_target_test.xml b/radio/1.0/vts/functional/vts_hal_radio_target_test.xml
index 082577e..82af2ee 100644
--- a/radio/1.0/vts/functional/vts_hal_radio_target_test.xml
+++ b/radio/1.0/vts/functional/vts_hal_radio_target_test.xml
@@ -17,9 +17,10 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-native" />
 
+    <!-- TODO: b/154638140, b/152655658: bad interactions -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
-    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
diff --git a/radio/1.0/vts/functional/vts_hal_sap_target_test.xml b/radio/1.0/vts/functional/vts_hal_sap_target_test.xml
index 457d700..d7d4477 100644
--- a/radio/1.0/vts/functional/vts_hal_sap_target_test.xml
+++ b/radio/1.0/vts/functional/vts_hal_sap_target_test.xml
@@ -17,9 +17,12 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-native" />
 
+    <!-- TODO: b/154638140, b/152655658: bad interactions -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
-    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
diff --git a/radio/1.1/vts/functional/AndroidTest.xml b/radio/1.1/vts/functional/AndroidTest.xml
index 252b72f..f1bc7a8 100644
--- a/radio/1.1/vts/functional/AndroidTest.xml
+++ b/radio/1.1/vts/functional/AndroidTest.xml
@@ -17,9 +17,10 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-native" />
 
+    <!-- TODO: b/154638140, b/152655658: bad interactions -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
-    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
index 02dcbab..08121fd 100644
--- a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
@@ -49,7 +49,6 @@
         }
         EXPECT_EQ(CardState::ABSENT, cardStatus.cardState);
     }
-#endif
 
     /* Test setSimCardPower power up */
     serial = GetRandomSerialNumber();
@@ -60,6 +59,7 @@
     ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_1->rspInfo.error,
                                  {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
                                   RadioError::INVALID_ARGUMENTS, RadioError::RADIO_NOT_AVAILABLE}));
+#endif
 
     /**
      * If the sim card status for the testing environment is PRESENT,
diff --git a/radio/1.2/vts/functional/AndroidTest.xml b/radio/1.2/vts/functional/AndroidTest.xml
index 5d92248..9904760 100644
--- a/radio/1.2/vts/functional/AndroidTest.xml
+++ b/radio/1.2/vts/functional/AndroidTest.xml
@@ -17,9 +17,10 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-native" />
 
+    <!-- TODO: b/154638140, b/152655658: bad interactions -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
-    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
diff --git a/radio/1.3/vts/functional/AndroidTest.xml b/radio/1.3/vts/functional/AndroidTest.xml
index c910047..9df8f9c 100644
--- a/radio/1.3/vts/functional/AndroidTest.xml
+++ b/radio/1.3/vts/functional/AndroidTest.xml
@@ -17,9 +17,10 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-native" />
 
+    <!-- TODO: b/154638140, b/152655658: bad interactions -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
-    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
diff --git a/radio/1.4/types.hal b/radio/1.4/types.hal
index a830816..393716b 100644
--- a/radio/1.4/types.hal
+++ b/radio/1.4/types.hal
@@ -1847,9 +1847,9 @@
     /**
      * SS reference signal received quality, multipled by -1.
      *
-     * Reference: 3GPP TS 38.215, 3GPP TS 38.133 section 10.
+     * Reference: 3GPP TS 38.215.
      *
-     * Range [-20 dB, 43 dB], INT_MAX means invalid/unreported.
+     * Range [3, 20], INT_MAX means invalid/unreported.
      */
     int32_t ssRsrq;
 
diff --git a/radio/1.4/vts/functional/AndroidTest.xml b/radio/1.4/vts/functional/AndroidTest.xml
index c910047..9df8f9c 100644
--- a/radio/1.4/vts/functional/AndroidTest.xml
+++ b/radio/1.4/vts/functional/AndroidTest.xml
@@ -17,9 +17,10 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-native" />
 
+    <!-- TODO: b/154638140, b/152655658: bad interactions -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
-    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index c1f3f03..b061bd5 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -107,9 +107,9 @@
     SSRSRP = 6,
     /**
      * 5G SS reference signal received quality.
-     * Range: -43 dB to 20 dB.
+     * Range: -20 dB to -3 dB.
      * Used RAN: NGRAN
-     * Reference: 3GPP TS 38.215, 3GPP TS 38.133 section 10
+     * Reference: 3GPP TS 38.215.
      */
     SSRSRQ = 7,
     /**
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 3cc5666..24b7fd5 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/properties.h>
 #include <radio_hidl_hal_utils_v1_5.h>
 
 #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
@@ -1214,7 +1215,7 @@
     cdmaSmsMessage.address = cdmaSmsAddress;
     cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
     cdmaSmsMessage.bearerData =
-        (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+            (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
 
     radio_v1_5->sendCdmaSmsExpectMore(serial, cdmaSmsMessage);
 
@@ -1224,9 +1225,9 @@
 
     if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_v1_5->rspInfo.error,
-            {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
-            CHECK_GENERAL_ERROR));
+                radioRsp_v1_5->rspInfo.error,
+                {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
+                CHECK_GENERAL_ERROR));
     }
 }
 
@@ -1241,6 +1242,17 @@
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
 
+    int32_t firstApiLevel = android::base::GetIntProperty<int32_t>("ro.product.first_api_level", 0);
+    // Allow devices shipping with Radio::1_5 and Android 11 to not support barring info.
+    if (firstApiLevel > 0 && firstApiLevel <= 30) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
+                                     {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+        // Early exit for devices that don't support barring info.
+        if (radioRsp_v1_5->rspInfo.error != RadioError::NONE) {
+            return;
+        }
+    }
+
     ASSERT_TRUE(radioRsp_v1_5->barringInfos.size() > 0);
 
     std::set<BarringInfo::ServiceType> reportedServices;
diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp
new file mode 100644
index 0000000..75faa1a
--- /dev/null
+++ b/rebootescrow/aidl/Android.bp
@@ -0,0 +1,19 @@
+aidl_interface {
+    name: "android.hardware.rebootescrow",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/rebootescrow/IRebootEscrow.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+    versions: ["1"],
+}
diff --git a/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/.hash b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/.hash
new file mode 100644
index 0000000..dcee3cc
--- /dev/null
+++ b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/.hash
@@ -0,0 +1 @@
+ba450432e0dab8ee7bbc30013819ea8aef12054b
diff --git a/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/android/hardware/rebootescrow/IRebootEscrow.aidl b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/android/hardware/rebootescrow/IRebootEscrow.aidl
new file mode 100644
index 0000000..ea669a3
--- /dev/null
+++ b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/1/android/hardware/rebootescrow/IRebootEscrow.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.rebootescrow;
+@VintfStability
+interface IRebootEscrow {
+  void storeKey(in byte[] kek);
+  byte[] retrieveKey();
+}
diff --git a/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/current/android/hardware/rebootescrow/IRebootEscrow.aidl b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/current/android/hardware/rebootescrow/IRebootEscrow.aidl
new file mode 100644
index 0000000..ea669a3
--- /dev/null
+++ b/rebootescrow/aidl/aidl_api/android.hardware.rebootescrow/current/android/hardware/rebootescrow/IRebootEscrow.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.rebootescrow;
+@VintfStability
+interface IRebootEscrow {
+  void storeKey(in byte[] kek);
+  byte[] retrieveKey();
+}
diff --git a/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl b/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl
new file mode 100644
index 0000000..edc695d
--- /dev/null
+++ b/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.rebootescrow;
+
+/**
+ * This HAL defines the interface to the device-specific implementation
+ * of retaining a secret to unlock the Synthetic Password stored during
+ * a reboot to perform an OTA update. The implementation of this interface
+ * should never store the key on any non-volatile medium. The key should be
+ * overwritten with zeroes when destroyKey() is called. All care should be given
+ * to provide the shortest lifetime for the storage of the key in volatile and
+ * erasable storage.
+ *
+ * This HAL is optional so does not require an implementation on device.
+ */
+@VintfStability
+interface IRebootEscrow {
+    /**
+     * Store the key for reboot.
+     */
+    void storeKey(in byte[] kek);
+
+    /**
+     * Retrieve the possible keys. If the implementation is probabalistic, it
+     * should return the keys in order from most-probable to least-probable.
+     * There is not a hard limit to the number of keys, but it is suggested to
+     * keep the number of key possibilities less than 32.
+     */
+    byte[] retrieveKey();
+}
diff --git a/rebootescrow/aidl/default/Android.bp b/rebootescrow/aidl/default/Android.bp
new file mode 100644
index 0000000..b77272f
--- /dev/null
+++ b/rebootescrow/aidl/default/Android.bp
@@ -0,0 +1,88 @@
+//
+// 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_library_static {
+    name: "librebootescrowdefaultimpl",
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.rebootescrow-ndk_platform",
+    ],
+    export_include_dirs: ["include"],
+    srcs: [
+        "RebootEscrow.cpp",
+    ],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.rebootescrow-service.default",
+    init_rc: ["rebootescrow-default.rc"],
+    relative_install_path: "hw",
+    vintf_fragments: ["rebootescrow-default.xml"],
+    vendor: true,
+    srcs: [
+        "service.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.rebootescrow-ndk_platform",
+    ],
+    static_libs: [
+        "libhadamardutils",
+        "librebootescrowdefaultimpl",
+    ],
+}
+
+cc_library_static {
+    name: "libhadamardutils",
+    vendor_available: true,
+    host_supported: true,
+    shared_libs: [
+        "libbase",
+    ],
+    srcs: [
+        "HadamardUtils.cpp",
+    ],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
+cc_test {
+    name: "HadamardUtilsTest",
+    host_supported: true,
+    srcs: [
+        "HadamardUtilsTest.cpp",
+    ],
+    static_libs: [
+        "libhadamardutils",
+        "libgtest_prod",
+    ],
+    shared_libs: [
+        "liblog",
+        "libbase",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp
new file mode 100644
index 0000000..adb2010
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtils.cpp
@@ -0,0 +1,181 @@
+/*
+ * 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 <HadamardUtils.h>
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+namespace hadamard {
+
+static inline uint8_t read_bit(const std::vector<uint8_t>& input, size_t bit) {
+    return (input[bit >> 3] >> (bit & 7)) & 1u;
+}
+
+// Use a simple LCG which is easy to run in reverse.
+// https://www.johndcook.com/blog/2017/07/05/simple-random-number-generator/
+constexpr uint64_t RNG_MODULUS = 0x7fffffff;
+constexpr uint64_t RNG_MUL = 742938285;
+constexpr uint64_t RNG_SEED = 20170705;
+constexpr uint64_t RNG_INV_MUL = 1413043504;   // (mul * inv_mul) % modulus == 1
+constexpr uint64_t RNG_INV_SEED = 1173538311;  // (seed * mul**65534) % modulus
+
+// Apply an error correcting encoding.
+//
+// The error correcting code used is an augmented Hadamard code with
+// k=15, so it takes a 16-bit input and produces a 2^15-bit output.
+// We break the 32-byte key into 16 16-bit codewords and encode
+// each codeword to a 2^15-bit output.
+//
+// To better defend against clustered errors, we stripe together the encoded
+// codewords. Thus if a single 512-byte DRAM line is lost, instead of losing
+// 2^11 bits from the encoding of a single code word, we lose 2^7 bits
+// from the encoding of each of the 16 codewords.
+// In addition we apply a Fisher-Yates shuffle to the bytes of the encoding;
+// Hadamard encoding recovers much better from random errors than systematic
+// ones, and this ensures that errors will be random.
+std::vector<uint8_t> EncodeKey(const std::vector<uint8_t>& input) {
+    CHECK_EQ(input.size(), KEY_SIZE_IN_BYTES);
+    std::vector<uint8_t> result(OUTPUT_SIZE_BYTES, 0);
+    static_assert(OUTPUT_SIZE_BYTES == 64 * 1024);
+    // Transpose the key so that each row contains one bit from each codeword
+    uint16_t wordmatrix[CODEWORD_BITS];
+    for (size_t i = 0; i < CODEWORD_BITS; i++) {
+        uint16_t word = 0;
+        for (size_t j = 0; j < KEY_CODEWORDS; j++) {
+            word |= read_bit(input, i + j * CODEWORD_BITS) << j;
+        }
+        wordmatrix[i] = word;
+    }
+    // Fill in the encodings in Gray code order for speed.
+    uint16_t val = wordmatrix[CODEWORD_BITS - 1];
+    size_t ix = 0;
+    for (size_t i = 0; i < ENCODE_LENGTH; i++) {
+        for (size_t b = 0; b < CODEWORD_BITS; b++) {
+            if (i & (1 << b)) {
+                ix ^= (1 << b);
+                val ^= wordmatrix[b];
+                break;
+            }
+        }
+        result[ix * KEY_CODEWORD_BYTES] = val & 0xffu;
+        result[ix * KEY_CODEWORD_BYTES + 1] = val >> 8u;
+    }
+    // Apply the inverse shuffle here; we apply the forward shuffle in decoding.
+    uint64_t rng_state = RNG_INV_SEED;
+    for (size_t i = OUTPUT_SIZE_BYTES - 1; i > 0; i--) {
+        auto j = rng_state % (i + 1);
+        auto t = result[i];
+        result[i] = result[j];
+        result[j] = t;
+        rng_state *= RNG_INV_MUL;
+        rng_state %= RNG_MODULUS;
+    }
+    return result;
+}
+
+// Constant-time conditional copy, to fix b/146520538
+// ctl must be 0 or 1; we do the copy if it's 1.
+static void CondCopy(uint32_t ctl, void* dest, const void* src, size_t len) {
+    const auto cdest = reinterpret_cast<uint8_t*>(dest);
+    const auto csrc = reinterpret_cast<const uint8_t*>(src);
+    for (size_t i = 0; i < len; i++) {
+        const uint32_t d = cdest[i];
+        const uint32_t s = csrc[i];
+        cdest[i] = d ^ (-ctl & (s ^ d));
+    }
+}
+
+struct CodewordWinner {
+    uint16_t codeword;
+    int32_t score;
+};
+
+// Replace dest with src if it has a higher score
+static void CopyWinner(CodewordWinner* dest, const CodewordWinner& src) {
+    // Scores are between - 2^15 and 2^15, so taking the difference won't
+    // overflow; we use the sign bit of the difference here.
+    CondCopy(static_cast<uint32_t>(dest->score - src.score) >> 31, dest, &src,
+             sizeof(CodewordWinner));
+}
+
+// Decode a single codeword. Because of the way codewords are striped together
+// this takes the entire input, plus an offset telling it which word to decode.
+static uint16_t DecodeWord(size_t word, const std::vector<uint8_t>& encoded) {
+    std::vector<int32_t> scores;
+    scores.reserve(ENCODE_LENGTH);
+    // Convert x -> -1^x in the encoded bits. e.g [1, 0, 0, 1] -> [-1, 1, 1, -1]
+    for (uint32_t i = 0; i < ENCODE_LENGTH; i++) {
+        scores.push_back(1 - 2 * read_bit(encoded, i * KEY_CODEWORDS + word));
+    }
+
+    // Multiply the hadamard matrix by the transformed input.
+    // |1  1  1  1|     |-1|     | 0|
+    // |1 -1  1 -1|  *  | 1|  =  | 0|
+    // |1  1 -1 -1|     | 1|     | 0|
+    // |1 -1 -1  1|     |-1|     |-4|
+    for (uint32_t i = 0; i < CODE_K; i++) {
+        uint16_t step = 1u << i;
+        for (uint32_t j = 0; j < ENCODE_LENGTH; j += 2 * step) {
+            for (uint32_t k = j; k < j + step; k++) {
+                auto a0 = scores[k];
+                auto a1 = scores[k + step];
+                scores[k] = a0 + a1;
+                scores[k + step] = a0 - a1;
+            }
+        }
+    }
+    // -ENCODE_LENGTH is least possible score, so start one less than that
+    auto best = CodewordWinner{0, -static_cast<int32_t>(ENCODE_LENGTH + 1)};
+    // For every possible codeword value, look at its score, and replace best if it's higher,
+    // in constant time.
+    for (size_t i = 0; i < ENCODE_LENGTH; i++) {
+        CopyWinner(&best, CodewordWinner{static_cast<uint16_t>(i), scores[i]});
+        CopyWinner(&best, CodewordWinner{static_cast<uint16_t>(i | (1 << CODE_K)), -scores[i]});
+    }
+    return best.codeword;
+}
+
+std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& shuffled) {
+    CHECK_EQ(OUTPUT_SIZE_BYTES, shuffled.size());
+    // Apply the forward Fisher-Yates shuffle.
+    std::vector<uint8_t> encoded(OUTPUT_SIZE_BYTES, 0);
+    encoded[0] = shuffled[0];
+    uint64_t rng_state = RNG_SEED;
+    for (size_t i = 1; i < OUTPUT_SIZE_BYTES; i++) {
+        auto j = rng_state % (i + 1);
+        encoded[i] = encoded[j];
+        encoded[j] = shuffled[i];
+        rng_state *= RNG_MUL;
+        rng_state %= RNG_MODULUS;
+    }
+    std::vector<uint8_t> result(KEY_SIZE_IN_BYTES, 0);
+    for (size_t i = 0; i < KEY_CODEWORDS; i++) {
+        uint16_t val = DecodeWord(i, encoded);
+        result[i * CODEWORD_BYTES] = val & 0xffu;
+        result[i * CODEWORD_BYTES + 1] = val >> 8u;
+    }
+    return result;
+}
+
+}  // namespace hadamard
+}  // namespace rebootescrow
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/rebootescrow/aidl/default/HadamardUtils.h b/rebootescrow/aidl/default/HadamardUtils.h
new file mode 100644
index 0000000..e04f7d5
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtils.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <vector>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+namespace hadamard {
+
+constexpr auto BYTE_LENGTH = 8u;
+constexpr auto CODEWORD_BYTES = 2u;  // uint16_t
+constexpr auto CODEWORD_BITS = CODEWORD_BYTES * BYTE_LENGTH;
+constexpr uint32_t CODE_K = CODEWORD_BITS - 1;
+constexpr uint32_t ENCODE_LENGTH = 1u << CODE_K;
+constexpr auto KEY_CODEWORD_BYTES = 2u;  // uint16_t (after transpose)
+constexpr auto KEY_CODEWORDS = KEY_CODEWORD_BYTES * BYTE_LENGTH;
+constexpr auto KEY_SIZE_IN_BYTES = KEY_CODEWORDS * CODEWORD_BYTES;
+constexpr auto OUTPUT_SIZE_BYTES = ENCODE_LENGTH * KEY_CODEWORD_BYTES;
+
+// Encodes a key that has a size of KEY_SIZE_IN_BYTES. Returns a byte array representation of the
+// encoded bitset. So a 32 bytes key will expand to 16*(2^15) bits = 64KiB.
+std::vector<uint8_t> EncodeKey(const std::vector<uint8_t>& input);
+
+// Given a byte array representation of the encoded keys, decodes it and return the result.
+std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& encoded);
+
+}  // namespace hadamard
+}  // namespace rebootescrow
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/rebootescrow/aidl/default/HadamardUtilsTest.cpp b/rebootescrow/aidl/default/HadamardUtilsTest.cpp
new file mode 100644
index 0000000..1c9a2fb
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtilsTest.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 <stdint.h>
+#include <random>
+
+#include <gtest/gtest.h>
+
+#include <HadamardUtils.h>
+
+using namespace aidl::android::hardware::rebootescrow::hadamard;
+
+class HadamardTest : public testing::Test {};
+
+static void AddError(std::vector<uint8_t>* data) {
+    for (size_t i = 0; i < data->size(); i++) {
+        for (size_t j = 0; j < BYTE_LENGTH; j++) {
+            if (random() % 100 < 47) {
+                (*data)[i] ^= (1 << j);
+            }
+        }
+    }
+}
+
+TEST_F(HadamardTest, Decode_error_correction) {
+    constexpr auto iteration = 10;
+    for (int i = 0; i < iteration; i++) {
+        std::vector<uint8_t> key;
+        for (int j = 0; j < KEY_SIZE_IN_BYTES; j++) {
+            key.emplace_back(random() & 0xff);
+        }
+        auto encoded = EncodeKey(key);
+        ASSERT_EQ(64 * 1024, encoded.size());
+        AddError(&encoded);
+        auto decoded = DecodeKey(encoded);
+        ASSERT_EQ(key, std::vector<uint8_t>(decoded.begin(), decoded.begin() + key.size()));
+    }
+}
diff --git a/rebootescrow/aidl/default/OWNERS b/rebootescrow/aidl/default/OWNERS
new file mode 100644
index 0000000..c5288d6
--- /dev/null
+++ b/rebootescrow/aidl/default/OWNERS
@@ -0,0 +1,2 @@
+kroot@google.com
+paulcrowley@google.com
diff --git a/rebootescrow/aidl/default/RebootEscrow.cpp b/rebootescrow/aidl/default/RebootEscrow.cpp
new file mode 100644
index 0000000..8e5e97c
--- /dev/null
+++ b/rebootescrow/aidl/default/RebootEscrow.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include "HadamardUtils.h"
+#include "rebootescrow-impl/RebootEscrow.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+
+using ::android::base::unique_fd;
+
+ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector<uint8_t>& ukek) {
+    int rawFd = TEMP_FAILURE_RETRY(::open(devicePath_.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
+    unique_fd fd(rawFd);
+    if (fd.get() < 0) {
+        LOG(WARNING) << "Could not open reboot escrow device";
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    auto encoded = hadamard::EncodeKey(ukek);
+
+    if (!::android::base::WriteFully(fd, encoded.data(), encoded.size())) {
+        LOG(WARNING) << "Could not write data fully to character device";
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector<uint8_t>* _aidl_return) {
+    int rawFd = TEMP_FAILURE_RETRY(::open(devicePath_.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+    unique_fd fd(rawFd);
+    if (fd.get() < 0) {
+        LOG(WARNING) << "Could not open reboot escrow device";
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    std::vector<uint8_t> encodedBytes(hadamard::OUTPUT_SIZE_BYTES);
+    if (!::android::base::ReadFully(fd, &encodedBytes[0], encodedBytes.size())) {
+        LOG(WARNING) << "Could not read device";
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    auto keyBytes = hadamard::DecodeKey(encodedBytes);
+
+    *_aidl_return = keyBytes;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace rebootescrow
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
new file mode 100644
index 0000000..cdbeb67
--- /dev/null
+++ b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/rebootescrow/BnRebootEscrow.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+
+class RebootEscrow : public BnRebootEscrow {
+  public:
+    explicit RebootEscrow(const std::string& devicePath) : devicePath_(devicePath) {}
+    ndk::ScopedAStatus storeKey(const std::vector<uint8_t>& kek) override;
+    ndk::ScopedAStatus retrieveKey(std::vector<uint8_t>* _aidl_return) override;
+
+  private:
+    const std::string devicePath_;
+};
+
+}  // namespace rebootescrow
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/rebootescrow/aidl/default/rebootescrow-default.rc b/rebootescrow/aidl/default/rebootescrow-default.rc
new file mode 100644
index 0000000..ad90465
--- /dev/null
+++ b/rebootescrow/aidl/default/rebootescrow-default.rc
@@ -0,0 +1,5 @@
+service vendor.rebootescrow-default /vendor/bin/hw/android.hardware.rebootescrow-service.default
+    interface aidl android.hardware.rebootescrow.IRebootEscrow/default
+    class hal
+    user system
+    group system
diff --git a/rebootescrow/aidl/default/rebootescrow-default.xml b/rebootescrow/aidl/default/rebootescrow-default.xml
new file mode 100644
index 0000000..0499fcc
--- /dev/null
+++ b/rebootescrow/aidl/default/rebootescrow-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.rebootescrow</name>
+        <fqname>IRebootEscrow/default</fqname>
+    </hal>
+</manifest>
diff --git a/rebootescrow/aidl/default/service.cpp b/rebootescrow/aidl/default/service.cpp
new file mode 100644
index 0000000..8a8086b
--- /dev/null
+++ b/rebootescrow/aidl/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 "rebootescrow-impl/RebootEscrow.h"
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::rebootescrow::RebootEscrow;
+
+constexpr auto kRebootEscrowDeviceProperty = "ro.rebootescrow.device";
+constexpr auto kRebootEscrowDeviceDefault = "/dev/access-kregistry";
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    auto rebootEscrowDevicePath =
+            android::base::GetProperty(kRebootEscrowDeviceProperty, kRebootEscrowDeviceDefault);
+    auto re = ndk::SharedRefBase::make<RebootEscrow>(rebootEscrowDevicePath);
+    const std::string instance = std::string() + RebootEscrow::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(re->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;
+}
diff --git a/rebootescrow/aidl/vts/OWNERS b/rebootescrow/aidl/vts/OWNERS
new file mode 100644
index 0000000..c5288d6
--- /dev/null
+++ b/rebootescrow/aidl/vts/OWNERS
@@ -0,0 +1,2 @@
+kroot@google.com
+paulcrowley@google.com
diff --git a/rebootescrow/aidl/vts/functional/Android.bp b/rebootescrow/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..5d51a53
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// 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: "VtsHalRebootEscrowTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalRebootEscrowTargetTest.cpp"],
+    shared_libs: [
+        "libbinder",
+    ],
+    static_libs: [
+        "android.hardware.rebootescrow-cpp",
+    ],
+    test_suites: [
+        "vts-core",
+    ],
+    require_root: true,
+}
diff --git a/rebootescrow/aidl/vts/functional/README.md b/rebootescrow/aidl/vts/functional/README.md
new file mode 100644
index 0000000..9ae5caf
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/README.md
@@ -0,0 +1,7 @@
+Many of the tests in this directory may require that TEE Keymaster
+"EARLY_BOOT_ONLY" keys be usable when this test runs. In order to accomplish
+this, a build of "vold" that omits the call to "earlyBootEnded()" function
+should be made. Then these DISABLED tests may be run successfully.
+
+The CTS test ResumeOnRebootHostTests will test the functionality without a
+special build.
diff --git a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
new file mode 100644
index 0000000..809a3b5
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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 <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android/hardware/rebootescrow/BnRebootEscrow.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+using android::sp;
+using android::String16;
+using android::hardware::rebootescrow::IRebootEscrow;
+
+#define SKIP_UNSUPPORTED \
+    if (rebootescrow == nullptr) GTEST_SKIP() << "Not supported on this device"
+
+/**
+ * This tests that the key can be written, read, and removed. It does not test
+ * that the key survives a reboot. That needs a host-based test.
+ *
+ * atest VtsHalRebootEscrowV1_0TargetTest
+ */
+class RebootEscrowAidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        rebootescrow = android::waitForDeclaredService<IRebootEscrow>(String16(GetParam().c_str()));
+    }
+
+    sp<IRebootEscrow> rebootescrow;
+
+    std::vector<uint8_t> KEY_1{
+            0xA5, 0x00, 0xFF, 0x01, 0xA5, 0x5a, 0xAA, 0x55, 0x00, 0xD3, 0x2A,
+            0x8C, 0x2E, 0x83, 0x0E, 0x65, 0x9E, 0x8D, 0xC6, 0xAC, 0x1E, 0x83,
+            0x21, 0xB3, 0x95, 0x02, 0x89, 0x64, 0x64, 0x92, 0x12, 0x1F,
+    };
+    std::vector<uint8_t> KEY_2{
+            0xFF, 0x00, 0x00, 0xAA, 0x5A, 0x19, 0x20, 0x71, 0x9F, 0xFB, 0xDA,
+            0xB6, 0x2D, 0x06, 0xD5, 0x49, 0x7E, 0xEF, 0x63, 0xAC, 0x18, 0xFF,
+            0x5A, 0xA3, 0x40, 0xBB, 0x64, 0xFA, 0x67, 0xC1, 0x10, 0x18,
+    };
+    std::vector<uint8_t> EMPTY_KEY{
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    };
+};
+
+// This test assumes that it can retrieve keys immediately, but some
+// implementations use the TEE's EARLY_BOOT_ONLY keys. This means that the
+// earlyBootEnded() calls will need to be disabled to test this correctly.
+TEST_P(RebootEscrowAidlTest, DISABLED_StoreAndRetrieve_Success) {
+    SKIP_UNSUPPORTED;
+
+    ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+
+    std::vector<uint8_t> actualKey;
+    ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+    EXPECT_EQ(actualKey, KEY_1);
+}
+
+// This test assumes that it can retrieve keys immediately, but some
+// implementations use the TEE's EARLY_BOOT_ONLY keys. This means that the
+// earlyBootEnded() calls will need to be disabled to test this correctly.
+TEST_P(RebootEscrowAidlTest, DISABLED_StoreAndRetrieve_SecondRetrieveSucceeds) {
+    SKIP_UNSUPPORTED;
+
+    ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+
+    std::vector<uint8_t> actualKey;
+    ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+    EXPECT_EQ(actualKey, KEY_1);
+
+    ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+    EXPECT_EQ(actualKey, KEY_1);
+}
+
+// This test assumes that it can retrieve keys immediately, but some
+// implementations use the TEE's EARLY_BOOT_ONLY keys. This means that the
+// earlyBootEnded() calls will need to be disabled to test this correctly.
+TEST_P(RebootEscrowAidlTest, DISABLED_StoreTwiceOverwrites_Success) {
+    SKIP_UNSUPPORTED;
+
+    ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+    ASSERT_TRUE(rebootescrow->storeKey(KEY_2).isOk());
+
+    std::vector<uint8_t> actualKey;
+    ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+    EXPECT_EQ(actualKey, KEY_2);
+}
+
+// This test assumes that it can retrieve keys immediately, but some
+// implementations use the TEE's EARLY_BOOT_ONLY keys. This means that the
+// earlyBootEnded() calls will need to be disabled to test this correctly.
+TEST_P(RebootEscrowAidlTest, DISABLED_StoreEmpty_AfterGetEmptyKey_Success) {
+    SKIP_UNSUPPORTED;
+
+    rebootescrow->storeKey(KEY_1);
+    rebootescrow->storeKey(EMPTY_KEY);
+
+    std::vector<uint8_t> actualKey;
+    ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+    EXPECT_EQ(actualKey, EMPTY_KEY);
+}
+
+TEST_P(RebootEscrowAidlTest, Store_Success) {
+    SKIP_UNSUPPORTED;
+
+    rebootescrow->storeKey(KEY_1);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        RebootEscrow, RebootEscrowAidlTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IRebootEscrow::descriptor)),
+        android::PrintInstanceNameToString);
diff --git a/sensors/1.0/default/OWNERS b/sensors/1.0/default/OWNERS
index 2031d84..90c2330 100644
--- a/sensors/1.0/default/OWNERS
+++ b/sensors/1.0/default/OWNERS
@@ -1,2 +1,3 @@
+arthuri@google.com
 bduddie@google.com
-bstack@google.com
+stange@google.com
diff --git a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
index b41730b..1af6d0b 100644
--- a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
+++ b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
@@ -2,6 +2,6 @@
     interface android.hardware.sensors@1.0::ISensors default
     class hal
     user system
-    group system wakelock uhid
+    group system wakelock uhid context_hub
     capabilities BLOCK_SUSPEND
     rlimit rtprio 10 10
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 1167fd4..4941ac2 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -20,17 +20,14 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "SensorsHidlEnvironmentV1_0.cpp",
-        "VtsHalSensorsV1_0TargetTest.cpp"
+        "VtsHalSensorsV1_0TargetTest.cpp",
     ],
     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",
         "VtsHalSensorsTargetTestUtils",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
-
diff --git a/sensors/1.0/vts/functional/OWNERS b/sensors/1.0/vts/functional/OWNERS
index 759d87b..892da15 100644
--- a/sensors/1.0/vts/functional/OWNERS
+++ b/sensors/1.0/vts/functional/OWNERS
@@ -1,6 +1,7 @@
 # Sensors team
+arthuri@google.com
 bduddie@google.com
-bstack@google.com
+stange@google.com
 
 # VTS team
 trong@google.com
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
index 1e5e886..aca6961 100644
--- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
@@ -25,6 +25,13 @@
 using ::android::hardware::sensors::V1_0::Result;
 using ::android::hardware::sensors::V1_0::SensorInfo;
 
+void SensorsHidlEnvironmentV1_0::HidlTearDown() {
+    mStopThread = true;
+    if (mPollThread.joinable()) {
+        mPollThread.detach();
+    }
+}
+
 bool SensorsHidlEnvironmentV1_0::resetHal() {
     // wait upto 100ms * 10 = 1s for hidl service.
     constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
@@ -103,18 +110,23 @@
     ALOGD("polling thread start");
 
     while (!stop) {
-        env->sensors->poll(
-            64, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) {
-                if (result != Result::OK ||
-                    (events.size() == 0 && dynamicSensorsAdded.size() == 0) || stop) {
-                    stop = true;
-                    return;
-                }
+        if (!env->sensors
+                     ->poll(64,
+                            [&](auto result, const auto& events, const auto& dynamicSensorsAdded) {
+                                if (result != Result::OK ||
+                                    (events.size() == 0 && dynamicSensorsAdded.size() == 0) ||
+                                    stop) {
+                                    stop = true;
+                                    return;
+                                }
 
-                for (const auto& e : events) {
-                    env->addEvent(e);
-                }
-            });
+                                for (const auto& e : events) {
+                                    env->addEvent(e);
+                                }
+                            })
+                     .isOk()) {
+            break;
+        }
     }
     ALOGD("polling thread end");
 }
\ No newline at end of file
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
index 29bfa50..168777d 100644
--- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
@@ -29,8 +29,11 @@
 using ::android::sp;
 
 class SensorsHidlTest;
-class SensorsHidlEnvironmentV1_0 : public SensorsHidlEnvironmentBase {
-   public:
+class SensorsHidlEnvironmentV1_0
+    : public SensorsHidlEnvironmentBase<::android::hardware::sensors::V1_0::Event> {
+  public:
+    void HidlTearDown() override;
+
     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 05be37b..56bc9cf 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>());
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SensorsHidlTest);
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/OWNERS b/sensors/2.0/default/OWNERS
index 2031d84..90c2330 100644
--- a/sensors/2.0/default/OWNERS
+++ b/sensors/2.0/default/OWNERS
@@ -1,2 +1,3 @@
+arthuri@google.com
 bduddie@google.com
-bstack@google.com
+stange@google.com
diff --git a/sensors/2.0/default/Sensor.cpp b/sensors/2.0/default/Sensor.cpp
deleted file mode 100644
index c09173f..0000000
--- a/sensors/2.0/default/Sensor.cpp
+++ /dev/null
@@ -1,373 +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 "Sensor.h"
-
-#include <utils/SystemClock.h>
-
-#include <cmath>
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::sensors::V1_0::MetaDataEventType;
-using ::android::hardware::sensors::V1_0::SensorFlagBits;
-using ::android::hardware::sensors::V1_0::SensorStatus;
-
-static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000;
-
-Sensor::Sensor(ISensorsEventCallback* callback)
-    : mIsEnabled(false),
-      mSamplingPeriodNs(0),
-      mLastSampleTimeNs(0),
-      mCallback(callback),
-      mMode(OperationMode::NORMAL) {
-    mRunThread = std::thread(startThread, this);
-}
-
-Sensor::~Sensor() {
-    std::unique_lock<std::mutex> lock(mRunMutex);
-    mStopThread = true;
-    mIsEnabled = false;
-    mWaitCV.notify_all();
-    lock.release();
-    mRunThread.join();
-}
-
-const SensorInfo& Sensor::getSensorInfo() const {
-    return mSensorInfo;
-}
-
-void Sensor::batch(int32_t samplingPeriodNs) {
-    if (samplingPeriodNs < mSensorInfo.minDelay * 1000) {
-        samplingPeriodNs = mSensorInfo.minDelay * 1000;
-    } else if (samplingPeriodNs > mSensorInfo.maxDelay * 1000) {
-        samplingPeriodNs = mSensorInfo.maxDelay * 1000;
-    }
-
-    if (mSamplingPeriodNs != samplingPeriodNs) {
-        mSamplingPeriodNs = samplingPeriodNs;
-        // Wake up the 'run' thread to check if a new event should be generated now
-        mWaitCV.notify_all();
-    }
-}
-
-void Sensor::activate(bool enable) {
-    if (mIsEnabled != enable) {
-        std::unique_lock<std::mutex> lock(mRunMutex);
-        mIsEnabled = enable;
-        mWaitCV.notify_all();
-    }
-}
-
-Result Sensor::flush() {
-    // Only generate a flush complete event if the sensor is enabled and if the sensor is not a
-    // one-shot sensor.
-    if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) {
-        return Result::BAD_VALUE;
-    }
-
-    // Note: If a sensor supports batching, write all of the currently batched events for the sensor
-    // to the Event FMQ prior to writing the flush complete event.
-    Event ev;
-    ev.sensorHandle = mSensorInfo.sensorHandle;
-    ev.sensorType = SensorType::META_DATA;
-    ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
-    std::vector<Event> evs{ev};
-    mCallback->postEvents(evs, isWakeUpSensor());
-
-    return Result::OK;
-}
-
-void Sensor::startThread(Sensor* sensor) {
-    sensor->run();
-}
-
-void Sensor::run() {
-    std::unique_lock<std::mutex> runLock(mRunMutex);
-    constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
-
-    while (!mStopThread) {
-        if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
-            mWaitCV.wait(runLock, [&] {
-                return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
-            });
-        } else {
-            timespec curTime;
-            clock_gettime(CLOCK_REALTIME, &curTime);
-            int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
-            int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
-
-            if (now >= nextSampleTime) {
-                mLastSampleTimeNs = now;
-                nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
-                mCallback->postEvents(readEvents(), isWakeUpSensor());
-            }
-
-            mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
-        }
-    }
-}
-
-bool Sensor::isWakeUpSensor() {
-    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
-}
-
-std::vector<Event> Sensor::readEvents() {
-    std::vector<Event> events;
-    Event event;
-    event.sensorHandle = mSensorInfo.sensorHandle;
-    event.sensorType = mSensorInfo.type;
-    event.timestamp = ::android::elapsedRealtimeNano();
-    event.u.vec3.x = 0;
-    event.u.vec3.y = 0;
-    event.u.vec3.z = 0;
-    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
-    events.push_back(event);
-    return events;
-}
-
-void Sensor::setOperationMode(OperationMode mode) {
-    if (mMode != mode) {
-        std::unique_lock<std::mutex> lock(mRunMutex);
-        mMode = mode;
-        mWaitCV.notify_all();
-    }
-}
-
-bool Sensor::supportsDataInjection() const {
-    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
-}
-
-Result Sensor::injectEvent(const Event& event) {
-    Result result = Result::OK;
-    if (event.sensorType == SensorType::ADDITIONAL_INFO) {
-        // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
-        // environment data into the device.
-    } else if (!supportsDataInjection()) {
-        result = Result::INVALID_OPERATION;
-    } else if (mMode == OperationMode::DATA_INJECTION) {
-        mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
-    } else {
-        result = Result::BAD_VALUE;
-    }
-    return result;
-}
-
-OnChangeSensor::OnChangeSensor(ISensorsEventCallback* callback)
-    : Sensor(callback), mPreviousEventSet(false) {}
-
-void OnChangeSensor::activate(bool enable) {
-    Sensor::activate(enable);
-    if (!enable) {
-        mPreviousEventSet = false;
-    }
-}
-
-std::vector<Event> OnChangeSensor::readEvents() {
-    std::vector<Event> events = Sensor::readEvents();
-    std::vector<Event> outputEvents;
-
-    for (auto iter = events.begin(); iter != events.end(); ++iter) {
-        Event ev = *iter;
-        if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) {
-            outputEvents.push_back(ev);
-            mPreviousEvent = ev;
-            mPreviousEventSet = true;
-        }
-    }
-    return outputEvents;
-}
-
-AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.name = "Accel Sensor";
-    mSensorInfo.vendor = "Vendor String";
-    mSensorInfo.version = 1;
-    mSensorInfo.type = SensorType::ACCELEROMETER;
-    mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 78.4f;  // +/- 8g
-    mSensorInfo.resolution = 1.52e-5;
-    mSensorInfo.power = 0.001f;          // mA
-    mSensorInfo.minDelay = 20 * 1000;    // microseconds
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
-};
-
-PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : Sensor(callback) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.name = "Pressure Sensor";
-    mSensorInfo.vendor = "Vendor String";
-    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.minDelay = 100 * 1000;  // microseconds
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = 0;
-};
-
-MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : Sensor(callback) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.name = "Magnetic Field Sensor";
-    mSensorInfo.vendor = "Vendor String";
-    mSensorInfo.version = 1;
-    mSensorInfo.type = SensorType::MAGNETIC_FIELD;
-    mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 1300.0f;
-    mSensorInfo.resolution = 0.01f;
-    mSensorInfo.power = 0.001f;       // mA
-    mSensorInfo.minDelay = 20 * 1000;  // microseconds
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = 0;
-};
-
-LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : OnChangeSensor(callback) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.name = "Light Sensor";
-    mSensorInfo.vendor = "Vendor String";
-    mSensorInfo.version = 1;
-    mSensorInfo.type = SensorType::LIGHT;
-    mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 43000.0f;
-    mSensorInfo.resolution = 10.0f;
-    mSensorInfo.power = 0.001f;           // mA
-    mSensorInfo.minDelay = 200 * 1000;    // microseconds
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
-};
-
-ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : OnChangeSensor(callback) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.name = "Proximity Sensor";
-    mSensorInfo.vendor = "Vendor String";
-    mSensorInfo.version = 1;
-    mSensorInfo.type = SensorType::PROXIMITY;
-    mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 5.0f;
-    mSensorInfo.resolution = 1.0f;
-    mSensorInfo.power = 0.012f;  // mA
-    mSensorInfo.minDelay = 200 * 1000;  // microseconds
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags =
-            static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP);
-};
-
-GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.name = "Gyro Sensor";
-    mSensorInfo.vendor = "Vendor String";
-    mSensorInfo.version = 1;
-    mSensorInfo.type = SensorType::GYROSCOPE;
-    mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
-    mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
-    mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 2.5f * 1000;  // microseconds
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = 0;
-};
-
-AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : OnChangeSensor(callback) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.name = "Ambient Temp Sensor";
-    mSensorInfo.vendor = "Vendor String";
-    mSensorInfo.version = 1;
-    mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
-    mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 80.0f;
-    mSensorInfo.resolution = 0.01f;
-    mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 40 * 1000;  // microseconds
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
-};
-
-DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : OnChangeSensor(callback) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.name = "Device Temp Sensor";
-    mSensorInfo.vendor = "Vendor String";
-    mSensorInfo.version = 1;
-    mSensorInfo.type = SensorType::TEMPERATURE;
-    mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 80.0f;
-    mSensorInfo.resolution = 0.01f;
-    mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 40 * 1000;  // microseconds
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
-}
-
-RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
-                                               ISensorsEventCallback* callback)
-    : OnChangeSensor(callback) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.name = "Relative Humidity Sensor";
-    mSensorInfo.vendor = "Vendor String";
-    mSensorInfo.version = 1;
-    mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
-    mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 100.0f;
-    mSensorInfo.resolution = 0.1f;
-    mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 40 * 1000;  // microseconds
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
diff --git a/sensors/2.0/default/Sensor.h b/sensors/2.0/default/Sensor.h
deleted file mode 100644
index 61900fa..0000000
--- a/sensors/2.0/default/Sensor.h
+++ /dev/null
@@ -1,147 +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_SENSOR_H
-#define ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H
-
-#include <android/hardware/sensors/1.0/types.h>
-
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-#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 implementation {
-
-class ISensorsEventCallback {
-   public:
-    virtual ~ISensorsEventCallback(){};
-    virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
-};
-
-class Sensor {
-   public:
-    Sensor(ISensorsEventCallback* callback);
-    virtual ~Sensor();
-
-    const SensorInfo& getSensorInfo() const;
-    void batch(int32_t samplingPeriodNs);
-    virtual void activate(bool enable);
-    Result flush();
-
-    void setOperationMode(OperationMode mode);
-    bool supportsDataInjection() const;
-    Result injectEvent(const Event& event);
-
-   protected:
-    void run();
-    virtual std::vector<Event> readEvents();
-    static void startThread(Sensor* sensor);
-
-    bool isWakeUpSensor();
-
-    bool mIsEnabled;
-    int64_t mSamplingPeriodNs;
-    int64_t mLastSampleTimeNs;
-    SensorInfo mSensorInfo;
-
-    std::atomic_bool mStopThread;
-    std::condition_variable mWaitCV;
-    std::mutex mRunMutex;
-    std::thread mRunThread;
-
-    ISensorsEventCallback* mCallback;
-
-    OperationMode mMode;
-};
-
-class OnChangeSensor : public Sensor {
-   public:
-    OnChangeSensor(ISensorsEventCallback* callback);
-
-    virtual void activate(bool enable) override;
-
-   protected:
-    virtual std::vector<Event> readEvents() override;
-
-   protected:
-    Event mPreviousEvent;
-    bool mPreviousEventSet;
-};
-
-class AccelSensor : public Sensor {
-   public:
-    AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class GyroSensor : public Sensor {
-   public:
-    GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class AmbientTempSensor : public OnChangeSensor {
-   public:
-    AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class DeviceTempSensor : public OnChangeSensor {
-   public:
-    DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class PressureSensor : public Sensor {
-   public:
-    PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class MagnetometerSensor : public Sensor {
-   public:
-    MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class LightSensor : public OnChangeSensor {
-   public:
-    LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class ProximitySensor : public OnChangeSensor {
-   public:
-    ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class RelativeHumiditySensor : public OnChangeSensor {
-   public:
-    RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_SENSORS_V2_0_SENSOR_H
diff --git a/sensors/2.0/default/Sensors.cpp b/sensors/2.0/default/Sensors.cpp
deleted file mode 100644
index 23dd26b..0000000
--- a/sensors/2.0/default/Sensors.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Sensors.h"
-
-#include <android/hardware/sensors/2.0/types.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::sensors::V1_0::Event;
-using ::android::hardware::sensors::V1_0::OperationMode;
-using ::android::hardware::sensors::V1_0::RateLevel;
-using ::android::hardware::sensors::V1_0::Result;
-using ::android::hardware::sensors::V1_0::SharedMemInfo;
-using ::android::hardware::sensors::V2_0::SensorTimeout;
-using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
-
-constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP";
-
-Sensors::Sensors()
-    : mEventQueueFlag(nullptr),
-      mNextHandle(1),
-      mOutstandingWakeUpEvents(0),
-      mReadWakeLockQueueRun(false),
-      mAutoReleaseWakeLockTime(0),
-      mHasWakeLock(false) {
-    AddSensor<AccelSensor>();
-    AddSensor<GyroSensor>();
-    AddSensor<AmbientTempSensor>();
-    AddSensor<DeviceTempSensor>();
-    AddSensor<PressureSensor>();
-    AddSensor<MagnetometerSensor>();
-    AddSensor<LightSensor>();
-    AddSensor<ProximitySensor>();
-    AddSensor<RelativeHumiditySensor>();
-}
-
-Sensors::~Sensors() {
-    deleteEventFlag();
-    mReadWakeLockQueueRun = false;
-    mWakeLockThread.join();
-}
-
-// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
-Return<void> Sensors::getSensorsList(getSensorsList_cb _hidl_cb) {
-    std::vector<SensorInfo> sensors;
-    for (const auto& sensor : mSensors) {
-        sensors.push_back(sensor.second->getSensorInfo());
-    }
-
-    // Call the HIDL callback with the SensorInfo
-    _hidl_cb(sensors);
-
-    return Void();
-}
-
-Return<Result> Sensors::setOperationMode(OperationMode mode) {
-    for (auto sensor : mSensors) {
-        sensor.second->setOperationMode(mode);
-    }
-    return Result::OK;
-}
-
-Return<Result> Sensors::activate(int32_t sensorHandle, bool enabled) {
-    auto sensor = mSensors.find(sensorHandle);
-    if (sensor != mSensors.end()) {
-        sensor->second->activate(enabled);
-        return Result::OK;
-    }
-    return Result::BAD_VALUE;
-}
-
-Return<Result> Sensors::initialize(
-    const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
-    const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
-    const sp<ISensorsCallback>& sensorsCallback) {
-    Result result = Result::OK;
-
-    // Ensure that all sensors are disabled
-    for (auto sensor : mSensors) {
-        sensor.second->activate(false /* enable */);
-    }
-
-    // Stop the Wake Lock thread if it is currently running
-    if (mReadWakeLockQueueRun.load()) {
-        mReadWakeLockQueueRun = false;
-        mWakeLockThread.join();
-    }
-
-    // Save a reference to the callback
-    mCallback = sensorsCallback;
-
-    // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
-    mEventQueue =
-        std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
-
-    // Ensure that any existing EventFlag is properly deleted
-    deleteEventFlag();
-
-    // Create the EventFlag that is used to signal to the framework that sensor events have been
-    // written to the Event FMQ
-    if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
-        result = Result::BAD_VALUE;
-    }
-
-    // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
-    // events have been successfully read and handled by the framework.
-    mWakeLockQueue =
-        std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
-
-    if (!mCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
-        result = Result::BAD_VALUE;
-    }
-
-    // Start the thread to read events from the Wake Lock FMQ
-    mReadWakeLockQueueRun = true;
-    mWakeLockThread = std::thread(startReadWakeLockThread, this);
-
-    return result;
-}
-
-Return<Result> Sensors::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
-                              int64_t /* maxReportLatencyNs */) {
-    auto sensor = mSensors.find(sensorHandle);
-    if (sensor != mSensors.end()) {
-        sensor->second->batch(samplingPeriodNs);
-        return Result::OK;
-    }
-    return Result::BAD_VALUE;
-}
-
-Return<Result> Sensors::flush(int32_t sensorHandle) {
-    auto sensor = mSensors.find(sensorHandle);
-    if (sensor != mSensors.end()) {
-        return sensor->second->flush();
-    }
-    return Result::BAD_VALUE;
-}
-
-Return<Result> Sensors::injectSensorData(const Event& event) {
-    auto sensor = mSensors.find(event.sensorHandle);
-    if (sensor != mSensors.end()) {
-        return sensor->second->injectEvent(event);
-    }
-
-    return Result::BAD_VALUE;
-}
-
-Return<void> Sensors::registerDirectChannel(const SharedMemInfo& /* mem */,
-                                            registerDirectChannel_cb _hidl_cb) {
-    _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
-    return Return<void>();
-}
-
-Return<Result> Sensors::unregisterDirectChannel(int32_t /* channelHandle */) {
-    return Result::INVALID_OPERATION;
-}
-
-Return<void> Sensors::configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */,
-                                         RateLevel /* rate */, configDirectReport_cb _hidl_cb) {
-    _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
-    return Return<void>();
-}
-
-void Sensors::postEvents(const std::vector<Event>& events, bool wakeup) {
-    std::lock_guard<std::mutex> lock(mWriteLock);
-    if (mEventQueue->write(events.data(), events.size())) {
-        mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
-
-        if (wakeup) {
-            // Keep track of the number of outstanding WAKE_UP events in order to properly hold
-            // a wake lock until the framework has secured a wake lock
-            updateWakeLock(events.size(), 0 /* eventsHandled */);
-        }
-    }
-}
-
-void Sensors::updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) {
-    std::lock_guard<std::mutex> lock(mWakeLockLock);
-    int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled;
-    if (newVal < 0) {
-        mOutstandingWakeUpEvents = 0;
-    } else {
-        mOutstandingWakeUpEvents = newVal;
-    }
-
-    if (eventsWritten > 0) {
-        // Update the time at which the last WAKE_UP event was sent
-        mAutoReleaseWakeLockTime = ::android::uptimeMillis() +
-                                   static_cast<uint32_t>(SensorTimeout::WAKE_LOCK_SECONDS) * 1000;
-    }
-
-    if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 &&
-        acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) {
-        mHasWakeLock = true;
-    } else if (mHasWakeLock) {
-        // Check if the wake lock should be released automatically if
-        // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written to
-        // the Wake Lock FMQ.
-        if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) {
-            ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock",
-                  SensorTimeout::WAKE_LOCK_SECONDS);
-            mOutstandingWakeUpEvents = 0;
-        }
-
-        if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) {
-            mHasWakeLock = false;
-        }
-    }
-}
-
-void Sensors::readWakeLockFMQ() {
-    while (mReadWakeLockQueueRun.load()) {
-        constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000;  // 500 ms
-        uint32_t eventsHandled = 0;
-
-        // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to ensure
-        // that any held wake lock is able to be released if it is held for too long.
-        mWakeLockQueue->readBlocking(&eventsHandled, 1 /* count */, 0 /* readNotification */,
-                                     static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN),
-                                     kReadTimeoutNs);
-        updateWakeLock(0 /* eventsWritten */, eventsHandled);
-    }
-}
-
-void Sensors::startReadWakeLockThread(Sensors* sensors) {
-    sensors->readWakeLockFMQ();
-}
-
-void Sensors::deleteEventFlag() {
-    status_t status = EventFlag::deleteEventFlag(&mEventQueueFlag);
-    if (status != OK) {
-        ALOGI("Failed to delete event flag: %d", status);
-    }
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
diff --git a/sensors/2.0/default/Sensors.h b/sensors/2.0/default/Sensors.h
deleted file mode 100644
index d06dd78..0000000
--- a/sensors/2.0/default/Sensors.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H
-#define ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H
-
-#include "Sensor.h"
-
-#include <android/hardware/sensors/2.0/ISensors.h>
-#include <fmq/MessageQueue.h>
-#include <hardware_legacy/power.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include <atomic>
-#include <memory>
-#include <thread>
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::hardware::EventFlag;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::MessageQueue;
-using ::android::hardware::MQDescriptor;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-struct Sensors : public ISensors, public ISensorsEventCallback {
-    using Event = ::android::hardware::sensors::V1_0::Event;
-    using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
-    using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
-    using Result = ::android::hardware::sensors::V1_0::Result;
-    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
-
-    Sensors();
-    virtual ~Sensors();
-
-    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
-    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
-
-    Return<Result> setOperationMode(OperationMode mode) override;
-
-    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
-
-    Return<Result> initialize(
-        const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
-        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
-        const sp<ISensorsCallback>& sensorsCallback) override;
-
-    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
-                         int64_t maxReportLatencyNs) override;
-
-    Return<Result> flush(int32_t sensorHandle) override;
-
-    Return<Result> injectSensorData(const Event& event) override;
-
-    Return<void> registerDirectChannel(const SharedMemInfo& mem,
-                                       registerDirectChannel_cb _hidl_cb) override;
-
-    Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
-
-    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
-                                    configDirectReport_cb _hidl_cb) override;
-
-    void postEvents(const std::vector<Event>& events, bool wakeup) override;
-
-   private:
-    /**
-     * Add a new sensor
-     */
-    template <class SensorType>
-    void AddSensor() {
-        std::shared_ptr<SensorType> sensor =
-                std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
-        mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
-    }
-
-    /**
-     * Utility function to delete the Event Flag
-     */
-    void deleteEventFlag();
-
-    /**
-     * Function to read the Wake Lock FMQ and release the wake lock when appropriate
-     */
-    void readWakeLockFMQ();
-
-    static void startReadWakeLockThread(Sensors* sensors);
-
-    /**
-     * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events
-     */
-    void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled);
-
-    using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
-    using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
-
-    /**
-     * The Event FMQ where sensor events are written
-     */
-    std::unique_ptr<EventMessageQueue> mEventQueue;
-
-    /**
-     * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
-     */
-    std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
-
-    /**
-     * Event Flag to signal to the framework when sensor events are available to be read
-     */
-    EventFlag* mEventQueueFlag;
-
-    /**
-     * Callback for asynchronous events, such as dynamic sensor connections.
-     */
-    sp<ISensorsCallback> mCallback;
-
-    /**
-     * A map of the available sensors
-     */
-    std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
-
-    /**
-     * The next available sensor handle
-     */
-    int32_t mNextHandle;
-
-    /**
-     * Lock to protect writes to the FMQs
-     */
-    std::mutex mWriteLock;
-
-    /**
-     * Lock to protect acquiring and releasing the wake lock
-     */
-    std::mutex mWakeLockLock;
-
-    /**
-     * Track the number of WAKE_UP events that have not been handled by the framework
-     */
-    uint32_t mOutstandingWakeUpEvents;
-
-    /**
-     * A thread to read the Wake Lock FMQ
-     */
-    std::thread mWakeLockThread;
-
-    /**
-     * Flag to indicate that the Wake Lock Thread should continue to run
-     */
-    std::atomic_bool mReadWakeLockQueueRun;
-
-    /**
-     * Track the time when the wake lock should automatically be released
-     */
-    int64_t mAutoReleaseWakeLockTime;
-
-    /**
-     * Flag to indicate if a wake lock has been acquired
-     */
-    bool mHasWakeLock;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_SENSORS_V2_0_SENSORS_H
diff --git a/sensors/2.0/default/SensorsV2_0.h b/sensors/2.0/default/SensorsV2_0.h
new file mode 100644
index 0000000..345835a
--- /dev/null
+++ b/sensors/2.0/default/SensorsV2_0.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_0_H
+#define ANDROID_HARDWARE_SENSORS_V2_0_H
+
+#include "Sensors.h"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+struct SensorsV2_0 : public ::android::hardware::sensors::V2_X::implementation::Sensors<ISensors> {
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_0_H
\ No newline at end of file
diff --git a/sensors/2.0/default/service.cpp b/sensors/2.0/default/service.cpp
index 5c13e33..e20bf85 100644
--- a/sensors/2.0/default/service.cpp
+++ b/sensors/2.0/default/service.cpp
@@ -20,17 +20,17 @@
 #include <hidl/HidlTransportSupport.h>
 #include <log/log.h>
 #include <utils/StrongPointer.h>
-#include "Sensors.h"
+#include "SensorsV2_0.h"
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::sensors::V2_0::ISensors;
-using android::hardware::sensors::V2_0::implementation::Sensors;
+using android::hardware::sensors::V2_0::implementation::SensorsV2_0;
 
 int main(int /* argc */, char** /* argv */) {
     configureRpcThreadpool(1, true);
 
-    android::sp<ISensors> sensors = new Sensors();
+    android::sp<ISensors> sensors = new SensorsV2_0();
     if (sensors->registerAsService() != ::android::OK) {
         ALOGE("Failed to register Sensors HAL instance");
         return -1;
diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp
index b7fa15a..bf51fcd 100644
--- a/sensors/2.0/multihal/Android.bp
+++ b/sensors/2.0/multihal/Android.bp
@@ -13,14 +13,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_defaults {
-    name: "android.hardware.sensors@2.0-multihal-defaults",
+cc_binary {
+    name: "android.hardware.sensors@2.0-service.multihal",
+    defaults: [
+        "hidl_defaults",
+    ],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "service.cpp",
+    ],
+    init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
+    vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
     header_libs: [
-        "android.hardware.sensors@2.0-multihal.header",
+        "android.hardware.sensors@2.X-shared-utils",
     ],
     shared_libs: [
-        "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.0-ScopedWakelock",
+        "android.hardware.sensors@2.1",
         "libbase",
         "libcutils",
         "libfmq",
@@ -29,81 +40,8 @@
         "libpower",
         "libutils",
     ],
-    cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
-}
-
-cc_binary {
-    name: "android.hardware.sensors@2.0-service.multihal",
-    defaults: [
-        "hidl_defaults",
-        "android.hardware.sensors@2.0-multihal-defaults",
-    ],
-    vendor: true,
-    relative_install_path: "hw",
-    srcs: [
-        "service.cpp",
-        "HalProxy.cpp",
-    ],
-    init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
-    vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
-    shared_libs: ["android.hardware.sensors@2.0-ScopedWakelock"],
-}
-
-cc_library_headers {
-    name: "android.hardware.sensors@2.0-multihal.header",
-    vendor_available: true,
-    export_include_dirs: ["include"],
-}
-
-cc_library_shared {
-    name: "android.hardware.sensors@2.0-ScopedWakelock",
-    defaults: [
-        "hidl_defaults",
-        "android.hardware.sensors@2.0-multihal-defaults",
-    ],
-    srcs: [
-        "ScopedWakelock.cpp",
-    ],
-    vendor_available: true,
-    export_header_lib_headers: [
-        "android.hardware.sensors@2.0-multihal.header",
-    ],
-}
-
-// The below targets should only be used for testing.
-cc_test_library {
-    name: "android.hardware.sensors@2.0-HalProxy",
-    defaults: [
-        "hidl_defaults",
-        "android.hardware.sensors@2.0-multihal-defaults",
-    ],
-    vendor_available: true,
-    srcs: [
-        "HalProxy.cpp",
-    ],
-    export_header_lib_headers: [
-        "android.hardware.sensors@2.0-multihal.header",
-    ],
-    export_shared_lib_headers: [
-        "android.hardware.sensors@2.0-ScopedWakelock",
-    ],
-    shared_libs: [
-        "libutils",
-        "android.hardware.sensors@2.0-ScopedWakelock",
-    ],
-}
-
-cc_test_library {
-    name: "android.hardware.sensors@2.0-ScopedWakelock.testlib",
-    defaults: [
-        "hidl_defaults",
-        "android.hardware.sensors@2.0-multihal-defaults",
-    ],
-    srcs: [
-        "ScopedWakelock.cpp",
-    ],
-    vendor_available: true,
-    export_header_lib_headers: [
-        "android.hardware.sensors@2.0-multihal.header",
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.X-multihal",
     ],
 }
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
deleted file mode 100644
index fbff24c..0000000
--- a/sensors/2.0/multihal/HalProxy.cpp
+++ /dev/null
@@ -1,712 +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 "HalProxy.h"
-
-#include "SubHal.h"
-
-#include <android/hardware/sensors/2.0/types.h>
-
-#include <android-base/file.h>
-#include "hardware_legacy/power.h"
-
-#include <dlfcn.h>
-
-#include <cinttypes>
-#include <cmath>
-#include <fstream>
-#include <functional>
-#include <thread>
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
-using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
-using ::android::hardware::sensors::V2_0::implementation::getTimeNow;
-using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs;
-
-typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*);
-
-static constexpr int32_t kBitsAfterSubHalIndex = 24;
-
-/**
- * Set the subhal index as first byte of sensor handle and return this modified version.
- *
- * @param sensorHandle The sensor handle to modify.
- * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to.
- *
- * @return The modified sensor handle.
- */
-int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) {
-    return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
-}
-
-/**
- * Extract the subHalIndex from sensorHandle.
- *
- * @param sensorHandle The sensorHandle to extract from.
- *
- * @return The subhal index.
- */
-size_t extractSubHalIndex(int32_t sensorHandle) {
-    return static_cast<size_t>(sensorHandle >> kBitsAfterSubHalIndex);
-}
-
-/**
- * Convert nanoseconds to milliseconds.
- *
- * @param nanos The nanoseconds input.
- *
- * @return The milliseconds count.
- */
-int64_t msFromNs(int64_t nanos) {
-    constexpr int64_t nanosecondsInAMillsecond = 1000000;
-    return nanos / nanosecondsInAMillsecond;
-}
-
-HalProxy::HalProxy() {
-    const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
-    initializeSubHalListFromConfigFile(kMultiHalConfigFile);
-    init();
-}
-
-HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) {
-    init();
-}
-
-HalProxy::~HalProxy() {
-    stopThreads();
-}
-
-Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
-    std::vector<SensorInfo> sensors;
-    for (const auto& iter : mSensors) {
-        sensors.push_back(iter.second);
-    }
-    _hidl_cb(sensors);
-    return Void();
-}
-
-Return<Result> HalProxy::setOperationMode(OperationMode mode) {
-    Result result = Result::OK;
-    size_t subHalIndex;
-    for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
-        ISensorsSubHal* subHal = mSubHalList[subHalIndex];
-        result = subHal->setOperationMode(mode);
-        if (result != Result::OK) {
-            ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str());
-            break;
-        }
-    }
-    if (result != Result::OK) {
-        // Reset the subhal operation modes that have been flipped
-        for (size_t i = 0; i < subHalIndex; i++) {
-            ISensorsSubHal* subHal = mSubHalList[i];
-            subHal->setOperationMode(mCurrentOperationMode);
-        }
-    } else {
-        mCurrentOperationMode = mode;
-    }
-    return result;
-}
-
-Return<Result> HalProxy::activate(int32_t sensorHandle, bool enabled) {
-    if (!isSubHalIndexValid(sensorHandle)) {
-        return Result::BAD_VALUE;
-    }
-    return getSubHalForSensorHandle(sensorHandle)
-            ->activate(clearSubHalIndex(sensorHandle), enabled);
-}
-
-Return<Result> HalProxy::initialize(
-        const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
-        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
-        const sp<ISensorsCallback>& sensorsCallback) {
-    Result result = Result::OK;
-
-    stopThreads();
-    resetSharedWakelock();
-
-    // So that the pending write events queue can be cleared safely and when we start threads
-    // again we do not get new events until after initialize resets the subhals.
-    disableAllSensors();
-
-    // Clears the queue if any events were pending write before.
-    mPendingWriteEventsQueue = std::queue<std::pair<std::vector<Event>, size_t>>();
-    mSizePendingWriteEventsQueue = 0;
-
-    // Clears previously connected dynamic sensors
-    mDynamicSensors.clear();
-
-    mDynamicSensorsCallback = sensorsCallback;
-
-    // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
-    mEventQueue =
-            std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
-
-    // 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 (mEventQueueFlag != nullptr) {
-        EventFlag::deleteEventFlag(&mEventQueueFlag);
-    }
-    if (mWakelockQueueFlag != nullptr) {
-        EventFlag::deleteEventFlag(&mWakelockQueueFlag);
-    }
-    if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
-        result = Result::BAD_VALUE;
-    }
-    if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) {
-        result = Result::BAD_VALUE;
-    }
-    if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
-        result = Result::BAD_VALUE;
-    }
-
-    mThreadsRun.store(true);
-
-    mPendingWritesThread = std::thread(startPendingWritesThread, this);
-    mWakelockThread = std::thread(startWakelockThread, this);
-
-    for (size_t i = 0; i < mSubHalList.size(); i++) {
-        auto subHal = mSubHalList[i];
-        const auto& subHalCallback = mSubHalCallbacks[i];
-        Result currRes = subHal->initialize(subHalCallback);
-        if (currRes != Result::OK) {
-            result = currRes;
-            ALOGE("Subhal '%s' failed to initialize.", subHal->getName().c_str());
-            break;
-        }
-    }
-
-    mCurrentOperationMode = OperationMode::NORMAL;
-
-    return result;
-}
-
-Return<Result> HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
-                               int64_t maxReportLatencyNs) {
-    if (!isSubHalIndexValid(sensorHandle)) {
-        return Result::BAD_VALUE;
-    }
-    return getSubHalForSensorHandle(sensorHandle)
-            ->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs);
-}
-
-Return<Result> HalProxy::flush(int32_t sensorHandle) {
-    if (!isSubHalIndexValid(sensorHandle)) {
-        return Result::BAD_VALUE;
-    }
-    return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle));
-}
-
-Return<Result> HalProxy::injectSensorData(const Event& event) {
-    Result result = Result::OK;
-    if (mCurrentOperationMode == OperationMode::NORMAL &&
-        event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) {
-        ALOGE("An event with type != ADDITIONAL_INFO passed to injectSensorData while operation"
-              " mode was NORMAL.");
-        result = Result::BAD_VALUE;
-    }
-    if (result == Result::OK) {
-        Event subHalEvent = event;
-        if (!isSubHalIndexValid(event.sensorHandle)) {
-            return Result::BAD_VALUE;
-        }
-        subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle);
-        result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent);
-    }
-    return result;
-}
-
-Return<void> HalProxy::registerDirectChannel(const SharedMemInfo& mem,
-                                             registerDirectChannel_cb _hidl_cb) {
-    if (mDirectChannelSubHal == nullptr) {
-        _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
-    } else {
-        mDirectChannelSubHal->registerDirectChannel(mem, _hidl_cb);
-    }
-    return Return<void>();
-}
-
-Return<Result> HalProxy::unregisterDirectChannel(int32_t channelHandle) {
-    Result result;
-    if (mDirectChannelSubHal == nullptr) {
-        result = Result::INVALID_OPERATION;
-    } else {
-        result = mDirectChannelSubHal->unregisterDirectChannel(channelHandle);
-    }
-    return result;
-}
-
-Return<void> HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle,
-                                          RateLevel rate, configDirectReport_cb _hidl_cb) {
-    if (mDirectChannelSubHal == nullptr) {
-        _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */);
-    } else {
-        mDirectChannelSubHal->configDirectReport(clearSubHalIndex(sensorHandle), channelHandle,
-                                                 rate, _hidl_cb);
-    }
-    return Return<void>();
-}
-
-Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
-    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
-        ALOGE("%s: missing fd for writing", __FUNCTION__);
-        return Void();
-    }
-
-    android::base::borrowed_fd writeFd = dup(fd->data[0]);
-
-    std::ostringstream stream;
-    stream << "===HalProxy===" << std::endl;
-    stream << "Internal values:" << std::endl;
-    stream << "  Threads are running: " << (mThreadsRun.load() ? "true" : "false") << std::endl;
-    int64_t now = getTimeNow();
-    stream << "  Wakelock timeout start time: " << msFromNs(now - mWakelockTimeoutStartTime)
-           << " ms ago" << std::endl;
-    stream << "  Wakelock timeout reset time: " << msFromNs(now - mWakelockTimeoutResetTime)
-           << " ms ago" << std::endl;
-    // TODO(b/142969448): Add logging for history of wakelock acquisition per subhal.
-    stream << "  Wakelock ref count: " << mWakelockRefCount << std::endl;
-    stream << "  # of events on pending write writes queue: " << mSizePendingWriteEventsQueue
-           << std::endl;
-    stream << " Most events seen on pending write events queue: "
-           << mMostEventsObservedPendingWriteEventsQueue << std::endl;
-    if (!mPendingWriteEventsQueue.empty()) {
-        stream << "  Size of events list on front of pending writes queue: "
-               << mPendingWriteEventsQueue.front().first.size() << std::endl;
-    }
-    stream << "  # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl;
-    stream << "  # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl;
-    stream << "SubHals (" << mSubHalList.size() << "):" << std::endl;
-    for (ISensorsSubHal* subHal : mSubHalList) {
-        stream << "  Name: " << subHal->getName() << std::endl;
-        stream << "  Debug dump: " << std::endl;
-        android::base::WriteStringToFd(stream.str(), writeFd);
-        subHal->debug(fd, {});
-        stream.str("");
-        stream << std::endl;
-    }
-    android::base::WriteStringToFd(stream.str(), writeFd);
-    return Return<void>();
-}
-
-Return<void> HalProxy::onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
-                                                 int32_t subHalIndex) {
-    std::vector<SensorInfo> sensors;
-    {
-        std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
-        for (SensorInfo sensor : dynamicSensorsAdded) {
-            if (!subHalIndexIsClear(sensor.sensorHandle)) {
-                ALOGE("Dynamic sensor added %s had sensorHandle with first byte not 0.",
-                      sensor.name.c_str());
-            } else {
-                sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
-                mDynamicSensors[sensor.sensorHandle] = sensor;
-                sensors.push_back(sensor);
-            }
-        }
-    }
-    mDynamicSensorsCallback->onDynamicSensorsConnected(sensors);
-    return Return<void>();
-}
-
-Return<void> HalProxy::onDynamicSensorsDisconnected(
-        const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) {
-    // TODO(b/143302327): Block this call until all pending events are flushed from queue
-    std::vector<int32_t> sensorHandles;
-    {
-        std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
-        for (int32_t sensorHandle : dynamicSensorHandlesRemoved) {
-            if (!subHalIndexIsClear(sensorHandle)) {
-                ALOGE("Dynamic sensorHandle removed had first byte not 0.");
-            } else {
-                sensorHandle = setSubHalIndex(sensorHandle, subHalIndex);
-                if (mDynamicSensors.find(sensorHandle) != mDynamicSensors.end()) {
-                    mDynamicSensors.erase(sensorHandle);
-                    sensorHandles.push_back(sensorHandle);
-                }
-            }
-        }
-    }
-    mDynamicSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
-    return Return<void>();
-}
-
-void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
-    std::ifstream subHalConfigStream(configFileName);
-    if (!subHalConfigStream) {
-        ALOGE("Failed to load subHal config file: %s", configFileName);
-    } else {
-        std::string subHalLibraryFile;
-        while (subHalConfigStream >> subHalLibraryFile) {
-            void* handle = getHandleForSubHalSharedObject(subHalLibraryFile);
-            if (handle == nullptr) {
-                ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str());
-            } else {
-                SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
-                        (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
-                if (sensorsHalGetSubHalPtr == nullptr) {
-                    ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s",
-                          subHalLibraryFile.c_str());
-                } else {
-                    std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
-                            *sensorsHalGetSubHalPtr;
-                    uint32_t version;
-                    ISensorsSubHal* subHal = sensorsHalGetSubHal(&version);
-                    if (version != SUB_HAL_2_0_VERSION) {
-                        ALOGE("SubHal version was not 2.0 for library: %s",
-                              subHalLibraryFile.c_str());
-                    } else {
-                        ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
-                        mSubHalList.push_back(subHal);
-                    }
-                }
-            }
-        }
-    }
-}
-
-void HalProxy::initializeSubHalCallbacks() {
-    for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
-        sp<IHalProxyCallback> callback = new HalProxyCallback(this, subHalIndex);
-        mSubHalCallbacks.push_back(callback);
-    }
-}
-
-void HalProxy::initializeSensorList() {
-    for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
-        ISensorsSubHal* subHal = mSubHalList[subHalIndex];
-        auto result = subHal->getSensorsList([&](const auto& list) {
-            for (SensorInfo sensor : list) {
-                if (!subHalIndexIsClear(sensor.sensorHandle)) {
-                    ALOGE("SubHal sensorHandle's first byte was not 0");
-                } else {
-                    ALOGV("Loaded sensor: %s", sensor.name.c_str());
-                    sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
-                    setDirectChannelFlags(&sensor, subHal);
-                    mSensors[sensor.sensorHandle] = sensor;
-                }
-            }
-        });
-        if (!result.isOk()) {
-            ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str());
-        }
-    }
-}
-
-void* HalProxy::getHandleForSubHalSharedObject(const std::string& filename) {
-    static const std::string kSubHalShareObjectLocations[] = {
-            "",  // Default locations will be searched
-#ifdef __LP64__
-            "/vendor/lib64/hw/", "/odm/lib64/", "/odm/lib64/hw/"
-#else
-            "/vendor/lib/hw/", "/odm/lib/", "/odm/lib/hw/"
-#endif
-    };
-
-    for (const std::string& dir : kSubHalShareObjectLocations) {
-        void* handle = dlopen((dir + filename).c_str(), RTLD_NOW);
-        if (handle != nullptr) {
-            return handle;
-        }
-    }
-    return nullptr;
-}
-
-void HalProxy::init() {
-    initializeSubHalCallbacks();
-    initializeSensorList();
-}
-
-void HalProxy::stopThreads() {
-    mThreadsRun.store(false);
-    if (mEventQueueFlag != nullptr && mEventQueue != nullptr) {
-        size_t numToRead = mEventQueue->availableToRead();
-        std::vector<Event> events(numToRead);
-        mEventQueue->read(events.data(), numToRead);
-        mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ));
-    }
-    if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) {
-        uint32_t kZero = 0;
-        mWakeLockQueue->write(&kZero);
-        mWakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
-    }
-    mWakelockCV.notify_one();
-    mEventQueueWriteCV.notify_one();
-    if (mPendingWritesThread.joinable()) {
-        mPendingWritesThread.join();
-    }
-    if (mWakelockThread.joinable()) {
-        mWakelockThread.join();
-    }
-}
-
-void HalProxy::disableAllSensors() {
-    for (const auto& sensorEntry : mSensors) {
-        int32_t sensorHandle = sensorEntry.first;
-        activate(sensorHandle, false /* enabled */);
-    }
-    std::lock_guard<std::mutex> dynamicSensorsLock(mDynamicSensorsMutex);
-    for (const auto& sensorEntry : mDynamicSensors) {
-        int32_t sensorHandle = sensorEntry.first;
-        activate(sensorHandle, false /* enabled */);
-    }
-}
-
-void HalProxy::startPendingWritesThread(HalProxy* halProxy) {
-    halProxy->handlePendingWrites();
-}
-
-void HalProxy::handlePendingWrites() {
-    // TODO(b/143302327): Find a way to optimize locking strategy maybe using two mutexes instead of
-    // one.
-    std::unique_lock<std::mutex> lock(mEventQueueWriteMutex);
-    while (mThreadsRun.load()) {
-        mEventQueueWriteCV.wait(
-                lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); });
-        if (mThreadsRun.load()) {
-            std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front().first;
-            size_t numWakeupEvents = mPendingWriteEventsQueue.front().second;
-            size_t eventQueueSize = mEventQueue->getQuantumCount();
-            size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
-            lock.unlock();
-            if (!mEventQueue->writeBlocking(
-                        pendingWriteEvents.data(), numToWrite,
-                        static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
-                        static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
-                        kPendingWriteTimeoutNs, mEventQueueFlag)) {
-                ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite);
-                if (numWakeupEvents > 0) {
-                    if (pendingWriteEvents.size() > eventQueueSize) {
-                        decrementRefCountAndMaybeReleaseWakelock(
-                                countNumWakeupEvents(pendingWriteEvents, eventQueueSize));
-                    } else {
-                        decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents);
-                    }
-                }
-            }
-            lock.lock();
-            mSizePendingWriteEventsQueue -= numToWrite;
-            if (pendingWriteEvents.size() > eventQueueSize) {
-                // TODO(b/143302327): Check if this erase operation is too inefficient. It will copy
-                // all the events ahead of it down to fill gap off array at front after the erase.
-                pendingWriteEvents.erase(pendingWriteEvents.begin(),
-                                         pendingWriteEvents.begin() + eventQueueSize);
-            } else {
-                mPendingWriteEventsQueue.pop();
-            }
-        }
-    }
-}
-
-void HalProxy::startWakelockThread(HalProxy* halProxy) {
-    halProxy->handleWakelocks();
-}
-
-void HalProxy::handleWakelocks() {
-    std::unique_lock<std::recursive_mutex> lock(mWakelockMutex);
-    while (mThreadsRun.load()) {
-        mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); });
-        if (mThreadsRun.load()) {
-            int64_t timeLeft;
-            if (sharedWakelockDidTimeout(&timeLeft)) {
-                resetSharedWakelock();
-            } else {
-                uint32_t numWakeLocksProcessed;
-                lock.unlock();
-                bool success = mWakeLockQueue->readBlocking(
-                        &numWakeLocksProcessed, 1, 0,
-                        static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft);
-                lock.lock();
-                if (success) {
-                    decrementRefCountAndMaybeReleaseWakelock(
-                            static_cast<size_t>(numWakeLocksProcessed));
-                }
-            }
-        }
-    }
-    resetSharedWakelock();
-}
-
-bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) {
-    bool didTimeout;
-    int64_t duration = getTimeNow() - mWakelockTimeoutStartTime;
-    if (duration > kWakelockTimeoutNs) {
-        didTimeout = true;
-    } else {
-        didTimeout = false;
-        *timeLeft = kWakelockTimeoutNs - duration;
-    }
-    return didTimeout;
-}
-
-void HalProxy::resetSharedWakelock() {
-    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
-    decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount);
-    mWakelockTimeoutResetTime = getTimeNow();
-}
-
-void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
-                                        ScopedWakelock wakelock) {
-    size_t numToWrite = 0;
-    std::lock_guard<std::mutex> lock(mEventQueueWriteMutex);
-    if (wakelock.isLocked()) {
-        incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents);
-    }
-    if (mPendingWriteEventsQueue.empty()) {
-        numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
-        if (numToWrite > 0) {
-            if (mEventQueue->write(events.data(), numToWrite)) {
-                // TODO(b/143302327): While loop if mEventQueue->avaiableToWrite > 0 to possibly fit
-                // in more writes immediately
-                mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
-            } else {
-                numToWrite = 0;
-            }
-        }
-    }
-    size_t numLeft = events.size() - numToWrite;
-    if (numToWrite < events.size() &&
-        mSizePendingWriteEventsQueue + numLeft <= kMaxSizePendingWriteEventsQueue) {
-        std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
-        mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
-        mSizePendingWriteEventsQueue += numLeft;
-        mMostEventsObservedPendingWriteEventsQueue =
-                std::max(mMostEventsObservedPendingWriteEventsQueue, mSizePendingWriteEventsQueue);
-        mEventQueueWriteCV.notify_one();
-    }
-}
-
-bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta,
-                                                        int64_t* timeoutStart /* = nullptr */) {
-    if (!mThreadsRun.load()) return false;
-    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
-    if (mWakelockRefCount == 0) {
-        acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName);
-        mWakelockCV.notify_one();
-    }
-    mWakelockTimeoutStartTime = getTimeNow();
-    mWakelockRefCount += delta;
-    if (timeoutStart != nullptr) {
-        *timeoutStart = mWakelockTimeoutStartTime;
-    }
-    return true;
-}
-
-void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta,
-                                                        int64_t timeoutStart /* = -1 */) {
-    if (!mThreadsRun.load()) return;
-    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
-    if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
-    if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;
-    mWakelockRefCount -= std::min(mWakelockRefCount, delta);
-    if (mWakelockRefCount == 0) {
-        release_wake_lock(kWakelockName);
-    }
-}
-
-void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) {
-    bool sensorSupportsDirectChannel =
-            (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
-                                  V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0;
-    if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) {
-        mDirectChannelSubHal = subHal;
-    } else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) {
-        // disable direct channel capability for sensors in subHals that are not
-        // the only one we will enable
-        sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
-                               V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
-    }
-}
-
-ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) {
-    return mSubHalList[extractSubHalIndex(sensorHandle)];
-}
-
-bool HalProxy::isSubHalIndexValid(int32_t sensorHandle) {
-    return extractSubHalIndex(sensorHandle) < mSubHalList.size();
-}
-
-size_t HalProxy::countNumWakeupEvents(const std::vector<Event>& events, size_t n) {
-    size_t numWakeupEvents = 0;
-    for (size_t i = 0; i < n; i++) {
-        int32_t sensorHandle = events[i].sensorHandle;
-        if (mSensors[sensorHandle].flags & static_cast<uint32_t>(V1_0::SensorFlagBits::WAKE_UP)) {
-            numWakeupEvents++;
-        }
-    }
-    return numWakeupEvents;
-}
-
-int32_t HalProxy::clearSubHalIndex(int32_t sensorHandle) {
-    return sensorHandle & (~kSensorHandleSubHalIndexMask);
-}
-
-bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) {
-    return (sensorHandle & kSensorHandleSubHalIndexMask) == 0;
-}
-
-void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) {
-    if (events.empty() || !mHalProxy->areThreadsRunning()) return;
-    size_t numWakeupEvents;
-    std::vector<Event> processedEvents = processEvents(events, &numWakeupEvents);
-    if (numWakeupEvents > 0) {
-        ALOG_ASSERT(wakelock.isLocked(),
-                    "Wakeup events posted while wakelock unlocked for subhal"
-                    " w/ index %" PRId32 ".",
-                    mSubHalIndex);
-    } else {
-        ALOG_ASSERT(!wakelock.isLocked(),
-                    "No Wakeup events posted but wakelock locked for subhal"
-                    " w/ index %" PRId32 ".",
-                    mSubHalIndex);
-    }
-    mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock));
-}
-
-ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) {
-    ScopedWakelock wakelock(mHalProxy, lock);
-    return wakelock;
-}
-
-std::vector<Event> HalProxyCallback::processEvents(const std::vector<Event>& events,
-                                                   size_t* numWakeupEvents) const {
-    *numWakeupEvents = 0;
-    std::vector<Event> eventsOut;
-    for (Event event : events) {
-        event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex);
-        eventsOut.push_back(event);
-        const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle);
-        if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) {
-            (*numWakeupEvents)++;
-        }
-    }
-    return eventsOut;
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/2.0/multihal/ScopedWakelock.cpp
deleted file mode 100644
index d85d4a7..0000000
--- a/sensors/2.0/multihal/ScopedWakelock.cpp
+++ /dev/null
@@ -1,48 +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 "ScopedWakelock.h"
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace implementation {
-
-int64_t getTimeNow() {
-    return std::chrono::duration_cast<std::chrono::nanoseconds>(
-                   std::chrono::system_clock::now().time_since_epoch())
-            .count();
-}
-
-ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked)
-    : mRefCounter(refCounter), mLocked(locked) {
-    if (mLocked) {
-        mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs);
-    }
-}
-
-ScopedWakelock::~ScopedWakelock() {
-    if (mLocked) {
-        mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs);
-    }
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
\ No newline at end of file
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
index a4da3b0..0b3d4c2 100644
--- a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
@@ -1,7 +1,7 @@
 service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal
     class hal
     user system
-    group system wakelock
+    group system wakelock context_hub
     writepid /dev/cpuset/system-background/tasks
     capabilities BLOCK_SUSPEND
     rlimit rtprio 10 10
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
deleted file mode 100644
index 10bba55..0000000
--- a/sensors/2.0/multihal/include/HalProxy.h
+++ /dev/null
@@ -1,415 +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.
- */
-
-#pragma once
-
-#include "ScopedWakelock.h"
-#include "SubHal.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 <atomic>
-#include <condition_variable>
-#include <map>
-#include <mutex>
-#include <queue>
-#include <thread>
-#include <utility>
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::hardware::EventFlag;
-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;
-
-class HalProxy : public ISensors, public IScopedWakelockRefCounter {
-  public:
-    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 SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo;
-    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
-    using ISensorsSubHal = ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
-
-    explicit HalProxy();
-    // Test only constructor.
-    explicit HalProxy(std::vector<ISensorsSubHal*>& subHalList);
-    ~HalProxy();
-
-    // 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;
-
-    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
-
-    // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change
-    // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework
-    // via the binder, these methods are invoked from a callback provided to sub-HALs inside the
-    // same process as the HalProxy, but potentially running on different threads.
-    Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
-                                           int32_t subHalIndex);
-
-    Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved,
-                                              int32_t subHalIndex);
-
-    // Below methods are for HalProxyCallback
-
-    /**
-     * Post events to the event message queue if there is room to write them. Otherwise post the
-     * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs
-     * timeout.
-     *
-     * @param events The list of events to post to the message queue.
-     * @param numWakeupEvents The number of wakeup events in events.
-     * @param wakelock The wakelock associated with this post of events.
-     */
-    void postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
-                                  ScopedWakelock wakelock);
-
-    /**
-     * Get the sensor info associated with that sensorHandle.
-     *
-     * @param sensorHandle The sensor handle.
-     *
-     * @return The sensor info object in the mapping.
-     */
-    const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; }
-
-    bool areThreadsRunning() { return mThreadsRun.load(); }
-
-    // Below methods are from IScopedWakelockRefCounter interface
-    bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
-                                                  int64_t* timeoutStart = nullptr) override;
-
-    void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override;
-
-  private:
-    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 and to
-     * interrupt event queue blocking write.
-     */
-    EventFlag* mEventQueueFlag = nullptr;
-
-    //! Event Flag to signal internally that the wakelock queue should stop its blocking read.
-    EventFlag* mWakelockQueueFlag = nullptr;
-
-    /**
-     * Callback to the sensors framework to inform it that new sensors have been added or removed.
-     */
-    sp<ISensorsCallback> mDynamicSensorsCallback;
-
-    /**
-     * SubHal object pointers that have been saved from vendor dynamic libraries.
-     */
-    std::vector<ISensorsSubHal*> mSubHalList;
-
-    //! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList
-    std::vector<const sp<IHalProxyCallback>> mSubHalCallbacks;
-
-    /**
-     * Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as
-     * well as the modified sensor handle for the framework.
-     *
-     * The subhal index is encoded in the first byte of the sensor handle and the remaining
-     * bytes are generated by the subhal to identify the sensor.
-     */
-    std::map<int32_t, SensorInfo> mSensors;
-
-    //! Map of the dynamic sensors that have been added to halproxy.
-    std::map<int32_t, SensorInfo> mDynamicSensors;
-
-    //! The current operation mode for all subhals.
-    OperationMode mCurrentOperationMode = OperationMode::NORMAL;
-
-    //! The single subHal that supports directChannel reporting.
-    ISensorsSubHal* mDirectChannelSubHal = nullptr;
-
-    //! The timeout for each pending write on background thread for events.
-    static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
-
-    //! The bit mask used to get the subhal index from a sensor handle.
-    static constexpr int32_t kSensorHandleSubHalIndexMask = 0xFF000000;
-
-    /**
-     * A FIFO queue of pairs of vector of events and the number of wakeup events in that vector
-     * which are waiting to be written to the events fmq in the background thread.
-     */
-    std::queue<std::pair<std::vector<Event>, size_t>> mPendingWriteEventsQueue;
-
-    //! The most events observed on the pending write events queue for debug purposes.
-    size_t mMostEventsObservedPendingWriteEventsQueue = 0;
-
-    //! The max number of events allowed in the pending write events queue
-    static constexpr size_t kMaxSizePendingWriteEventsQueue = 100000;
-
-    //! The number of events in the pending write events queue
-    size_t mSizePendingWriteEventsQueue = 0;
-
-    //! The mutex protecting writing to the fmq and the pending events queue
-    std::mutex mEventQueueWriteMutex;
-
-    //! The condition variable waiting on pending write events to stack up
-    std::condition_variable mEventQueueWriteCV;
-
-    //! The thread object ptr that handles pending writes
-    std::thread mPendingWritesThread;
-
-    //! The thread object that handles wakelocks
-    std::thread mWakelockThread;
-
-    //! The bool indicating whether to end the threads started in initialize
-    std::atomic_bool mThreadsRun = true;
-
-    //! The mutex protecting access to the dynamic sensors added and removed methods.
-    std::mutex mDynamicSensorsMutex;
-
-    // WakelockRefCount membar vars below
-
-    //! The mutex protecting the wakelock refcount and subsequent wakelock releases and
-    //! acquisitions
-    std::recursive_mutex mWakelockMutex;
-
-    std::condition_variable_any mWakelockCV;
-
-    //! The refcount of how many ScopedWakelocks and pending wakeup events are active
-    size_t mWakelockRefCount = 0;
-
-    int64_t mWakelockTimeoutStartTime = getTimeNow();
-
-    int64_t mWakelockTimeoutResetTime = getTimeNow();
-
-    const char* kWakelockName = "SensorsHAL_WAKEUP";
-
-    /**
-     * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
-     * listed in a config file.
-     */
-    void initializeSubHalListFromConfigFile(const char* configFileName);
-
-    /**
-     * Initialize the HalProxyCallback vector using the list of subhals.
-     */
-    void initializeSubHalCallbacks();
-
-    /**
-     * Initialize the list of SensorInfo objects in mSensorList by getting sensors from each
-     * subhal.
-     */
-    void initializeSensorList();
-
-    /**
-     * Try using the default include directories as well as the directories defined in
-     * kSubHalShareObjectLocations to get a handle for dlsym for a subhal.
-     *
-     * @param filename The file name to search for.
-     *
-     * @return The handle or nullptr if search failed.
-     */
-    void* getHandleForSubHalSharedObject(const std::string& filename);
-
-    /**
-     * Calls the helper methods that all ctors use.
-     */
-    void init();
-
-    /**
-     * Stops all threads by setting the threads running flag to false and joining to them.
-     */
-    void stopThreads();
-
-    /**
-     * Disable all the sensors observed by the HalProxy.
-     */
-    void disableAllSensors();
-
-    /**
-     * Starts the thread that handles pending writes to event fmq.
-     *
-     * @param halProxy The HalProxy object pointer.
-     */
-    static void startPendingWritesThread(HalProxy* halProxy);
-
-    //! Handles the pending writes on events to eventqueue.
-    void handlePendingWrites();
-
-    /**
-     * Starts the thread that handles decrementing the ref count on wakeup events processed by the
-     * framework and timing out wakelocks.
-     *
-     * @param halProxy The HalProxy object pointer.
-     */
-    static void startWakelockThread(HalProxy* halProxy);
-
-    //! Handles the wakelocks.
-    void handleWakelocks();
-
-    /**
-     * @param timeLeft The variable that should be set to the timeleft before timeout will occur or
-     * unmodified if timeout occurred.
-     *
-     * @return true if the shared wakelock has been held passed the timeout and should be released
-     */
-    bool sharedWakelockDidTimeout(int64_t* timeLeft);
-
-    /**
-     * Reset all the member variables associated with the wakelock ref count and maybe release
-     * the shared wakelock.
-     */
-    void resetSharedWakelock();
-
-    /**
-     * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
-     * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
-     * direct channel enabled sensor seen.
-     *
-     * @param sensorInfo The SensorInfo object that may be altered to have direct channel support
-     *    disabled.
-     * @param subHal The subhal pointer that the current sensorInfo object came from.
-     */
-    void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal);
-
-    /*
-     * Get the subhal pointer which can be found by indexing into the mSubHalList vector
-     * using the index from the first byte of sensorHandle.
-     *
-     * @param sensorHandle The handle used to identify a sensor in one of the subhals.
-     */
-    ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle);
-
-    /**
-     * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList.
-     *
-     * @param sensorHandle The sensor handle to check.
-     *
-     * @return true if sensorHandles's subhal index byte is valid.
-     */
-    bool isSubHalIndexValid(int32_t sensorHandle);
-
-    /**
-     * Count the number of wakeup events in the first n events of the vector.
-     *
-     * @param events The vector of Event objects.
-     * @param n The end index not inclusive of events to consider.
-     *
-     * @return The number of wakeup events of the considered events.
-     */
-    size_t countNumWakeupEvents(const std::vector<Event>& events, size_t n);
-
-    /*
-     * Clear out the subhal index bytes from a sensorHandle.
-     *
-     * @param sensorHandle The sensor handle to modify.
-     *
-     * @return The modified version of the sensor handle.
-     */
-    static int32_t clearSubHalIndex(int32_t sensorHandle);
-
-    /**
-     * @param sensorHandle The sensor handle to modify.
-     *
-     * @return true if subHalIndex byte of sensorHandle is zeroed.
-     */
-    static bool subHalIndexIsClear(int32_t sensorHandle);
-};
-
-/**
- * Callback class used to provide the HalProxy with the index of which subHal is invoking
- */
-class HalProxyCallback : public IHalProxyCallback {
-    using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo;
-
-  public:
-    HalProxyCallback(HalProxy* halProxy, int32_t subHalIndex)
-        : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {}
-
-    Return<void> onDynamicSensorsConnected(
-            const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
-        return mHalProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex);
-    }
-
-    Return<void> onDynamicSensorsDisconnected(
-            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
-        return mHalProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex);
-    }
-
-    void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock);
-
-    ScopedWakelock createScopedWakelock(bool lock);
-
-  private:
-    HalProxy* mHalProxy;
-    int32_t mSubHalIndex;
-
-    std::vector<Event> processEvents(const std::vector<Event>& events,
-                                     size_t* numWakeupEvents) const;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/2.0/multihal/include/ScopedWakelock.h
deleted file mode 100644
index aa6d9db..0000000
--- a/sensors/2.0/multihal/include/ScopedWakelock.h
+++ /dev/null
@@ -1,104 +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.
- */
-
-#pragma once
-
-#include <android/hardware/sensors/2.0/types.h>
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::sensors::V2_0::SensorTimeout;
-
-const int64_t kWakelockTimeoutNs =
-        static_cast<int64_t>(SensorTimeout::WAKE_LOCK_SECONDS) * INT64_C(1000000000);
-
-int64_t getTimeNow();
-
-class IScopedWakelockRefCounter : public RefBase {
-  public:
-    /**
-     * Increment the wakelock ref count and maybe acquire the shared wakelock if incrementing
-     * from 0 then return the time of incrementing back to caller.
-     *
-     * @param delta The amount to change ref count by.
-     * @param timeoutStart The ptr to the timestamp in ns that the increment occurred which will be
-     *        set in the function or nullptr if not specified.
-     *
-     * @return true if successfully incremented the wakelock ref count.
-     */
-    virtual bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
-                                                          int64_t* timeoutStart = nullptr) = 0;
-    /**
-     * Decrement the wakelock ref count and maybe release wakelock if ref count ends up 0.
-     *
-     * @param delta The amount to change ref count by.
-     * @param timeoutStart The timestamp in ns that the calling context kept track of when
-     *        incrementing the ref count or -1 by default
-     */
-    virtual void decrementRefCountAndMaybeReleaseWakelock(size_t delta,
-                                                          int64_t timeoutStart = -1) = 0;
-    // Virtual dtor needed for compilation success
-    virtual ~IScopedWakelockRefCounter(){};
-};
-
-/**
- * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a
- * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block.
- * When a ScopedWakelock is created, it increments the reference count stored in the HalProxy
- * for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes
- * out of scope, the ref count is decremented, potentially releasing the wake lock if no other
- * references to the wake lock exist.
- *
- * This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback
- * provided to sub-HALs during initialization and should be used for all wake lock acquisition
- * inside of the sub-HAL to ensure wake locks are not held indefinitely.
- *
- * The most prevalent use case for this class will be for posting events to the framework through
- * the postEvents HalProxy callback. The expectation is that sub-HALs will create this
- * ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean
- * provided to createScopedWakelock will be set the according to whether the sensor events are
- * from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the
- * postEvents callback passing in the previously created ScopedWakelock. At this point, ownership
- * of the object will be passed to the HalProxy that will then be responsible for ensuring any
- * wake locks continue to be held, if necessary.
- */
-class ScopedWakelock {
-  public:
-    ScopedWakelock(ScopedWakelock&&) = default;
-    ScopedWakelock& operator=(ScopedWakelock&&) = default;
-    virtual ~ScopedWakelock();
-
-    bool isLocked() const { return mLocked; }
-
-  private:
-    friend class HalProxyCallback;
-    IScopedWakelockRefCounter* mRefCounter;
-    int64_t mCreatedAtTimeNs;
-    bool mLocked;
-    ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked);
-    ScopedWakelock(const ScopedWakelock&) = delete;
-    ScopedWakelock& operator=(const ScopedWakelock&) = delete;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
\ No newline at end of file
diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h
deleted file mode 100644
index 92ae3a6..0000000
--- a/sensors/2.0/multihal/include/SubHal.h
+++ /dev/null
@@ -1,170 +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.
- */
-
-#pragma once
-
-#include "ScopedWakelock.h"
-
-#include <android/hardware/sensors/1.0/types.h>
-#include <android/hardware/sensors/2.0/ISensors.h>
-
-#include <vector>
-
-// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 |
-// (HAL minor version) << 16 | (multiHAL version)
-#define SUB_HAL_2_0_VERSION 0x02000000
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::sensors::V1_0::Event;
-using ::android::hardware::sensors::V1_0::Result;
-using ::android::hardware::sensors::V1_0::SensorInfo;
-
-/**
- * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor
- * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure
- * callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient
- * manner.
- */
-class IHalProxyCallback : public ISensorsCallback {
-  public:
-    /**
-     * Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this
-     * whenever new sensor events need to be delivered to the sensors framework. Once invoked, the
-     * HalProxy will attempt to send events to the sensors framework using a blocking write with a
-     * 5 second timeout. This write may be done asynchronously if the queue used to communicate
-     * with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the
-     * write fails, the events will be dropped and any wake locks held will be released.
-     *
-     * The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's
-     * not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant
-     * with the sensors HAL 2.0 specification. Additionally, since ScopedWakelock isn't copyable,
-     * the HalProxy will take ownership of the wake lock given when this method is invoked. Once the
-     * method returns, the HalProxy will handle holding the wake lock, if necessary, until the
-     * framework has successfully processed any wakeup events.
-     *
-     * No return type is used for this callback to avoid sub-HALs trying to resend events when
-     * writes fail. Writes should only fail when the framework is under inordinate stress which will
-     * likely result in a framework restart so retrying will likely only result in overloading the
-     * HalProxy. Sub-HALs should always assume that the write was a success and perform any
-     * necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and
-     * bug reports) it encounters during delivery to ensure it's obvious that a failure occurred.
-     *
-     * @param events the events that should be sent to the sensors framework
-     * @param wakelock ScopedWakelock that should be locked to send events from wake sensors and
-     *     unlocked otherwise.
-     */
-    virtual void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) = 0;
-
-    /**
-     * Initializes a ScopedWakelock on the stack that, when locked, will increment the reference
-     * count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class
-     * definition for how it should be used.
-     *
-     * @param lock whether the ScopedWakelock should be locked before it's returned.
-     * @return the created ScopedWakelock
-     */
-    virtual ScopedWakelock createScopedWakelock(bool lock) = 0;
-};
-
-/**
- * ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with
- * multihal 2.0 and in order for the HalProxy to successfully load and communicate with the sub-HAL.
- *
- * Any vendor wishing to implement this interface and support multihal 2.0 will need to create a
- * dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by
- * the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's
- * implementation of sensorsHalGetSubHal.
- *
- * With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec.
- * Any sensor handles given to the HalProxy, either through getSensorsList() or the
- * onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL
- * handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and
- * sub-HALs can continue to use the lower 3 bytes of the handle.
- */
-class ISensorsSubHal : public ISensors {
-  public:
-    // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement
-    // the version below to allow communciation logic to centralized in the HalProxy
-    Return<Result> initialize(
-            const ::android::hardware::MQDescriptorSync<Event>& /* eventQueueDescriptor */,
-            const ::android::hardware::MQDescriptorSync<uint32_t>& /* wakeLockDescriptor */,
-            const sp<ISensorsCallback>& /* sensorsCallback */) final {
-        return Result::INVALID_OPERATION;
-    }
-
-    /**
-     * Method defined in ::android::hidl::base::V1_0::IBase.
-     *
-     * This method should write debug information to hidl_handle that is useful for debugging
-     * issues. Suggestions include:
-     * - Sensor info including handle values and any other state available in the SensorInfo class
-     * - List of active sensors and their current sampling period and reporting latency
-     * - Information about pending flush requests
-     * - Current operating mode
-     * - Currently registered direct channel info
-     * - A history of any of the above
-     */
-    virtual Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) = 0;
-
-    /**
-     * @return A human-readable name for use in wake locks and logging.
-     */
-    virtual const std::string getName() = 0;
-
-    /**
-     * This is the first method invoked on the sub-HAL after it's allocated through
-     * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and
-     * retain the callback given in order to communicate with the HalProxy. Method will be called
-     * anytime the sensors framework restarts. Therefore, this method will be responsible for
-     * reseting the state of the subhal and cleaning up and reallocating any previously allocated
-     * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state
-     * as well.
-     *
-     * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state
-     *     changes, new sensor events should be sent to the framework, and when a new ScopedWakelock
-     *     should be created.
-     * @return result OK on success
-     */
-    virtual Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) = 0;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
-
-using ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
-
-/**
- * Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic
- * library. This function will only be invoked once at initialization time.
- *
- * NOTE: The supported sensors HAL version must match SUB_HAL_2_0_VERSION exactly or the HalProxy
- * will fail to initialize.
- *
- * @param uint32_t when this function returns, this parameter must contain the HAL version that
- *     this sub-HAL supports. To support this version of multi-HAL, this must be set to
- *     SUB_HAL_2_0_VERSION.
- * @return A statically allocated, valid ISensorsSubHal implementation.
- */
-__attribute__((visibility("default"))) extern "C" ISensorsSubHal* sensorsHalGetSubHal(
-        uint32_t* version);
diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp
index ef77048..f50ad7e 100644
--- a/sensors/2.0/multihal/service.cpp
+++ b/sensors/2.0/multihal/service.cpp
@@ -23,12 +23,12 @@
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::sensors::V2_0::ISensors;
-using android::hardware::sensors::V2_0::implementation::HalProxy;
+using android::hardware::sensors::V2_1::implementation::HalProxyV2_0;
 
 int main(int /* argc */, char** /* argv */) {
     configureRpcThreadpool(1, true);
 
-    android::sp<ISensors> halProxy = new HalProxy();
+    android::sp<ISensors> halProxy = new HalProxyV2_0();
     if (halProxy->registerAsService() != ::android::OK) {
         ALOGE("Failed to register Sensors HAL instance");
         return -1;
diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp
deleted file mode 100644
index 472f3f3..0000000
--- a/sensors/2.0/multihal/tests/Android.bp
+++ /dev/null
@@ -1,101 +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_defaults {
-    name: "android.hardware.sensors@2.0-fakesubhal-defaults",
-    srcs: [
-        "fake_subhal/*.cpp",
-    ],
-    header_libs: [
-        "android.hardware.sensors@2.0-multihal.header",
-    ],
-    export_include_dirs: ["fake_subhal"],
-    shared_libs: [
-        "android.hardware.sensors@1.0",
-        "android.hardware.sensors@2.0",
-        "android.hardware.sensors@2.0-ScopedWakelock",
-        "libcutils",
-        "libfmq",
-        "libhardware",
-        "libhidlbase",
-        "liblog",
-        "libpower",
-        "libutils",
-    ],
-    static_libs: [
-        "android.hardware.sensors@2.0-HalProxy",
-    ],
-    cflags: [
-        "-DLOG_TAG=\"FakeSubHal\"",
-    ],
-}
-
-cc_library {
-    name: "android.hardware.sensors@2.0-fakesubhal-config1",
-    vendor: true,
-    defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
-    cflags: [
-        "-DSUPPORT_CONTINUOUS_SENSORS",
-        "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"",
-    ],
-}
-
-cc_library {
-    name: "android.hardware.sensors@2.0-fakesubhal-config2",
-    vendor: true,
-    defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
-    cflags: [
-        "-DSUPPORT_ON_CHANGE_SENSORS",
-        "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"",
-    ],
-}
-
-cc_test_library {
-    name: "android.hardware.sensors@2.0-fakesubhal-unittest",
-    vendor_available: true,
-    defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
-    cflags: [
-        "-DSUPPORT_ON_CHANGE_SENSORS",
-        "-DSUPPORT_CONTINUOUS_SENSORS",
-        "-DSUB_HAL_NAME=\"FakeSubHal-Test\"",
-    ],
-}
-
-cc_test {
-    name: "android.hardware.sensors@2.0-halproxy-unit-tests",
-    srcs: ["HalProxy_test.cpp"],
-    vendor: true,
-    static_libs: [
-        "android.hardware.sensors@2.0-HalProxy",
-        "android.hardware.sensors@2.0-fakesubhal-unittest",
-        "android.hardware.sensors@2.0-ScopedWakelock.testlib",
-    ],
-    shared_libs: [
-        "android.hardware.sensors@1.0",
-        "android.hardware.sensors@2.0",
-        "libbase",
-        "libcutils",
-        "libfmq",
-        "libhardware",
-        "libhidlbase",
-        "liblog",
-        "libpower",
-        "libutils",
-    ],
-    test_suites: ["device-tests"],
-    cflags: [
-        "-DLOG_TAG=\"HalProxyUnitTests\"",
-    ],
-}
diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp
deleted file mode 100644
index 4633a75..0000000
--- a/sensors/2.0/multihal/tests/HalProxy_test.cpp
+++ /dev/null
@@ -1,872 +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 <gtest/gtest.h>
-
-#include <android/hardware/sensors/2.0/types.h>
-#include <fmq/MessageQueue.h>
-
-#include "HalProxy.h"
-#include "ScopedWakelock.h"
-#include "SensorsSubHal.h"
-
-#include <chrono>
-#include <set>
-#include <thread>
-#include <vector>
-
-namespace {
-
-using ::android::hardware::EventFlag;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::MessageQueue;
-using ::android::hardware::Return;
-using ::android::hardware::sensors::V1_0::EventPayload;
-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::V2_0::EventQueueFlagBits;
-using ::android::hardware::sensors::V2_0::ISensorsCallback;
-using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
-using ::android::hardware::sensors::V2_0::implementation::HalProxy;
-using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback;
-using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal;
-using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal;
-using ::android::hardware::sensors::V2_0::subhal::implementation::
-        AllSupportDirectChannelSensorsSubHal;
-using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal;
-using ::android::hardware::sensors::V2_0::subhal::implementation::
-        DoesNotSupportDirectChannelSensorsSubHal;
-using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal;
-using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal;
-using ::android::hardware::sensors::V2_0::subhal::implementation::
-        SetOperationModeFailingSensorsSubHal;
-
-using EventMessageQueue = MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite>;
-using WakeupMessageQueue = MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite>;
-
-// The barebones sensors callback class passed into halproxy initialize calls
-class SensorsCallback : public ISensorsCallback {
-  public:
-    Return<void> onDynamicSensorsConnected(
-            const hidl_vec<SensorInfo>& /*dynamicSensorsAdded*/) override {
-        // Nothing yet
-        return Return<void>();
-    }
-
-    Return<void> onDynamicSensorsDisconnected(
-            const hidl_vec<int32_t>& /*dynamicSensorHandlesRemoved*/) override {
-        // Nothing yet
-        return Return<void>();
-    }
-};
-
-// The sensors callback that expects a variable list of sensors to be added
-class TestSensorsCallback : public ISensorsCallback {
-  public:
-    Return<void> onDynamicSensorsConnected(
-            const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
-        mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(),
-                                 dynamicSensorsAdded.end());
-        return Return<void>();
-    }
-
-    Return<void> onDynamicSensorsDisconnected(
-            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
-        mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(),
-                                          dynamicSensorHandlesRemoved.begin(),
-                                          dynamicSensorHandlesRemoved.end());
-        return Return<void>();
-    }
-
-    const std::vector<SensorInfo>& getSensorsConnected() const { return mSensorsConnected; }
-    const std::vector<int32_t>& getSensorHandlesDisconnected() const {
-        return mSensorHandlesDisconnected;
-    }
-
-  private:
-    std::vector<SensorInfo> mSensorsConnected;
-    std::vector<int32_t> mSensorHandlesDisconnected;
-};
-
-// Helper declarations follow
-
-/**
- * Tests that for each SensorInfo object from a proxy getSensorsList call each corresponding
- * object from a subhal getSensorsList call has the same type and its last 3 bytes are the
- * same for sensorHandle field.
- *
- * @param proxySensorsList The list of SensorInfo objects from the proxy.getSensorsList callback.
- * @param subHalSenosrsList The list of SensorInfo objects from the subHal.getSensorsList callback.
- */
-void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
-                                       const std::vector<SensorInfo>& subHalSensorsList);
-
-/**
- * Tests that there is exactly one subhal that allows its sensors to have direct channel enabled.
- * Therefore, all SensorInfo objects that are not from the enabled subhal should be disabled for
- * direct channel.
- *
- * @param sensorsList The SensorInfo object list from proxy.getSensorsList call.
- * @param enabledSubHalIndex The index of the subhal in the halproxy that is expected to be
- *     enabled.
- */
-void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
-                                                     size_t enabledSubHalIndex);
-
-void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
-                               EventFlag* wakelockQueueFlag);
-
-bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
-                          EventFlag* eventQueueFlag);
-
-std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size);
-
-std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size);
-
-/**
- * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
- *    which is a wakeup type sensor.
- *
- * @return A proximity event.
- */
-Event makeProximityEvent();
-
-/**
- * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
- *    which is a wakeup type sensor.
- *
- * @return A proximity event.
- */
-Event makeAccelerometerEvent();
-
-/**
- * Make a certain number of proximity type events with the sensorHandle field set to
- * the proper number for AllSensorsSubHal subhal type.
- *
- * @param numEvents The number of events to make.
- *
- * @return The created list of events.
- */
-std::vector<Event> makeMultipleProximityEvents(size_t numEvents);
-
-/**
- * Make a certain number of accelerometer type events with the sensorHandle field set to
- * the proper number for AllSensorsSubHal subhal type.
- *
- * @param numEvents The number of events to make.
- *
- * @return The created list of events.
- */
-std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents);
-
-/**
- * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo
- * objects that have the sensorHandle property set to int32_ts from start to start + size
- * (exclusive) and push those sensorHandles also onto 'sensorHandles'.
- *
- * @param start The starting sensorHandle value.
- * @param size The ending (not included) sensorHandle value.
- * @param sensors The SensorInfo object vector reference to push_back to.
- * @param sensorHandles The sensor handles int32_t vector reference to push_back to.
- */
-void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
-                                                  std::vector<SensorInfo>& sensors,
-                                                  std::vector<int32_t>& sensorHandles);
-
-// Tests follow
-TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> fakeSubHals{&subHal};
-    HalProxy proxy(fakeSubHals);
-
-    proxy.getSensorsList([&](const auto& proxySensorsList) {
-        subHal.getSensorsList([&](const auto& subHalSensorsList) {
-            testSensorsListFromProxyAndSubHal(proxySensorsList, subHalSensorsList);
-        });
-    });
-}
-
-TEST(HalProxyTest, GetSensorsListTwoSubHalTest) {
-    ContinuousSensorsSubHal continuousSubHal;
-    OnChangeSensorsSubHal onChangeSubHal;
-    std::vector<ISensorsSubHal*> fakeSubHals;
-    fakeSubHals.push_back(&continuousSubHal);
-    fakeSubHals.push_back(&onChangeSubHal);
-    HalProxy proxy(fakeSubHals);
-
-    std::vector<SensorInfo> proxySensorsList, combinedSubHalSensorsList;
-
-    proxy.getSensorsList([&](const auto& list) { proxySensorsList = list; });
-    continuousSubHal.getSensorsList([&](const auto& list) {
-        combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
-    });
-    onChangeSubHal.getSensorsList([&](const auto& list) {
-        combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
-    });
-
-    testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList);
-}
-
-TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) {
-    ContinuousSensorsSubHal subHal1;
-    OnChangeSensorsSubHal subHal2;
-
-    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
-    HalProxy proxy(fakeSubHals);
-
-    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
-    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
-
-    Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
-
-    EXPECT_EQ(result, Result::OK);
-    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::DATA_INJECTION);
-    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::DATA_INJECTION);
-}
-
-TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) {
-    AllSensorsSubHal subHal1;
-    SetOperationModeFailingSensorsSubHal subHal2;
-
-    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
-    HalProxy proxy(fakeSubHals);
-
-    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
-    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
-
-    Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
-
-    EXPECT_NE(result, Result::OK);
-    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
-    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
-}
-
-TEST(HalProxyTest, InitDirectChannelTwoSubHalsUnitTest) {
-    AllSupportDirectChannelSensorsSubHal subHal1;
-    AllSupportDirectChannelSensorsSubHal subHal2;
-
-    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
-    HalProxy proxy(fakeSubHals);
-
-    proxy.getSensorsList([&](const auto& sensorsList) {
-        testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0);
-    });
-}
-
-TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) {
-    DoesNotSupportDirectChannelSensorsSubHal subHal1;
-    AllSupportDirectChannelSensorsSubHal subHal2, subHal3;
-    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2, &subHal3};
-    HalProxy proxy(fakeSubHals);
-
-    proxy.getSensorsList([&](const auto& sensorsList) {
-        testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1);
-    });
-}
-
-TEST(HalProxyTest, PostSingleNonWakeupEvent) {
-    constexpr size_t kQueueSize = 5;
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-    HalProxy proxy(subHals);
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    std::vector<Event> events{makeAccelerometerEvent()};
-    subHal.postEvents(events, false /* wakeup */);
-
-    EXPECT_EQ(eventQueue->availableToRead(), 1);
-}
-
-TEST(HalProxyTest, PostMultipleNonWakeupEvent) {
-    constexpr size_t kQueueSize = 5;
-    constexpr size_t kNumEvents = 3;
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-    HalProxy proxy(subHals);
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
-    subHal.postEvents(events, false /* wakeup */);
-
-    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
-}
-
-TEST(HalProxyTest, PostSingleWakeupEvent) {
-    constexpr size_t kQueueSize = 5;
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-    HalProxy proxy(subHals);
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    EventFlag* eventQueueFlag;
-    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
-
-    EventFlag* wakelockQueueFlag;
-    EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
-
-    std::vector<Event> events{makeProximityEvent()};
-    subHal.postEvents(events, true /* wakeup */);
-
-    EXPECT_EQ(eventQueue->availableToRead(), 1);
-
-    readEventsOutOfQueue(1, eventQueue, eventQueueFlag);
-    ackWakeupEventsToHalProxy(1, wakeLockQueue, wakelockQueueFlag);
-}
-
-TEST(HalProxyTest, PostMultipleWakeupEvents) {
-    constexpr size_t kQueueSize = 5;
-    constexpr size_t kNumEvents = 3;
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-    HalProxy proxy(subHals);
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    EventFlag* eventQueueFlag;
-    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
-
-    EventFlag* wakelockQueueFlag;
-    EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
-
-    std::vector<Event> events = makeMultipleProximityEvents(kNumEvents);
-    subHal.postEvents(events, true /* wakeup */);
-
-    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
-
-    readEventsOutOfQueue(kNumEvents, eventQueue, eventQueueFlag);
-    ackWakeupEventsToHalProxy(kNumEvents, wakeLockQueue, wakelockQueueFlag);
-}
-
-TEST(HalProxyTest, PostEventsMultipleSubhals) {
-    constexpr size_t kQueueSize = 5;
-    constexpr size_t kNumEvents = 2;
-    AllSensorsSubHal subHal1, subHal2;
-    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
-    HalProxy proxy(subHals);
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
-    subHal1.postEvents(events, false /* wakeup */);
-
-    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
-
-    subHal2.postEvents(events, false /* wakeup */);
-
-    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
-}
-
-TEST(HalProxyTest, PostEventsDelayedWrite) {
-    constexpr size_t kQueueSize = 5;
-    constexpr size_t kNumEvents = 6;
-    AllSensorsSubHal subHal1, subHal2;
-    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
-    HalProxy proxy(subHals);
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    EventFlag* eventQueueFlag;
-    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
-
-    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
-    subHal1.postEvents(events, false /* wakeup */);
-
-    EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
-
-    // readblock a full queue size worth of events out of queue, timeout for half a second
-    EXPECT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
-
-    // proxy background thread should have wrote remaining events when it saw space
-    EXPECT_TRUE(readEventsOutOfQueue(kNumEvents - kQueueSize, eventQueue, eventQueueFlag));
-
-    EXPECT_EQ(eventQueue->availableToRead(), 0);
-}
-
-TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) {
-    constexpr size_t kQueueSize = 5;
-    constexpr size_t kNumEvents = 2;
-    AllSensorsSubHal subHal1, subHal2;
-    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
-    HalProxy proxy(subHals);
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
-
-    std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false);
-    std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false);
-
-    t1.join();
-    t2.join();
-
-    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
-}
-
-TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) {
-    constexpr size_t kQueueSize = 5;
-    constexpr size_t kNumEvents = 6;
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    HalProxy proxy(subHals);
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
-    subHal.postEvents(events, false /* wakeup */);
-
-    // Destructing HalProxy object with events on the background thread
-}
-
-TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) {
-    constexpr size_t kQueueSize = 5;
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    HalProxy proxy(subHals);
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    std::vector<Event> events{makeProximityEvent()};
-    subHal.postEvents(events, true /* wakeup */);
-
-    // Not sending any acks back through wakeLockQueue
-
-    // Destructing HalProxy object with unacked wakeup events posted
-}
-
-TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) {
-    constexpr size_t kQueueSize = 5;
-    constexpr size_t kNumEvents = 10;
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    HalProxy proxy(subHals);
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
-    subHal.postEvents(events, false /* wakeup */);
-
-    eventQueue = makeEventFMQ(kQueueSize);
-    wakeLockQueue = makeWakelockFMQ(kQueueSize);
-
-    Result secondInitResult =
-            proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-    EXPECT_EQ(secondInitResult, Result::OK);
-    // Small sleep so that pending writes thread has a change to hit writeBlocking call.
-    std::this_thread::sleep_for(std::chrono::milliseconds(5));
-    Event eventOut;
-    EXPECT_FALSE(eventQueue->read(&eventOut));
-}
-
-TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) {
-    constexpr size_t kQueueSize = 5;
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    HalProxy proxy(subHals);
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    std::vector<Event> events{makeProximityEvent()};
-    subHal.postEvents(events, true /* wakeup */);
-
-    // Not sending any acks back through wakeLockQueue
-
-    eventQueue = makeEventFMQ(kQueueSize);
-    wakeLockQueue = makeWakelockFMQ(kQueueSize);
-
-    Result secondInitResult =
-            proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-    EXPECT_EQ(secondInitResult, Result::OK);
-}
-
-TEST(HalProxyTest, InitializeManyTimesInARow) {
-    constexpr size_t kQueueSize = 5;
-    constexpr size_t kNumTimesToInit = 100;
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    HalProxy proxy(subHals);
-
-    for (size_t i = 0; i < kNumTimesToInit; i++) {
-        Result secondInitResult =
-                proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-        EXPECT_EQ(secondInitResult, Result::OK);
-    }
-}
-
-TEST(HalProxyTest, OperationModeResetOnInitialize) {
-    constexpr size_t kQueueSize = 5;
-    AllSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    HalProxy proxy(subHals);
-    proxy.setOperationMode(OperationMode::DATA_INJECTION);
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-    Event event = makeAccelerometerEvent();
-    // Should not be able to inject a non AdditionInfo type event because operation mode should
-    // have been reset to NORMAL
-    EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
-}
-
-TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) {
-    constexpr size_t kQueueSize = 5;
-    constexpr size_t kNumSensors = 5;
-    AddAndRemoveDynamicSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    HalProxy proxy(subHals);
-
-    std::vector<SensorInfo> sensorsToConnect;
-    std::vector<int32_t> sensorHandlesToAttemptToRemove;
-    makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
-                                                 sensorHandlesToAttemptToRemove);
-
-    std::vector<int32_t> nonDynamicSensorHandles;
-    for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
-        nonDynamicSensorHandles.push_back(sensorHandle);
-    }
-
-    TestSensorsCallback* callback = new TestSensorsCallback();
-    ::android::sp<ISensorsCallback> callbackPtr = callback;
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
-    subHal.addDynamicSensors(sensorsToConnect);
-
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
-    subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
-
-    std::vector<int32_t> sensorHandlesActuallyRemoved = callback->getSensorHandlesDisconnected();
-
-    // Should not have received the sensorHandles for any dynamic sensors that were removed since
-    // all of them should have been removed in the second initialize call.
-    EXPECT_TRUE(sensorHandlesActuallyRemoved.empty());
-}
-
-TEST(HalProxyTest, DynamicSensorsConnectedTest) {
-    constexpr size_t kNumSensors = 3;
-    AddAndRemoveDynamicSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-    HalProxy proxy(subHals);
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
-
-    std::vector<SensorInfo> sensorsToConnect;
-    std::vector<int32_t> sensorHandlesToExpect;
-    makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
-                                                 sensorHandlesToExpect);
-
-    TestSensorsCallback* callback = new TestSensorsCallback();
-    ::android::sp<ISensorsCallback> callbackPtr = callback;
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
-    subHal.addDynamicSensors(sensorsToConnect);
-
-    std::vector<SensorInfo> sensorsSeen = callback->getSensorsConnected();
-    EXPECT_EQ(kNumSensors, sensorsSeen.size());
-    for (size_t i = 0; i < kNumSensors; i++) {
-        auto sensorHandleSeen = sensorsSeen[i].sensorHandle;
-        // Note since only one subhal we do not need to change first byte for expected
-        auto sensorHandleExpected = sensorHandlesToExpect[i];
-        EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
-    }
-}
-
-TEST(HalProxyTest, DynamicSensorsDisconnectedTest) {
-    constexpr size_t kNumSensors = 3;
-    AddAndRemoveDynamicSensorsSubHal subHal;
-    std::vector<ISensorsSubHal*> subHals{&subHal};
-    HalProxy proxy(subHals);
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
-
-    std::vector<SensorInfo> sensorsToConnect;
-    std::vector<int32_t> sensorHandlesToExpect;
-    makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect,
-                                                 sensorHandlesToExpect);
-
-    std::vector<int32_t> nonDynamicSensorHandles;
-    for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
-        nonDynamicSensorHandles.push_back(sensorHandle);
-    }
-
-    std::set<int32_t> nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(),
-                                                 nonDynamicSensorHandles.end());
-
-    std::vector<int32_t> sensorHandlesToAttemptToRemove;
-    sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
-                                          sensorHandlesToExpect.begin(),
-                                          sensorHandlesToExpect.end());
-    sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
-                                          nonDynamicSensorHandles.begin(),
-                                          nonDynamicSensorHandles.end());
-
-    TestSensorsCallback* callback = new TestSensorsCallback();
-    ::android::sp<ISensorsCallback> callbackPtr = callback;
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
-    subHal.addDynamicSensors(sensorsToConnect);
-    subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
-
-    std::vector<int32_t> sensorHandlesSeen = callback->getSensorHandlesDisconnected();
-    EXPECT_EQ(kNumSensors, sensorHandlesSeen.size());
-    for (size_t i = 0; i < kNumSensors; i++) {
-        auto sensorHandleSeen = sensorHandlesSeen[i];
-        // Note since only one subhal we do not need to change first byte for expected
-        auto sensorHandleExpected = sensorHandlesToExpect[i];
-        EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
-        EXPECT_TRUE(nonDynamicSensorHandlesSet.find(sensorHandleSeen) ==
-                    nonDynamicSensorHandlesSet.end());
-    }
-}
-
-TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) {
-    constexpr size_t kNumSubHals = 3;
-    constexpr size_t kQueueSize = 5;
-    int32_t kNumSubHalsInt32 = static_cast<int32_t>(kNumSubHals);
-    std::vector<AllSensorsSubHal> subHalObjs(kNumSubHals);
-    std::vector<ISensorsSubHal*> subHals;
-    for (const auto& subHal : subHalObjs) {
-        subHals.push_back((ISensorsSubHal*)(&subHal));
-    }
-
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    HalProxy proxy(subHals);
-    // Initialize for the injectSensorData call so callback postEvents is valid
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    // For testing proxy.injectSensorData properly
-    proxy.setOperationMode(OperationMode::DATA_INJECTION);
-
-    // kNumSubHalsInt32 index is one off the end of mSubHalList in proxy object
-    EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE);
-    EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE);
-    EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE);
-    Event event;
-    event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24);
-    EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
-}
-
-TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) {
-    constexpr size_t kQueueSize = 5;
-    constexpr int32_t subhal1Index = 0;
-    constexpr int32_t subhal2Index = 1;
-    AllSensorsSubHal subhal1;
-    AllSensorsSubHal subhal2;
-    std::vector<ISensorsSubHal*> subHals{&subhal1, &subhal2};
-
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    HalProxy proxy(subHals);
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    int32_t sensorHandleToPost = 0x00000001;
-    Event eventIn = makeAccelerometerEvent();
-    eventIn.sensorHandle = sensorHandleToPost;
-    std::vector<Event> eventsToPost{eventIn};
-    subhal1.postEvents(eventsToPost, false);
-
-    Event eventOut;
-    EXPECT_TRUE(eventQueue->read(&eventOut));
-
-    EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost);
-
-    subhal2.postEvents(eventsToPost, false);
-
-    EXPECT_TRUE(eventQueue->read(&eventOut));
-
-    EXPECT_EQ(eventOut.sensorHandle, (subhal2Index << 24) | sensorHandleToPost);
-}
-
-TEST(HalProxyTest, FillAndDrainPendingQueueTest) {
-    constexpr size_t kQueueSize = 5;
-    // TODO: Make this constant linked to same limit in HalProxy.h
-    constexpr size_t kMaxPendingQueueSize = 100000;
-    AllSensorsSubHal subhal;
-    std::vector<ISensorsSubHal*> subHals{&subhal};
-
-    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
-    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
-    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
-    EventFlag* eventQueueFlag;
-    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
-    HalProxy proxy(subHals);
-    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
-
-    // Fill pending queue
-    std::vector<Event> events = makeMultipleAccelerometerEvents(kQueueSize);
-    subhal.postEvents(events, false);
-    events = makeMultipleAccelerometerEvents(kMaxPendingQueueSize);
-    subhal.postEvents(events, false);
-
-    // Drain pending queue
-    for (int i = 0; i < kMaxPendingQueueSize + kQueueSize; i += kQueueSize) {
-        ASSERT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
-    }
-
-    // Put one event on pending queue
-    events = makeMultipleAccelerometerEvents(kQueueSize);
-    subhal.postEvents(events, false);
-    events = {makeAccelerometerEvent()};
-    subhal.postEvents(events, false);
-
-    // Read out to make room for one event on pending queue to write to FMQ
-    ASSERT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
-
-    // Should be able to read that last event off queue
-    EXPECT_TRUE(readEventsOutOfQueue(1, eventQueue, eventQueueFlag));
-}
-
-// Helper implementations follow
-void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
-                                       const std::vector<SensorInfo>& subHalSensorsList) {
-    EXPECT_EQ(proxySensorsList.size(), subHalSensorsList.size());
-
-    for (size_t i = 0; i < proxySensorsList.size(); i++) {
-        const SensorInfo& proxySensor = proxySensorsList[i];
-        const SensorInfo& subHalSensor = subHalSensorsList[i];
-
-        EXPECT_EQ(proxySensor.type, subHalSensor.type);
-        EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle);
-    }
-}
-
-void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
-                                                     size_t enabledSubHalIndex) {
-    for (const SensorInfo& sensor : sensorsList) {
-        size_t subHalIndex = static_cast<size_t>(sensor.sensorHandle >> 24);
-        if (subHalIndex == enabledSubHalIndex) {
-            // First subhal should have been picked as the direct channel subhal
-            // and so have direct channel enabled on all of its sensors
-            EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
-            EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
-        } else {
-            // All other subhals should have direct channel disabled for all sensors
-            EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
-            EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
-        }
-    }
-}
-
-void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
-                               EventFlag* wakelockQueueFlag) {
-    uint32_t numEventsUInt32 = static_cast<uint32_t>(numEvents);
-    wakelockQueue->write(&numEventsUInt32);
-    wakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
-}
-
-bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
-                          EventFlag* eventQueueFlag) {
-    constexpr int64_t kReadBlockingTimeout = INT64_C(500000000);
-    std::vector<Event> events(numEvents);
-    return eventQueue->readBlocking(events.data(), numEvents,
-                                    static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
-                                    static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
-                                    kReadBlockingTimeout, eventQueueFlag);
-}
-
-std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size) {
-    return std::make_unique<EventMessageQueue>(size, true);
-}
-
-std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size) {
-    return std::make_unique<WakeupMessageQueue>(size, true);
-}
-
-Event makeProximityEvent() {
-    Event event;
-    event.timestamp = 0xFF00FF00;
-    // This is the sensorhandle of proximity, which is wakeup type
-    event.sensorHandle = 0x00000008;
-    event.sensorType = SensorType::PROXIMITY;
-    event.u = EventPayload();
-    return event;
-}
-
-Event makeAccelerometerEvent() {
-    Event event;
-    event.timestamp = 0xFF00FF00;
-    // This is the sensorhandle of proximity, which is wakeup type
-    event.sensorHandle = 0x00000001;
-    event.sensorType = SensorType::ACCELEROMETER;
-    event.u = EventPayload();
-    return event;
-}
-
-std::vector<Event> makeMultipleProximityEvents(size_t numEvents) {
-    std::vector<Event> events;
-    for (size_t i = 0; i < numEvents; i++) {
-        events.push_back(makeProximityEvent());
-    }
-    return events;
-}
-
-std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents) {
-    std::vector<Event> events;
-    for (size_t i = 0; i < numEvents; i++) {
-        events.push_back(makeAccelerometerEvent());
-    }
-    return events;
-}
-
-void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
-                                                  std::vector<SensorInfo>& sensors,
-                                                  std::vector<int32_t>& sensorHandles) {
-    for (int32_t sensorHandle = start; sensorHandle < start + static_cast<int32_t>(size);
-         sensorHandle++) {
-        SensorInfo sensor;
-        // Just set the sensorHandle field to the correct value so as to not have
-        // to compare every field
-        sensor.sensorHandle = sensorHandle;
-        sensors.push_back(sensor);
-        sensorHandles.push_back(sensorHandle);
-    }
-}
-
-}  // namespace
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
deleted file mode 100644
index de89a00..0000000
--- a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
+++ /dev/null
@@ -1,349 +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 "Sensor.h"
-
-#include <hardware/sensors.h>
-#include <utils/SystemClock.h>
-
-#include <cmath>
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace subhal {
-namespace implementation {
-
-using ::android::hardware::sensors::V1_0::MetaDataEventType;
-using ::android::hardware::sensors::V1_0::SensorFlagBits;
-using ::android::hardware::sensors::V1_0::SensorStatus;
-
-Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : mIsEnabled(false),
-      mSamplingPeriodNs(0),
-      mLastSampleTimeNs(0),
-      mCallback(callback),
-      mMode(OperationMode::NORMAL) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.vendor = "Vendor String";
-    mSensorInfo.version = 1;
-    constexpr float kDefaultMaxDelayUs = 1000 * 1000;
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = 0;
-    mRunThread = std::thread(startThread, this);
-}
-
-Sensor::~Sensor() {
-    // Ensure that lock is unlocked before calling mRunThread.join() or a
-    // deadlock will occur.
-    {
-        std::unique_lock<std::mutex> lock(mRunMutex);
-        mStopThread = true;
-        mIsEnabled = false;
-        mWaitCV.notify_all();
-    }
-    mRunThread.join();
-}
-
-const SensorInfo& Sensor::getSensorInfo() const {
-    return mSensorInfo;
-}
-
-void Sensor::batch(int32_t samplingPeriodNs) {
-    samplingPeriodNs =
-            std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000);
-
-    if (mSamplingPeriodNs != samplingPeriodNs) {
-        mSamplingPeriodNs = samplingPeriodNs;
-        // Wake up the 'run' thread to check if a new event should be generated now
-        mWaitCV.notify_all();
-    }
-}
-
-void Sensor::activate(bool enable) {
-    if (mIsEnabled != enable) {
-        std::unique_lock<std::mutex> lock(mRunMutex);
-        mIsEnabled = enable;
-        mWaitCV.notify_all();
-    }
-}
-
-Result Sensor::flush() {
-    // Only generate a flush complete event if the sensor is enabled and if the sensor is not a
-    // one-shot sensor.
-    if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) {
-        return Result::BAD_VALUE;
-    }
-
-    // Note: If a sensor supports batching, write all of the currently batched events for the sensor
-    // to the Event FMQ prior to writing the flush complete event.
-    Event ev;
-    ev.sensorHandle = mSensorInfo.sensorHandle;
-    ev.sensorType = SensorType::META_DATA;
-    ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
-    std::vector<Event> evs{ev};
-    mCallback->postEvents(evs, isWakeUpSensor());
-
-    return Result::OK;
-}
-
-void Sensor::startThread(Sensor* sensor) {
-    sensor->run();
-}
-
-void Sensor::run() {
-    std::unique_lock<std::mutex> runLock(mRunMutex);
-    constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
-
-    while (!mStopThread) {
-        if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
-            mWaitCV.wait(runLock, [&] {
-                return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
-            });
-        } else {
-            timespec curTime;
-            clock_gettime(CLOCK_REALTIME, &curTime);
-            int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
-            int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
-
-            if (now >= nextSampleTime) {
-                mLastSampleTimeNs = now;
-                nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
-                mCallback->postEvents(readEvents(), isWakeUpSensor());
-            }
-
-            mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
-        }
-    }
-}
-
-bool Sensor::isWakeUpSensor() {
-    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
-}
-
-std::vector<Event> Sensor::readEvents() {
-    std::vector<Event> events;
-    Event event;
-    event.sensorHandle = mSensorInfo.sensorHandle;
-    event.sensorType = mSensorInfo.type;
-    event.timestamp = ::android::elapsedRealtimeNano();
-    event.u.vec3.x = 0;
-    event.u.vec3.y = 0;
-    event.u.vec3.z = 0;
-    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
-    events.push_back(event);
-    return events;
-}
-
-void Sensor::setOperationMode(OperationMode mode) {
-    if (mMode != mode) {
-        std::unique_lock<std::mutex> lock(mRunMutex);
-        mMode = mode;
-        mWaitCV.notify_all();
-    }
-}
-
-bool Sensor::supportsDataInjection() const {
-    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
-}
-
-Result Sensor::injectEvent(const Event& event) {
-    Result result = Result::OK;
-    if (event.sensorType == SensorType::ADDITIONAL_INFO) {
-        // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
-        // environment data into the device.
-    } else if (!supportsDataInjection()) {
-        result = Result::INVALID_OPERATION;
-    } else if (mMode == OperationMode::DATA_INJECTION) {
-        mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
-    } else {
-        result = Result::BAD_VALUE;
-    }
-    return result;
-}
-
-OnChangeSensor::OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : Sensor(sensorHandle, callback), mPreviousEventSet(false) {
-    mSensorInfo.flags |= SensorFlagBits::ON_CHANGE_MODE;
-}
-
-void OnChangeSensor::activate(bool enable) {
-    Sensor::activate(enable);
-    if (!enable) {
-        mPreviousEventSet = false;
-    }
-}
-
-std::vector<Event> OnChangeSensor::readEvents() {
-    std::vector<Event> events = Sensor::readEvents();
-    std::vector<Event> outputEvents;
-
-    for (auto iter = events.begin(); iter != events.end(); ++iter) {
-        Event ev = *iter;
-        if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) {
-            outputEvents.push_back(ev);
-            mPreviousEvent = ev;
-            mPreviousEventSet = true;
-        }
-    }
-    return outputEvents;
-}
-
-ContinuousSensor::ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : Sensor(sensorHandle, callback) {
-    mSensorInfo.flags |= SensorFlagBits::CONTINUOUS_MODE;
-}
-
-AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : ContinuousSensor(sensorHandle, callback) {
-    mSensorInfo.name = "Accel Sensor";
-    mSensorInfo.type = SensorType::ACCELEROMETER;
-    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_ACCELEROMETER;
-    mSensorInfo.maxRange = 78.4f;  // +/- 8g
-    mSensorInfo.resolution = 1.52e-5;
-    mSensorInfo.power = 0.001f;        // mA
-    mSensorInfo.minDelay = 20 * 1000;  // microseconds
-    mSensorInfo.flags |= SensorFlagBits::DATA_INJECTION;
-}
-
-std::vector<Event> AccelSensor::readEvents() {
-    std::vector<Event> events;
-    Event event;
-    event.sensorHandle = mSensorInfo.sensorHandle;
-    event.sensorType = mSensorInfo.type;
-    event.timestamp = ::android::elapsedRealtimeNano();
-    event.u.vec3.x = 0;
-    event.u.vec3.y = 0;
-    event.u.vec3.z = -9.815;
-    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
-    events.push_back(event);
-    return events;
-}
-
-PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : ContinuousSensor(sensorHandle, callback) {
-    mSensorInfo.name = "Pressure Sensor";
-    mSensorInfo.type = SensorType::PRESSURE;
-    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PRESSURE;
-    mSensorInfo.maxRange = 1100.0f;     // hPa
-    mSensorInfo.resolution = 0.005f;    // hPa
-    mSensorInfo.power = 0.001f;         // mA
-    mSensorInfo.minDelay = 100 * 1000;  // microseconds
-}
-
-MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : ContinuousSensor(sensorHandle, callback) {
-    mSensorInfo.name = "Magnetic Field Sensor";
-    mSensorInfo.type = SensorType::MAGNETIC_FIELD;
-    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_MAGNETIC_FIELD;
-    mSensorInfo.maxRange = 1300.0f;
-    mSensorInfo.resolution = 0.01f;
-    mSensorInfo.power = 0.001f;        // mA
-    mSensorInfo.minDelay = 20 * 1000;  // microseconds
-}
-
-LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : OnChangeSensor(sensorHandle, callback) {
-    mSensorInfo.name = "Light Sensor";
-    mSensorInfo.type = SensorType::LIGHT;
-    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_LIGHT;
-    mSensorInfo.maxRange = 43000.0f;
-    mSensorInfo.resolution = 10.0f;
-    mSensorInfo.power = 0.001f;         // mA
-    mSensorInfo.minDelay = 200 * 1000;  // microseconds
-}
-
-ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : OnChangeSensor(sensorHandle, callback) {
-    mSensorInfo.name = "Proximity Sensor";
-    mSensorInfo.type = SensorType::PROXIMITY;
-    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PROXIMITY;
-    mSensorInfo.maxRange = 5.0f;
-    mSensorInfo.resolution = 1.0f;
-    mSensorInfo.power = 0.012f;         // mA
-    mSensorInfo.minDelay = 200 * 1000;  // microseconds
-    mSensorInfo.flags |= SensorFlagBits::WAKE_UP;
-}
-
-GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : ContinuousSensor(sensorHandle, callback) {
-    mSensorInfo.name = "Gyro Sensor";
-    mSensorInfo.type = SensorType::GYROSCOPE;
-    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_GYROSCOPE;
-    mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
-    mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
-    mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 2.5f * 1000;  // microseconds
-}
-
-std::vector<Event> GyroSensor::readEvents() {
-    std::vector<Event> events;
-    Event event;
-    event.sensorHandle = mSensorInfo.sensorHandle;
-    event.sensorType = mSensorInfo.type;
-    event.timestamp = ::android::elapsedRealtimeNano();
-    event.u.vec3.x = 0;
-    event.u.vec3.y = 0;
-    event.u.vec3.z = 0;
-    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
-    events.push_back(event);
-    return events;
-}
-
-AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : OnChangeSensor(sensorHandle, callback) {
-    mSensorInfo.name = "Ambient Temp Sensor";
-    mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
-    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
-    mSensorInfo.maxRange = 80.0f;
-    mSensorInfo.resolution = 0.01f;
-    mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 40 * 1000;  // microseconds
-}
-
-DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : ContinuousSensor(sensorHandle, callback) {
-    mSensorInfo.name = "Device Temp Sensor";
-    mSensorInfo.type = SensorType::TEMPERATURE;
-    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE;
-    mSensorInfo.maxRange = 80.0f;
-    mSensorInfo.resolution = 0.01f;
-    mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 40 * 1000;  // microseconds
-}
-
-RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
-                                               ISensorsEventCallback* callback)
-    : OnChangeSensor(sensorHandle, callback) {
-    mSensorInfo.name = "Relative Humidity Sensor";
-    mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
-    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
-    mSensorInfo.maxRange = 100.0f;
-    mSensorInfo.resolution = 0.1f;
-    mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 40 * 1000;  // microseconds
-}
-
-}  // namespace implementation
-}  // namespace subhal
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
deleted file mode 100644
index 60f5d3d..0000000
--- a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
+++ /dev/null
@@ -1,157 +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.
- */
-
-#pragma once
-
-#include <android/hardware/sensors/1.0/types.h>
-
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-#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 subhal {
-namespace implementation {
-
-class ISensorsEventCallback {
-  public:
-    virtual ~ISensorsEventCallback(){};
-    virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
-};
-
-class Sensor {
-  public:
-    Sensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-    virtual ~Sensor();
-
-    const SensorInfo& getSensorInfo() const;
-    void batch(int32_t samplingPeriodNs);
-    virtual void activate(bool enable);
-    Result flush();
-
-    void setOperationMode(OperationMode mode);
-    bool supportsDataInjection() const;
-    Result injectEvent(const Event& event);
-
-  protected:
-    void run();
-    virtual std::vector<Event> readEvents();
-    static void startThread(Sensor* sensor);
-
-    bool isWakeUpSensor();
-
-    bool mIsEnabled;
-    int64_t mSamplingPeriodNs;
-    int64_t mLastSampleTimeNs;
-    SensorInfo mSensorInfo;
-
-    std::atomic_bool mStopThread;
-    std::condition_variable mWaitCV;
-    std::mutex mRunMutex;
-    std::thread mRunThread;
-
-    ISensorsEventCallback* mCallback;
-
-    OperationMode mMode;
-};
-
-class OnChangeSensor : public Sensor {
-  public:
-    OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-
-    virtual void activate(bool enable) override;
-
-  protected:
-    virtual std::vector<Event> readEvents() override;
-
-  protected:
-    Event mPreviousEvent;
-    bool mPreviousEventSet;
-};
-
-class ContinuousSensor : public Sensor {
-  public:
-    ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class AccelSensor : public ContinuousSensor {
-  public:
-    AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-
-  protected:
-    std::vector<Event> readEvents() override;
-};
-
-class GyroSensor : public ContinuousSensor {
-  public:
-    GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-
-  protected:
-    std::vector<Event> readEvents() override;
-};
-
-class DeviceTempSensor : public ContinuousSensor {
-  public:
-    DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class PressureSensor : public ContinuousSensor {
-  public:
-    PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class MagnetometerSensor : public ContinuousSensor {
-  public:
-    MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class AmbientTempSensor : public OnChangeSensor {
-  public:
-    AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class LightSensor : public OnChangeSensor {
-  public:
-    LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class ProximitySensor : public OnChangeSensor {
-  public:
-    ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-class RelativeHumiditySensor : public OnChangeSensor {
-  public:
-    RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
-}  // namespace implementation
-}  // namespace subhal
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
deleted file mode 100644
index ff5ff38..0000000
--- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
+++ /dev/null
@@ -1,240 +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 "SensorsSubHal.h"
-
-#include <android/hardware/sensors/2.0/types.h>
-#include <log/log.h>
-
-ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) {
-#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
-    static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal;
-#elif defined SUPPORT_CONTINUOUS_SENSORS
-    static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal
-            subHal;
-#elif defined SUPPORT_ON_CHANGE_SENSORS
-    static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal;
-#else
-    static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal;
-#endif  // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
-    *version = SUB_HAL_2_0_VERSION;
-    return &subHal;
-}
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace subhal {
-namespace implementation {
-
-using ::android::hardware::Void;
-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;
-using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
-
-SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {}
-
-// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
-Return<void> SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
-    std::vector<SensorInfo> sensors;
-    for (const auto& sensor : mSensors) {
-        sensors.push_back(sensor.second->getSensorInfo());
-    }
-
-    _hidl_cb(sensors);
-    return Void();
-}
-
-Return<Result> SensorsSubHal::setOperationMode(OperationMode mode) {
-    for (auto sensor : mSensors) {
-        sensor.second->setOperationMode(mode);
-    }
-    mCurrentOperationMode = mode;
-    return Result::OK;
-}
-
-Return<Result> SensorsSubHal::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> SensorsSubHal::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> SensorsSubHal::flush(int32_t sensorHandle) {
-    auto sensor = mSensors.find(sensorHandle);
-    if (sensor != mSensors.end()) {
-        return sensor->second->flush();
-    }
-    return Result::BAD_VALUE;
-}
-
-Return<Result> SensorsSubHal::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> SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */,
-                                                  registerDirectChannel_cb _hidl_cb) {
-    _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
-    return Return<void>();
-}
-
-Return<Result> SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) {
-    return Result::INVALID_OPERATION;
-}
-
-Return<void> SensorsSubHal::configDirectReport(int32_t /* sensorHandle */,
-                                               int32_t /* channelHandle */, RateLevel /* rate */,
-                                               configDirectReport_cb _hidl_cb) {
-    _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
-    return Return<void>();
-}
-
-Return<void> SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
-    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
-        ALOGE("%s: missing fd for writing", __FUNCTION__);
-        return Void();
-    }
-
-    FILE* out = fdopen(dup(fd->data[0]), "w");
-
-    if (args.size() != 0) {
-        fprintf(out,
-                "Note: sub-HAL %s currently does not support args. Input arguments are "
-                "ignored.\n",
-                getName().c_str());
-    }
-
-    std::ostringstream stream;
-    stream << "Available sensors:" << std::endl;
-    for (auto sensor : mSensors) {
-        SensorInfo info = sensor.second->getSensorInfo();
-        stream << "Name: " << info.name << std::endl;
-        stream << "Min delay: " << info.minDelay << std::endl;
-        stream << "Flags: " << info.flags << std::endl;
-    }
-    stream << std::endl;
-
-    fprintf(out, "%s", stream.str().c_str());
-
-    fclose(out);
-    return Return<void>();
-}
-
-Return<Result> SensorsSubHal::initialize(const sp<IHalProxyCallback>& halProxyCallback) {
-    mCallback = halProxyCallback;
-    setOperationMode(OperationMode::NORMAL);
-    return Result::OK;
-}
-
-void SensorsSubHal::postEvents(const std::vector<Event>& events, bool wakeup) {
-    ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup);
-    mCallback->postEvents(events, std::move(wakelock));
-}
-
-ContinuousSensorsSubHal::ContinuousSensorsSubHal() {
-    AddSensor<AccelSensor>();
-    AddSensor<GyroSensor>();
-    AddSensor<MagnetometerSensor>();
-    AddSensor<PressureSensor>();
-    AddSensor<DeviceTempSensor>();
-}
-
-OnChangeSensorsSubHal::OnChangeSensorsSubHal() {
-    AddSensor<AmbientTempSensor>();
-    AddSensor<LightSensor>();
-    AddSensor<ProximitySensor>();
-    AddSensor<RelativeHumiditySensor>();
-}
-
-AllSensorsSubHal::AllSensorsSubHal() {
-    AddSensor<AccelSensor>();
-    AddSensor<GyroSensor>();
-    AddSensor<MagnetometerSensor>();
-    AddSensor<PressureSensor>();
-    AddSensor<DeviceTempSensor>();
-    AddSensor<AmbientTempSensor>();
-    AddSensor<LightSensor>();
-    AddSensor<ProximitySensor>();
-    AddSensor<RelativeHumiditySensor>();
-}
-
-Return<Result> SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) {
-    return Result::BAD_VALUE;
-}
-
-Return<void> AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
-    std::vector<SensorInfo> sensors;
-    for (const auto& sensor : mSensors) {
-        SensorInfo sensorInfo = sensor.second->getSensorInfo();
-        sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL;
-        sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT;
-        sensors.push_back(sensorInfo);
-    }
-    _hidl_cb(sensors);
-    return Void();
-}
-
-Return<void> DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
-    std::vector<SensorInfo> sensors;
-    for (const auto& sensor : mSensors) {
-        SensorInfo sensorInfo = sensor.second->getSensorInfo();
-        sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
-        sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_REPORT);
-        sensors.push_back(sensorInfo);
-    }
-    _hidl_cb(sensors);
-    return Void();
-}
-
-void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors(
-        const std::vector<SensorInfo>& sensorsAdded) {
-    mCallback->onDynamicSensorsConnected(sensorsAdded);
-}
-
-void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors(
-        const std::vector<int32_t>& sensorHandlesRemoved) {
-    mCallback->onDynamicSensorsDisconnected(sensorHandlesRemoved);
-}
-
-}  // namespace implementation
-}  // namespace subhal
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
deleted file mode 100644
index c1e3647..0000000
--- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
+++ /dev/null
@@ -1,165 +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.
- */
-
-#pragma once
-
-#include "SubHal.h"
-
-#include "Sensor.h"
-
-#include <vector>
-
-namespace android {
-namespace hardware {
-namespace sensors {
-namespace V2_0 {
-namespace subhal {
-namespace implementation {
-
-using ::android::hardware::sensors::V1_0::OperationMode;
-using ::android::hardware::sensors::V1_0::Result;
-using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback;
-
-/**
- * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0.
- * See the README file for more details on how this class can be used for testing.
- */
-class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback {
-    using Event = ::android::hardware::sensors::V1_0::Event;
-    using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
-    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
-
-  public:
-    SensorsSubHal();
-
-    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
-    virtual Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
-
-    virtual Return<Result> setOperationMode(OperationMode mode) override;
-
-    OperationMode getOperationMode() const { return mCurrentOperationMode; }
-
-    Return<Result> activate(int32_t sensorHandle, bool enabled) 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;
-
-    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
-
-    // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow.
-    const std::string getName() override {
-#ifdef SUB_HAL_NAME
-        return SUB_HAL_NAME;
-#else   // SUB_HAL_NAME
-        return "FakeSubHal";
-#endif  // SUB_HAL_NAME
-    }
-
-    Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) override;
-
-    // Method from ISensorsEventCallback.
-    void postEvents(const std::vector<Event>& events, bool wakeup) override;
-
-  protected:
-    template <class SensorType>
-    void AddSensor() {
-        std::shared_ptr<SensorType> sensor =
-                std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
-        mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
-    }
-
-    /**
-     * A map of the available sensors
-     */
-    std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
-
-    /**
-     * Callback used to communicate to the HalProxy when dynamic sensors are connected /
-     * disconnected, sensor events need to be sent to the framework, and when a wakelock should be
-     * acquired.
-     */
-    sp<IHalProxyCallback> mCallback;
-
-  private:
-    /**
-     * The current operation mode of the multihal framework. Ensures that all subhals are set to
-     * the same operation mode.
-     */
-    OperationMode mCurrentOperationMode = OperationMode::NORMAL;
-
-    /**
-     * The next available sensor handle
-     */
-    int32_t mNextHandle;
-};
-
-// SubHal that has continuous sensors for testing purposes.
-class ContinuousSensorsSubHal : public SensorsSubHal {
-  public:
-    ContinuousSensorsSubHal();
-};
-
-// SubHal that has on-change sensors for testing purposes.
-class OnChangeSensorsSubHal : public SensorsSubHal {
-  public:
-    OnChangeSensorsSubHal();
-};
-
-// SubHal that has both continuous and on-change sensors for testing purposes.
-class AllSensorsSubHal : public SensorsSubHal {
-  public:
-    AllSensorsSubHal();
-};
-
-class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal {
-  public:
-    Return<Result> setOperationMode(OperationMode mode) override;
-};
-
-class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
-  public:
-    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
-};
-
-class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
-  public:
-    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
-};
-
-class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal {
-  public:
-    void addDynamicSensors(const std::vector<SensorInfo>& sensorsAdded);
-    void removeDynamicSensors(const std::vector<int32_t>& sensorHandlesAdded);
-};
-
-}  // namespace implementation
-}  // namespace subhal
-}  // namespace V2_0
-}  // namespace sensors
-}  // namespace hardware
-}  // namespace android
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
index 4765fa2..c0803c7 100644
--- a/sensors/2.0/vts/functional/Android.bp
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -19,19 +19,22 @@
     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",
-        "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_0TargetTest-lib",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
     ],
 }
-
diff --git a/sensors/2.0/vts/functional/OWNERS b/sensors/2.0/vts/functional/OWNERS
index 759d87b..892da15 100644
--- a/sensors/2.0/vts/functional/OWNERS
+++ b/sensors/2.0/vts/functional/OWNERS
@@ -1,6 +1,7 @@
 # Sensors team
+arthuri@google.com
 bduddie@google.com
-bstack@google.com
+stange@google.com
 
 # VTS team
 trong@google.com
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
deleted file mode 100644
index 2071c5a..0000000
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
+++ /dev/null
@@ -1,165 +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 "SensorsHidlEnvironmentV2_0.h"
-
-#include <android/hardware/sensors/2.0/types.h>
-#include <log/log.h>
-
-#include <algorithm>
-#include <vector>
-
-using ::android::hardware::EventFlag;
-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_0::ISensors;
-using ::android::hardware::sensors::V2_0::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 */) {
-    ALOGE("Sensors HAL died (likely crashed) during test");
-    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 succeed = false;
-    do {
-        mSensors = 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) {
-            break;
-        }
-
-        EventFlag::deleteEventFlag(&mEventQueueFlag);
-        EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
-        if (mEventQueueFlag == nullptr) {
-            break;
-        }
-
-        mSensors->initialize(*mEventQueue->getDesc(), *mWakeLockQueue->getDesc(),
-                             new SensorsCallback());
-
-        std::vector<SensorInfo> sensorList;
-        if (!mSensors->getSensorsList([&](const hidl_vec<SensorInfo>& list) { sensorList = list; })
-                 .isOk()) {
-            break;
-        }
-
-        // stop each sensor individually
-        bool ok = true;
-        for (const auto& i : sensorList) {
-            if (!mSensors->activate(i.sensorHandle, false).isOk()) {
-                ok = false;
-                break;
-            }
-        }
-        if (!ok) {
-            break;
-        }
-
-        // mark it done
-        succeed = true;
-    } while (0);
-
-    if (!succeed) {
-        mSensors = nullptr;
-    }
-
-    return succeed;
-}
-
-void SensorsHidlEnvironmentV2_0::HidlTearDown() {
-    mStopThread = true;
-
-    if (mEventQueueFlag != nullptr) {
-        // Wake up the event queue so the poll thread can exit
-        mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::READ_AND_PROCESS));
-        if (mPollThread.joinable()) {
-            mPollThread.join();
-        }
-
-        EventFlag::deleteEventFlag(&mEventQueueFlag);
-    }
-}
-
-void SensorsHidlEnvironmentV2_0::startPollingThread() {
-    mStopThread = false;
-    mPollThread = std::thread(pollingThread, this);
-    mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
-}
-
-void SensorsHidlEnvironmentV2_0::readEvents() {
-    size_t availableEvents = mEventQueue->availableToRead();
-
-    if (availableEvents == 0) {
-        uint32_t eventFlagState = 0;
-
-        mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS), &eventFlagState);
-        availableEvents = mEventQueue->availableToRead();
-    }
-
-    size_t eventsToRead = std::min(availableEvents, mEventBuffer.size());
-    if (eventsToRead > 0) {
-        if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) {
-            mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::EVENTS_READ));
-            for (size_t i = 0; i < eventsToRead; i++) {
-                addEvent(mEventBuffer[i]);
-            }
-        }
-    }
-}
-
-void SensorsHidlEnvironmentV2_0::pollingThread(SensorsHidlEnvironmentV2_0* env) {
-    ALOGD("polling thread start");
-
-    while (!env->mStopThread.load()) {
-        env->readEvents();
-    }
-
-    ALOGD("polling thread end");
-}
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
deleted file mode 100644
index 819cdd4..0000000
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
+++ /dev/null
@@ -1,127 +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_SENSORS_HIDL_ENVIRONMENT_V2_0_H
-#define ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
-
-#include "sensors-vts-utils/SensorsHidlEnvironmentBase.h"
-
-#include <android/hardware/sensors/1.0/types.h>
-#include <android/hardware/sensors/2.0/ISensors.h>
-#include <fmq/MessageQueue.h>
-#include <utils/StrongPointer.h>
-
-#include <array>
-#include <atomic>
-#include <memory>
-
-using ::android::sp;
-using ::android::hardware::MessageQueue;
-
-class SensorsHidlTest;
-
-class SensorsHalDeathRecipient : public ::android::hardware::hidl_death_recipient {
-    virtual void serviceDied(
-            uint64_t cookie,
-            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;
-    virtual void HidlTearDown() override;
-
-   protected:
-    friend SensorsHidlTest;
-    SensorsHidlEnvironmentV2_0(const std::string& service_name)
-        : SensorsHidlEnvironmentBase(service_name), mEventQueueFlag(nullptr) {}
-
-    /**
-     * Resets the HAL with new FMQs and a new Event Flag
-     *
-     * @return bool true if successful, false otherwise
-     */
-    bool resetHal() override;
-
-    /**
-     * Starts the polling thread that reads sensor events from the Event FMQ
-     */
-    void startPollingThread() override;
-
-    /**
-     * Thread responsible for calling functions to read Event FMQ
-     *
-     * @param env SensorEnvironment to being polling for events on
-     */
-    static void pollingThread(SensorsHidlEnvironmentV2_0* env);
-
-    /**
-     * Reads and saves sensor events from the Event FMQ
-     */
-    void readEvents();
-
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV2_0);
-
-    /**
-     * Pointer to the Sensors HAL Interface that allows the test to call HAL functions.
-     */
-    sp<android::hardware::sensors::V2_0::ISensors> mSensors;
-
-    /**
-     * Monitors the HAL for crashes, triggering test failure if seen
-     */
-    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.
-     */
-    std::unique_ptr<WakeLockQueue> mWakeLockQueue;
-
-    /**
-     * The Event Queue Flag notifies the test framework when sensor events have been written to the
-     * Event FMQ by the Sensors HAL.
-     */
-    ::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;
-};
-
-#endif  // ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index e46f034..a0d436f 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -14,1074 +14,205 @@
  * limitations under the License.
  */
 
-#include "SensorsHidlEnvironmentV2_0.h"
-#include "sensors-vts-utils/SensorsHidlTestBase.h"
-#include "sensors-vts-utils/SensorsTestSharedMemory.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) {
-    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 type string non-empty only for private sensor types.
-            if (s.type >= SensorType::DEVICE_PRIVATE_BASE) {
-                EXPECT_FALSE(s.typeAsString.empty());
-            } else if (!s.typeAsString.empty()) {
-                // Test type string matches framework string if specified for non-private types.
-                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)));
-        }
-    });
-}
-
-// 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));
-}
+#include "VtsHalSensorsV2_XTargetTest.h"
 
 // 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);
+    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(SensorType::ACCELEROMETER, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), sAccelNormChecker);
+    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(SensorType::ACCELEROMETER, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), sAccelNormChecker);
+    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(SensorType::GYROSCOPE, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), sGyroNormChecker);
+    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(SensorType::GYROSCOPE, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), sGyroNormChecker);
+    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(SensorType::GYROSCOPE, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), sGyroNormChecker);
+    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(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), NullChecker());
+    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(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), NullChecker());
+    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(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), NullChecker());
+    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(SensorType::ACCELEROMETER);
-    testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/);
+    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(SensorType::GYROSCOPE);
-    testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/);
+    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(SensorType::MAGNETIC_FIELD);
-    testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
+    testSamplingRateHotSwitchOperation(SensorTypeVersion::MAGNETIC_FIELD);
+    testSamplingRateHotSwitchOperation(SensorTypeVersion::MAGNETIC_FIELD, false /*fastToSlow*/);
 }
 
 // Test if sensor hal can do accelerometer batching properly
 TEST_P(SensorsHidlTest, AccelerometerBatchingOperation) {
-    testBatchingOperation(SensorType::ACCELEROMETER);
+    testBatchingOperation(SensorTypeVersion::ACCELEROMETER);
 }
 
 // Test if sensor hal can do gyroscope batching properly
 TEST_P(SensorsHidlTest, GyroscopeBatchingOperation) {
-    testBatchingOperation(SensorType::GYROSCOPE);
+    testBatchingOperation(SensorTypeVersion::GYROSCOPE);
 }
 
 // Test if sensor hal can do magnetometer batching properly
 TEST_P(SensorsHidlTest, MagnetometerBatchingOperation) {
-    testBatchingOperation(SensorType::MAGNETIC_FIELD);
+    testBatchingOperation(SensorTypeVersion::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);
+    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(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
-                              sAccelNormChecker);
+    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(SensorType::ACCELEROMETER, SharedMemType::ASHMEM,
-                              RateLevel::VERY_FAST, sAccelNormChecker);
+    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(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              sGyroNormChecker);
+    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(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
-                              sGyroNormChecker);
+    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(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
-                              sGyroNormChecker);
+    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(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              NullChecker());
+    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(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
-                              NullChecker());
+    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(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM,
-                              RateLevel::VERY_FAST, NullChecker());
+    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(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              sAccelNormChecker);
+    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(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
-                              sAccelNormChecker);
+    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(SensorType::ACCELEROMETER, SharedMemType::GRALLOC,
-                              RateLevel::VERY_FAST, sAccelNormChecker);
+    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(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              sGyroNormChecker);
+    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(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
-                              sGyroNormChecker);
+    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(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
-                              sGyroNormChecker);
+    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(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              NullChecker());
+    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(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
-                              NullChecker());
+    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(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);
-
-    getEnvironment()->unregisterCallback();
-
-    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;
+    testDirectReportOperation(SensorTypeVersion::MAGNETIC_FIELD, SharedMemType::GRALLOC,
+                              RateLevel::VERY_FAST, NullChecker<EventType>());
 }
 
 TEST_P(SensorsHidlTest, ConfigureDirectChannelWithInvalidHandle) {
-    SensorInfo sensor;
+    SensorInfoType sensor;
     SharedMemType memType;
     RateLevel rate;
     if (!getDirectChannelSensor(&sensor, &memType, &rate)) {
@@ -1098,7 +229,7 @@
     constexpr size_t kNumEvents = 1;
     constexpr size_t kMemSize = kNumEvents * kEventSize;
 
-    SensorInfo sensor;
+    SensorInfoType sensor;
     SharedMemType memType;
     RateLevel rate;
 
@@ -1106,8 +237,8 @@
         return;
     }
 
-    std::shared_ptr<SensorsTestSharedMemory> mem(
-        SensorsTestSharedMemory::create(memType, kMemSize));
+    std::shared_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem(
+            SensorsTestSharedMemory<SensorTypeVersion, EventType>::create(memType, kMemSize));
     ASSERT_NE(mem, nullptr);
 
     int32_t directChannelHandle = 0;
@@ -1118,8 +249,8 @@
 
     // Configure the channel and expect success
     configDirectReport(
-        sensor.sensorHandle, directChannelHandle, rate,
-        [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
+            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
@@ -1133,15 +264,39 @@
 
     // 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); });
+            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;
 }
 
+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];
+            EXPECT_FALSE(s.type == ::android::hardware::sensors::V2_1::SensorType::HINGE_ANGLE);
+        }
+    });
+}
+
+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);
+}
+
 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..9ba3248
--- /dev/null
+++ b/sensors/2.1/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.sensors@2.1",
+    root: "android.hardware",
+    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/multihal/Android.bp b/sensors/2.1/multihal/Android.bp
new file mode 100644
index 0000000..6a7cac9
--- /dev/null
+++ b/sensors/2.1/multihal/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.sensors@2.1-service.multihal",
+    defaults: [
+        "hidl_defaults",
+    ],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "service.cpp",
+    ],
+    init_rc: ["android.hardware.sensors@2.1-service-multihal.rc"],
+    vintf_fragments: ["android.hardware.sensors@2.1-multihal.xml"],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.0-ScopedWakelock",
+        "android.hardware.sensors@2.1",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.X-multihal",
+    ],
+}
diff --git a/sensors/2.1/multihal/OWNERS b/sensors/2.1/multihal/OWNERS
new file mode 100644
index 0000000..e955670
--- /dev/null
+++ b/sensors/2.1/multihal/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
\ No newline at end of file
diff --git a/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml b/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.xml
new file mode 100644
index 0000000..18bd3ae
--- /dev/null
+++ b/sensors/2.1/multihal/android.hardware.sensors@2.1-multihal.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/multihal/android.hardware.sensors@2.1-service-multihal.rc b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc
new file mode 100644
index 0000000..fc99ee7
--- /dev/null
+++ b/sensors/2.1/multihal/android.hardware.sensors@2.1-service-multihal.rc
@@ -0,0 +1,7 @@
+service vendor.sensors-hal-2-1-multihal /vendor/bin/hw/android.hardware.sensors@2.1-service.multihal
+    class hal
+    user system
+    group system wakelock context_hub
+    writepid /dev/cpuset/system-background/tasks
+    capabilities BLOCK_SUSPEND
+    rlimit rtprio 10 10
diff --git a/sensors/2.1/multihal/service.cpp b/sensors/2.1/multihal/service.cpp
new file mode 100644
index 0000000..d68d9a3
--- /dev/null
+++ b/sensors/2.1/multihal/service.cpp
@@ -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.
+ */
+
+#include <android/hardware/sensors/2.1/ISensors.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include "HalProxy.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::sensors::V2_1::ISensors;
+using android::hardware::sensors::V2_1::implementation::HalProxyV2_1;
+
+int main(int /* argc */, char** /* argv */) {
+    configureRpcThreadpool(1, true);
+
+    android::sp<ISensors> halProxy = new HalProxyV2_1();
+    if (halProxy->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..920b642
--- /dev/null
+++ b/sensors/2.1/vts/functional/Android.bp
@@ -0,0 +1,42 @@
+//
+// 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.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..2ef8dc6
--- /dev/null
+++ b/sensors/2.1/vts/functional/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?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 class="com.android.tradefed.targetprep.StopServicesSetup"/>
+
+    <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/common/default/2.X/Sensor.cpp b/sensors/common/default/2.X/Sensor.cpp
new file mode 100644
index 0000000..1841dff
--- /dev/null
+++ b/sensors/common/default/2.X/Sensor.cpp
@@ -0,0 +1,376 @@
+/*
+ * 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 "Sensor.h"
+
+#include <utils/SystemClock.h>
+
+#include <cmath>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+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;
+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),
+      mSamplingPeriodNs(0),
+      mLastSampleTimeNs(0),
+      mCallback(callback),
+      mMode(OperationMode::NORMAL) {
+    mRunThread = std::thread(startThread, this);
+}
+
+Sensor::~Sensor() {
+    std::unique_lock<std::mutex> lock(mRunMutex);
+    mStopThread = true;
+    mIsEnabled = false;
+    mWaitCV.notify_all();
+    lock.release();
+    mRunThread.join();
+}
+
+const SensorInfo& Sensor::getSensorInfo() const {
+    return mSensorInfo;
+}
+
+void Sensor::batch(int32_t samplingPeriodNs) {
+    if (samplingPeriodNs < mSensorInfo.minDelay * 1000) {
+        samplingPeriodNs = mSensorInfo.minDelay * 1000;
+    } else if (samplingPeriodNs > mSensorInfo.maxDelay * 1000) {
+        samplingPeriodNs = mSensorInfo.maxDelay * 1000;
+    }
+
+    if (mSamplingPeriodNs != samplingPeriodNs) {
+        mSamplingPeriodNs = samplingPeriodNs;
+        // Wake up the 'run' thread to check if a new event should be generated now
+        mWaitCV.notify_all();
+    }
+}
+
+void Sensor::activate(bool enable) {
+    if (mIsEnabled != enable) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mIsEnabled = enable;
+        mWaitCV.notify_all();
+    }
+}
+
+Result Sensor::flush() {
+    // Only generate a flush complete event if the sensor is enabled and if the sensor is not a
+    // one-shot sensor.
+    if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) {
+        return Result::BAD_VALUE;
+    }
+
+    // Note: If a sensor supports batching, write all of the currently batched events for the sensor
+    // to the Event FMQ prior to writing the flush complete event.
+    Event ev;
+    ev.sensorHandle = mSensorInfo.sensorHandle;
+    ev.sensorType = SensorType::META_DATA;
+    ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
+    std::vector<Event> evs{ev};
+    mCallback->postEvents(evs, isWakeUpSensor());
+
+    return Result::OK;
+}
+
+void Sensor::startThread(Sensor* sensor) {
+    sensor->run();
+}
+
+void Sensor::run() {
+    std::unique_lock<std::mutex> runLock(mRunMutex);
+    constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
+
+    while (!mStopThread) {
+        if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
+            mWaitCV.wait(runLock, [&] {
+                return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
+            });
+        } else {
+            timespec curTime;
+            clock_gettime(CLOCK_REALTIME, &curTime);
+            int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
+            int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+
+            if (now >= nextSampleTime) {
+                mLastSampleTimeNs = now;
+                nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+                mCallback->postEvents(readEvents(), isWakeUpSensor());
+            }
+
+            mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
+        }
+    }
+}
+
+bool Sensor::isWakeUpSensor() {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+}
+
+std::vector<Event> Sensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 0;
+    event.u.vec3.z = 0;
+    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+    events.push_back(event);
+    return events;
+}
+
+void Sensor::setOperationMode(OperationMode mode) {
+    if (mMode != mode) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mMode = mode;
+        mWaitCV.notify_all();
+    }
+}
+
+bool Sensor::supportsDataInjection() const {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
+}
+
+Result Sensor::injectEvent(const Event& event) {
+    Result result = Result::OK;
+    if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+        // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
+        // environment data into the device.
+    } else if (!supportsDataInjection()) {
+        result = Result::INVALID_OPERATION;
+    } else if (mMode == OperationMode::DATA_INJECTION) {
+        mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
+    } else {
+        result = Result::BAD_VALUE;
+    }
+    return result;
+}
+
+OnChangeSensor::OnChangeSensor(ISensorsEventCallback* callback)
+    : Sensor(callback), mPreviousEventSet(false) {}
+
+void OnChangeSensor::activate(bool enable) {
+    Sensor::activate(enable);
+    if (!enable) {
+        mPreviousEventSet = false;
+    }
+}
+
+std::vector<Event> OnChangeSensor::readEvents() {
+    std::vector<Event> events = Sensor::readEvents();
+    std::vector<Event> outputEvents;
+
+    for (auto iter = events.begin(); iter != events.end(); ++iter) {
+        Event ev = *iter;
+        if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) {
+            outputEvents.push_back(ev);
+            mPreviousEvent = ev;
+            mPreviousEventSet = true;
+        }
+    }
+    return outputEvents;
+}
+
+AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Accel Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::ACCELEROMETER;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 78.4f;  // +/- 8g
+    mSensorInfo.resolution = 1.52e-5;
+    mSensorInfo.power = 0.001f;        // mA
+    mSensorInfo.minDelay = 20 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
+};
+
+PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : Sensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Pressure Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    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.minDelay = 100 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = 0;
+};
+
+MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : Sensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Magnetic Field Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::MAGNETIC_FIELD;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 1300.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;        // mA
+    mSensorInfo.minDelay = 20 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = 0;
+};
+
+LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Light Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::LIGHT;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 43000.0f;
+    mSensorInfo.resolution = 10.0f;
+    mSensorInfo.power = 0.001f;         // mA
+    mSensorInfo.minDelay = 200 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
+};
+
+ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Proximity Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::PROXIMITY;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 5.0f;
+    mSensorInfo.resolution = 1.0f;
+    mSensorInfo.power = 0.012f;         // mA
+    mSensorInfo.minDelay = 200 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags =
+            static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP);
+};
+
+GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Gyro Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::GYROSCOPE;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
+    mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 2.5f * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = 0;
+};
+
+AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Ambient Temp Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 80.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
+};
+
+DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Device Temp Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::TEMPERATURE;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 80.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
+}
+
+RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
+                                               ISensorsEventCallback* callback)
+    : OnChangeSensor(callback) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.name = "Relative Humidity Sensor";
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
+    mSensorInfo.typeAsString = "";
+    mSensorInfo.maxRange = 100.0f;
+    mSensorInfo.resolution = 0.1f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
+}
+
+}  // namespace implementation
+}  // namespace V2_X
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/common/default/2.X/Sensor.h b/sensors/common/default/2.X/Sensor.h
new file mode 100644
index 0000000..2f8a143
--- /dev/null
+++ b/sensors/common/default/2.X/Sensor.h
@@ -0,0 +1,152 @@
+/*
+ * 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_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>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_X {
+namespace implementation {
+
+static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000;
+
+class ISensorsEventCallback {
+  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:
+    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();
+
+    const SensorInfo& getSensorInfo() const;
+    void batch(int32_t samplingPeriodNs);
+    virtual void activate(bool enable);
+    Result flush();
+
+    void setOperationMode(OperationMode mode);
+    bool supportsDataInjection() const;
+    Result injectEvent(const Event& event);
+
+  protected:
+    void run();
+    virtual std::vector<Event> readEvents();
+    static void startThread(Sensor* sensor);
+
+    bool isWakeUpSensor();
+
+    bool mIsEnabled;
+    int64_t mSamplingPeriodNs;
+    int64_t mLastSampleTimeNs;
+    SensorInfo mSensorInfo;
+
+    std::atomic_bool mStopThread;
+    std::condition_variable mWaitCV;
+    std::mutex mRunMutex;
+    std::thread mRunThread;
+
+    ISensorsEventCallback* mCallback;
+
+    OperationMode mMode;
+};
+
+class OnChangeSensor : public Sensor {
+  public:
+    OnChangeSensor(ISensorsEventCallback* callback);
+
+    virtual void activate(bool enable) override;
+
+  protected:
+    virtual std::vector<Event> readEvents() override;
+
+  protected:
+    Event mPreviousEvent;
+    bool mPreviousEventSet;
+};
+
+class AccelSensor : public Sensor {
+  public:
+    AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class GyroSensor : public Sensor {
+  public:
+    GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class AmbientTempSensor : public OnChangeSensor {
+  public:
+    AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class DeviceTempSensor : public OnChangeSensor {
+  public:
+    DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class PressureSensor : public Sensor {
+  public:
+    PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class MagnetometerSensor : public Sensor {
+  public:
+    MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class LightSensor : public OnChangeSensor {
+  public:
+    LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class ProximitySensor : public OnChangeSensor {
+  public:
+    ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class RelativeHumiditySensor : public OnChangeSensor {
+  public:
+    RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+}  // namespace implementation
+}  // namespace V2_X
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#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/default/2.X/multihal/Android.bp b/sensors/common/default/2.X/multihal/Android.bp
new file mode 100644
index 0000000..c80c47a
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/Android.bp
@@ -0,0 +1,111 @@
+//
+// 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_defaults {
+    name: "android.hardware.sensors@2.X-multihal-defaults",
+    header_libs: [
+        "android.hardware.sensors@2.X-multihal.header",
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+    ],
+    cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
+}
+
+// Header target for sub-HALs that implement the Multi-HAL 2.0 interface
+cc_library_headers {
+    name: "android.hardware.sensors@2.0-multihal.header",
+    vendor_available: true,
+    export_include_dirs: ["include/V2_0"],
+}
+
+// Header target for sub-HALs that implement the Multi-HAL 2.1 interface
+cc_library_headers {
+    name: "android.hardware.sensors@2.1-multihal.header",
+    vendor_available: true,
+    export_include_dirs: ["include/V2_1"],
+}
+
+// Header target for Multi-HAL so it can reference both 2.0/2.1 headers
+cc_library_headers {
+    name: "android.hardware.sensors@2.X-multihal.header",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+}
+
+cc_library_static {
+    name: "android.hardware.sensors@2.X-multihal",
+    defaults: [
+        "hidl_defaults",
+        "android.hardware.sensors@2.X-multihal-defaults",
+    ],
+    srcs: [
+        "HalProxy.cpp",
+        "HalProxyCallback.cpp",
+    ],
+    vendor_available: true,
+    export_header_lib_headers: [
+        "android.hardware.sensors@2.X-multihal.header",
+    ],
+}
+
+cc_library_shared {
+    name: "android.hardware.sensors@2.0-ScopedWakelock",
+    defaults: [
+        "hidl_defaults",
+        "android.hardware.sensors@2.X-multihal-defaults",
+    ],
+    srcs: [
+        "ScopedWakelock.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+    vendor_available: true,
+    export_header_lib_headers: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+}
+
+cc_test_library {
+    name: "android.hardware.sensors@2.0-ScopedWakelock.testlib",
+    defaults: [
+        "hidl_defaults",
+        "android.hardware.sensors@2.X-multihal-defaults",
+    ],
+    srcs: [
+        "ScopedWakelock.cpp",
+    ],
+    vendor_available: true,
+    header_libs: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+}
diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp
new file mode 100644
index 0000000..75ffc17
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/HalProxy.cpp
@@ -0,0 +1,750 @@
+/*
+ * 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 "HalProxy.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+
+#include <android-base/file.h>
+#include "hardware_legacy/power.h"
+
+#include <dlfcn.h>
+
+#include <cinttypes>
+#include <cmath>
+#include <fstream>
+#include <functional>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::getTimeNow;
+using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs;
+
+typedef V2_0::implementation::ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*);
+typedef V2_1::implementation::ISensorsSubHal*(SensorsHalGetSubHalV2_1Func)(uint32_t*);
+
+static constexpr int32_t kBitsAfterSubHalIndex = 24;
+
+/**
+ * Set the subhal index as first byte of sensor handle and return this modified version.
+ *
+ * @param sensorHandle The sensor handle to modify.
+ * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to.
+ *
+ * @return The modified sensor handle.
+ */
+int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) {
+    return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
+}
+
+/**
+ * Extract the subHalIndex from sensorHandle.
+ *
+ * @param sensorHandle The sensorHandle to extract from.
+ *
+ * @return The subhal index.
+ */
+size_t extractSubHalIndex(int32_t sensorHandle) {
+    return static_cast<size_t>(sensorHandle >> kBitsAfterSubHalIndex);
+}
+
+/**
+ * Convert nanoseconds to milliseconds.
+ *
+ * @param nanos The nanoseconds input.
+ *
+ * @return The milliseconds count.
+ */
+int64_t msFromNs(int64_t nanos) {
+    constexpr int64_t nanosecondsInAMillsecond = 1000000;
+    return nanos / nanosecondsInAMillsecond;
+}
+
+HalProxy::HalProxy() {
+    const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
+    initializeSubHalListFromConfigFile(kMultiHalConfigFile);
+    init();
+}
+
+HalProxy::HalProxy(std::vector<ISensorsSubHalV2_0*>& subHalList) {
+    for (ISensorsSubHalV2_0* subHal : subHalList) {
+        mSubHalList.push_back(std::make_unique<SubHalWrapperV2_0>(subHal));
+    }
+
+    init();
+}
+
+HalProxy::HalProxy(std::vector<ISensorsSubHalV2_0*>& subHalList,
+                   std::vector<ISensorsSubHalV2_1*>& subHalListV2_1) {
+    for (ISensorsSubHalV2_0* subHal : subHalList) {
+        mSubHalList.push_back(std::make_unique<SubHalWrapperV2_0>(subHal));
+    }
+
+    for (ISensorsSubHalV2_1* subHal : subHalListV2_1) {
+        mSubHalList.push_back(std::make_unique<SubHalWrapperV2_1>(subHal));
+    }
+
+    init();
+}
+
+HalProxy::~HalProxy() {
+    stopThreads();
+}
+
+Return<void> HalProxy::getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb) {
+    std::vector<V2_1::SensorInfo> sensors;
+    for (const auto& iter : mSensors) {
+        sensors.push_back(iter.second);
+    }
+    _hidl_cb(sensors);
+    return Void();
+}
+
+Return<void> HalProxy::getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) {
+    std::vector<V1_0::SensorInfo> sensors;
+    for (const auto& iter : mSensors) {
+        sensors.push_back(convertToOldSensorInfo(iter.second));
+    }
+    _hidl_cb(sensors);
+    return Void();
+}
+
+Return<Result> HalProxy::setOperationMode(OperationMode mode) {
+    Result result = Result::OK;
+    size_t subHalIndex;
+    for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+        result = mSubHalList[subHalIndex]->setOperationMode(mode);
+        if (result != Result::OK) {
+            ALOGE("setOperationMode failed for SubHal: %s",
+                  mSubHalList[subHalIndex]->getName().c_str());
+            break;
+        }
+    }
+
+    if (result != Result::OK) {
+        // Reset the subhal operation modes that have been flipped
+        for (size_t i = 0; i < subHalIndex; i++) {
+            mSubHalList[i]->setOperationMode(mCurrentOperationMode);
+        }
+    } else {
+        mCurrentOperationMode = mode;
+    }
+    return result;
+}
+
+Return<Result> HalProxy::activate(int32_t sensorHandle, bool enabled) {
+    if (!isSubHalIndexValid(sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
+    return getSubHalForSensorHandle(sensorHandle)
+            ->activate(clearSubHalIndex(sensorHandle), enabled);
+}
+
+Return<Result> HalProxy::initialize_2_1(
+        const ::android::hardware::MQDescriptorSync<V2_1::Event>& eventQueueDescriptor,
+        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+        const sp<V2_1::ISensorsCallback>& sensorsCallback) {
+    sp<ISensorsCallbackWrapperBase> dynamicCallback =
+            new ISensorsCallbackWrapperV2_1(sensorsCallback);
+
+    // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
+    auto eventQueue =
+            std::make_unique<EventMessageQueueV2_1>(eventQueueDescriptor, true /* resetPointers */);
+    std::unique_ptr<EventMessageQueueWrapperBase> queue =
+            std::make_unique<EventMessageQueueWrapperV2_1>(eventQueue);
+
+    return initializeCommon(queue, wakeLockDescriptor, dynamicCallback);
+}
+
+Return<Result> HalProxy::initialize(
+        const ::android::hardware::MQDescriptorSync<V1_0::Event>& eventQueueDescriptor,
+        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+        const sp<V2_0::ISensorsCallback>& sensorsCallback) {
+    sp<ISensorsCallbackWrapperBase> dynamicCallback =
+            new ISensorsCallbackWrapperV2_0(sensorsCallback);
+
+    // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
+    auto eventQueue =
+            std::make_unique<EventMessageQueueV2_0>(eventQueueDescriptor, true /* resetPointers */);
+    std::unique_ptr<EventMessageQueueWrapperBase> queue =
+            std::make_unique<EventMessageQueueWrapperV1_0>(eventQueue);
+
+    return initializeCommon(queue, wakeLockDescriptor, dynamicCallback);
+}
+
+Return<Result> HalProxy::initializeCommon(
+        std::unique_ptr<EventMessageQueueWrapperBase>& eventQueue,
+        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+        const sp<ISensorsCallbackWrapperBase>& sensorsCallback) {
+    Result result = Result::OK;
+
+    stopThreads();
+    resetSharedWakelock();
+
+    // So that the pending write events queue can be cleared safely and when we start threads
+    // again we do not get new events until after initialize resets the subhals.
+    disableAllSensors();
+
+    // Clears the queue if any events were pending write before.
+    mPendingWriteEventsQueue = std::queue<std::pair<std::vector<V2_1::Event>, size_t>>();
+    mSizePendingWriteEventsQueue = 0;
+
+    // Clears previously connected dynamic sensors
+    mDynamicSensors.clear();
+
+    mDynamicSensorsCallback = sensorsCallback;
+
+    // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
+    mEventQueue = std::move(eventQueue);
+
+    // 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 (mEventQueueFlag != nullptr) {
+        EventFlag::deleteEventFlag(&mEventQueueFlag);
+    }
+    if (mWakelockQueueFlag != nullptr) {
+        EventFlag::deleteEventFlag(&mWakelockQueueFlag);
+    }
+    if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
+        result = Result::BAD_VALUE;
+    }
+    if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) {
+        result = Result::BAD_VALUE;
+    }
+    if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
+        result = Result::BAD_VALUE;
+    }
+
+    mThreadsRun.store(true);
+
+    mPendingWritesThread = std::thread(startPendingWritesThread, this);
+    mWakelockThread = std::thread(startWakelockThread, this);
+
+    for (size_t i = 0; i < mSubHalList.size(); i++) {
+        Result currRes = mSubHalList[i]->initialize(this, this, i);
+        if (currRes != Result::OK) {
+            result = currRes;
+            ALOGE("Subhal '%s' failed to initialize.", mSubHalList[i]->getName().c_str());
+            break;
+        }
+    }
+
+    mCurrentOperationMode = OperationMode::NORMAL;
+
+    return result;
+}
+
+Return<Result> HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                               int64_t maxReportLatencyNs) {
+    if (!isSubHalIndexValid(sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
+    return getSubHalForSensorHandle(sensorHandle)
+            ->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs);
+}
+
+Return<Result> HalProxy::flush(int32_t sensorHandle) {
+    if (!isSubHalIndexValid(sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
+    return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle));
+}
+
+Return<Result> HalProxy::injectSensorData_2_1(const V2_1::Event& event) {
+    return injectSensorData(convertToOldEvent(event));
+}
+
+Return<Result> HalProxy::injectSensorData(const V1_0::Event& event) {
+    Result result = Result::OK;
+    if (mCurrentOperationMode == OperationMode::NORMAL &&
+        event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) {
+        ALOGE("An event with type != ADDITIONAL_INFO passed to injectSensorData while operation"
+              " mode was NORMAL.");
+        result = Result::BAD_VALUE;
+    }
+    if (result == Result::OK) {
+        V1_0::Event subHalEvent = event;
+        if (!isSubHalIndexValid(event.sensorHandle)) {
+            return Result::BAD_VALUE;
+        }
+        subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle);
+        result = getSubHalForSensorHandle(event.sensorHandle)
+                         ->injectSensorData(convertToNewEvent(subHalEvent));
+    }
+    return result;
+}
+
+Return<void> HalProxy::registerDirectChannel(const SharedMemInfo& mem,
+                                             ISensorsV2_0::registerDirectChannel_cb _hidl_cb) {
+    if (mDirectChannelSubHal == nullptr) {
+        _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+    } else {
+        mDirectChannelSubHal->registerDirectChannel(mem, _hidl_cb);
+    }
+    return Return<void>();
+}
+
+Return<Result> HalProxy::unregisterDirectChannel(int32_t channelHandle) {
+    Result result;
+    if (mDirectChannelSubHal == nullptr) {
+        result = Result::INVALID_OPERATION;
+    } else {
+        result = mDirectChannelSubHal->unregisterDirectChannel(channelHandle);
+    }
+    return result;
+}
+
+Return<void> HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle,
+                                          RateLevel rate,
+                                          ISensorsV2_0::configDirectReport_cb _hidl_cb) {
+    if (mDirectChannelSubHal == nullptr) {
+        _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */);
+    } else if (sensorHandle == -1 && rate != RateLevel::STOP) {
+        _hidl_cb(Result::BAD_VALUE, -1 /* reportToken */);
+    } else {
+        // -1 denotes all sensors should be disabled
+        if (sensorHandle != -1) {
+            sensorHandle = clearSubHalIndex(sensorHandle);
+        }
+        mDirectChannelSubHal->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+    }
+    return Return<void>();
+}
+
+Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+        ALOGE("%s: missing fd for writing", __FUNCTION__);
+        return Void();
+    }
+
+    android::base::borrowed_fd writeFd = dup(fd->data[0]);
+
+    std::ostringstream stream;
+    stream << "===HalProxy===" << std::endl;
+    stream << "Internal values:" << std::endl;
+    stream << "  Threads are running: " << (mThreadsRun.load() ? "true" : "false") << std::endl;
+    int64_t now = getTimeNow();
+    stream << "  Wakelock timeout start time: " << msFromNs(now - mWakelockTimeoutStartTime)
+           << " ms ago" << std::endl;
+    stream << "  Wakelock timeout reset time: " << msFromNs(now - mWakelockTimeoutResetTime)
+           << " ms ago" << std::endl;
+    // TODO(b/142969448): Add logging for history of wakelock acquisition per subhal.
+    stream << "  Wakelock ref count: " << mWakelockRefCount << std::endl;
+    stream << "  # of events on pending write writes queue: " << mSizePendingWriteEventsQueue
+           << std::endl;
+    stream << " Most events seen on pending write events queue: "
+           << mMostEventsObservedPendingWriteEventsQueue << std::endl;
+    if (!mPendingWriteEventsQueue.empty()) {
+        stream << "  Size of events list on front of pending writes queue: "
+               << mPendingWriteEventsQueue.front().first.size() << std::endl;
+    }
+    stream << "  # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl;
+    stream << "  # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl;
+    stream << "SubHals (" << mSubHalList.size() << "):" << std::endl;
+    for (auto& subHal : mSubHalList) {
+        stream << "  Name: " << subHal->getName() << std::endl;
+        stream << "  Debug dump: " << std::endl;
+        android::base::WriteStringToFd(stream.str(), writeFd);
+        subHal->debug(fd, {});
+        stream.str("");
+        stream << std::endl;
+    }
+    android::base::WriteStringToFd(stream.str(), writeFd);
+    return Return<void>();
+}
+
+Return<void> HalProxy::onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+                                                 int32_t subHalIndex) {
+    std::vector<SensorInfo> sensors;
+    {
+        std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+        for (SensorInfo sensor : dynamicSensorsAdded) {
+            if (!subHalIndexIsClear(sensor.sensorHandle)) {
+                ALOGE("Dynamic sensor added %s had sensorHandle with first byte not 0.",
+                      sensor.name.c_str());
+            } else {
+                sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
+                mDynamicSensors[sensor.sensorHandle] = sensor;
+                sensors.push_back(sensor);
+            }
+        }
+    }
+    mDynamicSensorsCallback->onDynamicSensorsConnected(sensors);
+    return Return<void>();
+}
+
+Return<void> HalProxy::onDynamicSensorsDisconnected(
+        const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) {
+    // TODO(b/143302327): Block this call until all pending events are flushed from queue
+    std::vector<int32_t> sensorHandles;
+    {
+        std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+        for (int32_t sensorHandle : dynamicSensorHandlesRemoved) {
+            if (!subHalIndexIsClear(sensorHandle)) {
+                ALOGE("Dynamic sensorHandle removed had first byte not 0.");
+            } else {
+                sensorHandle = setSubHalIndex(sensorHandle, subHalIndex);
+                if (mDynamicSensors.find(sensorHandle) != mDynamicSensors.end()) {
+                    mDynamicSensors.erase(sensorHandle);
+                    sensorHandles.push_back(sensorHandle);
+                }
+            }
+        }
+    }
+    mDynamicSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
+    return Return<void>();
+}
+
+void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
+    std::ifstream subHalConfigStream(configFileName);
+    if (!subHalConfigStream) {
+        ALOGE("Failed to load subHal config file: %s", configFileName);
+    } else {
+        std::string subHalLibraryFile;
+        while (subHalConfigStream >> subHalLibraryFile) {
+            void* handle = getHandleForSubHalSharedObject(subHalLibraryFile);
+            if (handle == nullptr) {
+                ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str());
+            } else {
+                SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
+                        (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
+                if (sensorsHalGetSubHalPtr != nullptr) {
+                    std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
+                            *sensorsHalGetSubHalPtr;
+                    uint32_t version;
+                    ISensorsSubHalV2_0* subHal = sensorsHalGetSubHal(&version);
+                    if (version != SUB_HAL_2_0_VERSION) {
+                        ALOGE("SubHal version was not 2.0 for library: %s",
+                              subHalLibraryFile.c_str());
+                    } else {
+                        ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
+                        mSubHalList.push_back(std::make_unique<SubHalWrapperV2_0>(subHal));
+                    }
+                } else {
+                    SensorsHalGetSubHalV2_1Func* getSubHalV2_1Ptr =
+                            (SensorsHalGetSubHalV2_1Func*)dlsym(handle, "sensorsHalGetSubHal_2_1");
+
+                    if (getSubHalV2_1Ptr == nullptr) {
+                        ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s",
+                              subHalLibraryFile.c_str());
+                    } else {
+                        std::function<SensorsHalGetSubHalV2_1Func> sensorsHalGetSubHal_2_1 =
+                                *getSubHalV2_1Ptr;
+                        uint32_t version;
+                        ISensorsSubHalV2_1* subHal = sensorsHalGetSubHal_2_1(&version);
+                        if (version != SUB_HAL_2_1_VERSION) {
+                            ALOGE("SubHal version was not 2.1 for library: %s",
+                                  subHalLibraryFile.c_str());
+                        } else {
+                            ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
+                            mSubHalList.push_back(std::make_unique<SubHalWrapperV2_1>(subHal));
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+void HalProxy::initializeSensorList() {
+    for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+        auto result = mSubHalList[subHalIndex]->getSensorsList([&](const auto& list) {
+            for (SensorInfo sensor : list) {
+                if (!subHalIndexIsClear(sensor.sensorHandle)) {
+                    ALOGE("SubHal sensorHandle's first byte was not 0");
+                } else {
+                    ALOGV("Loaded sensor: %s", sensor.name.c_str());
+                    sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
+                    setDirectChannelFlags(&sensor, mSubHalList[subHalIndex]);
+                    mSensors[sensor.sensorHandle] = sensor;
+                }
+            }
+        });
+        if (!result.isOk()) {
+            ALOGE("getSensorsList call failed for SubHal: %s",
+                  mSubHalList[subHalIndex]->getName().c_str());
+        }
+    }
+}
+
+void* HalProxy::getHandleForSubHalSharedObject(const std::string& filename) {
+    static const std::string kSubHalShareObjectLocations[] = {
+            "",  // Default locations will be searched
+#ifdef __LP64__
+            "/vendor/lib64/hw/", "/odm/lib64/hw/"
+#else
+            "/vendor/lib/hw/", "/odm/lib/hw/"
+#endif
+    };
+
+    for (const std::string& dir : kSubHalShareObjectLocations) {
+        void* handle = dlopen((dir + filename).c_str(), RTLD_NOW);
+        if (handle != nullptr) {
+            return handle;
+        }
+    }
+    return nullptr;
+}
+
+void HalProxy::init() {
+    initializeSensorList();
+}
+
+void HalProxy::stopThreads() {
+    mThreadsRun.store(false);
+    if (mEventQueueFlag != nullptr && mEventQueue != nullptr) {
+        size_t numToRead = mEventQueue->availableToRead();
+        std::vector<Event> events(numToRead);
+        mEventQueue->read(events.data(), numToRead);
+        mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ));
+    }
+    if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) {
+        uint32_t kZero = 0;
+        mWakeLockQueue->write(&kZero);
+        mWakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+    }
+    mWakelockCV.notify_one();
+    mEventQueueWriteCV.notify_one();
+    if (mPendingWritesThread.joinable()) {
+        mPendingWritesThread.join();
+    }
+    if (mWakelockThread.joinable()) {
+        mWakelockThread.join();
+    }
+}
+
+void HalProxy::disableAllSensors() {
+    for (const auto& sensorEntry : mSensors) {
+        int32_t sensorHandle = sensorEntry.first;
+        activate(sensorHandle, false /* enabled */);
+    }
+    std::lock_guard<std::mutex> dynamicSensorsLock(mDynamicSensorsMutex);
+    for (const auto& sensorEntry : mDynamicSensors) {
+        int32_t sensorHandle = sensorEntry.first;
+        activate(sensorHandle, false /* enabled */);
+    }
+}
+
+void HalProxy::startPendingWritesThread(HalProxy* halProxy) {
+    halProxy->handlePendingWrites();
+}
+
+void HalProxy::handlePendingWrites() {
+    // TODO(b/143302327): Find a way to optimize locking strategy maybe using two mutexes instead of
+    // one.
+    std::unique_lock<std::mutex> lock(mEventQueueWriteMutex);
+    while (mThreadsRun.load()) {
+        mEventQueueWriteCV.wait(
+                lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); });
+        if (mThreadsRun.load()) {
+            std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front().first;
+            size_t numWakeupEvents = mPendingWriteEventsQueue.front().second;
+            size_t eventQueueSize = mEventQueue->getQuantumCount();
+            size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
+            lock.unlock();
+            if (!mEventQueue->writeBlocking(
+                        pendingWriteEvents.data(), numToWrite,
+                        static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+                        static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+                        kPendingWriteTimeoutNs, mEventQueueFlag)) {
+                ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite);
+                if (numWakeupEvents > 0) {
+                    if (pendingWriteEvents.size() > eventQueueSize) {
+                        decrementRefCountAndMaybeReleaseWakelock(
+                                countNumWakeupEvents(pendingWriteEvents, eventQueueSize));
+                    } else {
+                        decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents);
+                    }
+                }
+            }
+            lock.lock();
+            mSizePendingWriteEventsQueue -= numToWrite;
+            if (pendingWriteEvents.size() > eventQueueSize) {
+                // TODO(b/143302327): Check if this erase operation is too inefficient. It will copy
+                // all the events ahead of it down to fill gap off array at front after the erase.
+                pendingWriteEvents.erase(pendingWriteEvents.begin(),
+                                         pendingWriteEvents.begin() + eventQueueSize);
+            } else {
+                mPendingWriteEventsQueue.pop();
+            }
+        }
+    }
+}
+
+void HalProxy::startWakelockThread(HalProxy* halProxy) {
+    halProxy->handleWakelocks();
+}
+
+void HalProxy::handleWakelocks() {
+    std::unique_lock<std::recursive_mutex> lock(mWakelockMutex);
+    while (mThreadsRun.load()) {
+        mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); });
+        if (mThreadsRun.load()) {
+            int64_t timeLeft;
+            if (sharedWakelockDidTimeout(&timeLeft)) {
+                resetSharedWakelock();
+            } else {
+                uint32_t numWakeLocksProcessed;
+                lock.unlock();
+                bool success = mWakeLockQueue->readBlocking(
+                        &numWakeLocksProcessed, 1, 0,
+                        static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft);
+                lock.lock();
+                if (success) {
+                    decrementRefCountAndMaybeReleaseWakelock(
+                            static_cast<size_t>(numWakeLocksProcessed));
+                }
+            }
+        }
+    }
+    resetSharedWakelock();
+}
+
+bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) {
+    bool didTimeout;
+    int64_t duration = getTimeNow() - mWakelockTimeoutStartTime;
+    if (duration > kWakelockTimeoutNs) {
+        didTimeout = true;
+    } else {
+        didTimeout = false;
+        *timeLeft = kWakelockTimeoutNs - duration;
+    }
+    return didTimeout;
+}
+
+void HalProxy::resetSharedWakelock() {
+    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+    decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount);
+    mWakelockTimeoutResetTime = getTimeNow();
+}
+
+void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+                                        V2_0::implementation::ScopedWakelock wakelock) {
+    size_t numToWrite = 0;
+    std::lock_guard<std::mutex> lock(mEventQueueWriteMutex);
+    if (wakelock.isLocked()) {
+        incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents);
+    }
+    if (mPendingWriteEventsQueue.empty()) {
+        numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
+        if (numToWrite > 0) {
+            if (mEventQueue->write(events.data(), numToWrite)) {
+                // TODO(b/143302327): While loop if mEventQueue->avaiableToWrite > 0 to possibly fit
+                // in more writes immediately
+                mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+            } else {
+                numToWrite = 0;
+            }
+        }
+    }
+    size_t numLeft = events.size() - numToWrite;
+    if (numToWrite < events.size() &&
+        mSizePendingWriteEventsQueue + numLeft <= kMaxSizePendingWriteEventsQueue) {
+        std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
+        mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
+        mSizePendingWriteEventsQueue += numLeft;
+        mMostEventsObservedPendingWriteEventsQueue =
+                std::max(mMostEventsObservedPendingWriteEventsQueue, mSizePendingWriteEventsQueue);
+        mEventQueueWriteCV.notify_one();
+    }
+}
+
+bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+                                                        int64_t* timeoutStart /* = nullptr */) {
+    if (!mThreadsRun.load()) return false;
+    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+    if (mWakelockRefCount == 0) {
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName);
+        mWakelockCV.notify_one();
+    }
+    mWakelockTimeoutStartTime = getTimeNow();
+    mWakelockRefCount += delta;
+    if (timeoutStart != nullptr) {
+        *timeoutStart = mWakelockTimeoutStartTime;
+    }
+    return true;
+}
+
+void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+                                                        int64_t timeoutStart /* = -1 */) {
+    if (!mThreadsRun.load()) return;
+    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+    if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
+    if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;
+    mWakelockRefCount -= std::min(mWakelockRefCount, delta);
+    if (mWakelockRefCount == 0) {
+        release_wake_lock(kWakelockName);
+    }
+}
+
+void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo,
+                                     std::shared_ptr<ISubHalWrapperBase> subHal) {
+    bool sensorSupportsDirectChannel =
+            (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
+                                  V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0;
+    if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) {
+        mDirectChannelSubHal = subHal;
+    } else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) {
+        // disable direct channel capability for sensors in subHals that are not
+        // the only one we will enable
+        sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
+                               V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
+    }
+}
+
+std::shared_ptr<ISubHalWrapperBase> HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) {
+    return mSubHalList[extractSubHalIndex(sensorHandle)];
+}
+
+bool HalProxy::isSubHalIndexValid(int32_t sensorHandle) {
+    return extractSubHalIndex(sensorHandle) < mSubHalList.size();
+}
+
+size_t HalProxy::countNumWakeupEvents(const std::vector<Event>& events, size_t n) {
+    size_t numWakeupEvents = 0;
+    for (size_t i = 0; i < n; i++) {
+        int32_t sensorHandle = events[i].sensorHandle;
+        if (mSensors[sensorHandle].flags & static_cast<uint32_t>(V1_0::SensorFlagBits::WAKE_UP)) {
+            numWakeupEvents++;
+        }
+    }
+    return numWakeupEvents;
+}
+
+int32_t HalProxy::clearSubHalIndex(int32_t sensorHandle) {
+    return sensorHandle & (~kSensorHandleSubHalIndexMask);
+}
+
+bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) {
+    return (sensorHandle & kSensorHandleSubHalIndexMask) == 0;
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/common/default/2.X/multihal/HalProxyCallback.cpp b/sensors/common/default/2.X/multihal/HalProxyCallback.cpp
new file mode 100644
index 0000000..3c1b17c
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/HalProxyCallback.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 "HalProxyCallback.h"
+
+#include <cinttypes>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+static constexpr int32_t kBitsAfterSubHalIndex = 24;
+
+/**
+ * Set the subhal index as first byte of sensor handle and return this modified version.
+ *
+ * @param sensorHandle The sensor handle to modify.
+ * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to.
+ *
+ * @return The modified sensor handle.
+ */
+int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) {
+    return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
+}
+
+void HalProxyCallbackBase::postEvents(const std::vector<V2_1::Event>& events,
+                                      ScopedWakelock wakelock) {
+    if (events.empty() || !mCallback->areThreadsRunning()) return;
+    size_t numWakeupEvents;
+    std::vector<V2_1::Event> processedEvents = processEvents(events, &numWakeupEvents);
+    if (numWakeupEvents > 0) {
+        ALOG_ASSERT(wakelock.isLocked(),
+                    "Wakeup events posted while wakelock unlocked for subhal"
+                    " w/ index %" PRId32 ".",
+                    mSubHalIndex);
+    } else {
+        ALOG_ASSERT(!wakelock.isLocked(),
+                    "No Wakeup events posted but wakelock locked for subhal"
+                    " w/ index %" PRId32 ".",
+                    mSubHalIndex);
+    }
+    mCallback->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock));
+}
+
+ScopedWakelock HalProxyCallbackBase::createScopedWakelock(bool lock) {
+    ScopedWakelock wakelock(mRefCounter, lock);
+    return wakelock;
+}
+
+std::vector<V2_1::Event> HalProxyCallbackBase::processEvents(const std::vector<V2_1::Event>& events,
+                                                             size_t* numWakeupEvents) const {
+    *numWakeupEvents = 0;
+    std::vector<V2_1::Event> eventsOut;
+    for (V2_1::Event event : events) {
+        event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex);
+        eventsOut.push_back(event);
+        const V2_1::SensorInfo& sensor = mCallback->getSensorInfo(event.sensorHandle);
+        if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) {
+            (*numWakeupEvents)++;
+        }
+    }
+    return eventsOut;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/common/default/2.X/multihal/ScopedWakelock.cpp b/sensors/common/default/2.X/multihal/ScopedWakelock.cpp
new file mode 100644
index 0000000..bf2ad35
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/ScopedWakelock.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 "V2_0/ScopedWakelock.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+int64_t getTimeNow() {
+    return std::chrono::duration_cast<std::chrono::nanoseconds>(
+                   std::chrono::system_clock::now().time_since_epoch())
+            .count();
+}
+
+ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked)
+    : mRefCounter(refCounter), mLocked(locked) {
+    if (mLocked) {
+        mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs);
+    }
+}
+
+ScopedWakelock::~ScopedWakelock() {
+    if (mLocked) {
+        mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/sensors/common/default/2.X/multihal/include/HalProxy.h b/sensors/common/default/2.X/multihal/include/HalProxy.h
new file mode 100644
index 0000000..35d7c8b
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/include/HalProxy.h
@@ -0,0 +1,462 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "EventMessageQueueWrapper.h"
+#include "HalProxyCallback.h"
+#include "ISensorsCallbackWrapper.h"
+#include "SubHalWrapper.h"
+#include "V2_0/ScopedWakelock.h"
+#include "V2_0/SubHal.h"
+#include "V2_1/SubHal.h"
+#include "convertV2_1.h"
+
+#include <android/hardware/sensors/2.1/ISensors.h>
+#include <android/hardware/sensors/2.1/types.h>
+#include <fmq/MessageQueue.h>
+#include <hardware_legacy/power.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <map>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+/**
+ * HalProxy is the main interface for Multi-HAL. It is responsible for managing  subHALs and
+ * proxying function calls to/from the subHAL APIs from the sensors framework. It also manages any
+ * wakelocks allocated through the IHalProxyCallback and manages posting events to the sensors
+ * framework.
+ */
+class HalProxy : public V2_0::implementation::IScopedWakelockRefCounter,
+                 public V2_0::implementation::ISubHalCallback {
+  public:
+    using Event = ::android::hardware::sensors::V2_1::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 SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
+    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+    using IHalProxyCallbackV2_0 = V2_0::implementation::IHalProxyCallback;
+    using IHalProxyCallbackV2_1 = V2_1::implementation::IHalProxyCallback;
+    using ISensorsSubHalV2_0 = V2_0::implementation::ISensorsSubHal;
+    using ISensorsSubHalV2_1 = V2_1::implementation::ISensorsSubHal;
+    using ISensorsV2_0 = V2_0::ISensors;
+    using ISensorsV2_1 = V2_1::ISensors;
+    using HalProxyCallbackBase = V2_0::implementation::HalProxyCallbackBase;
+
+    explicit HalProxy();
+    // Test only constructor.
+    explicit HalProxy(std::vector<ISensorsSubHalV2_0*>& subHalList);
+    explicit HalProxy(std::vector<ISensorsSubHalV2_0*>& subHalList,
+                      std::vector<ISensorsSubHalV2_1*>& subHalListV2_1);
+    ~HalProxy();
+
+    // Methods from ::android::hardware::sensors::V2_1::ISensors follow.
+    Return<void> getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb);
+
+    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);
+
+    Return<Result> injectSensorData_2_1(const Event& event);
+
+    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+    Return<void> getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb);
+
+    Return<Result> setOperationMode(OperationMode mode);
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled);
+
+    Return<Result> initialize(
+            const ::android::hardware::MQDescriptorSync<V1_0::Event>& eventQueueDescriptor,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+            const sp<V2_0::ISensorsCallback>& sensorsCallback);
+
+    Return<Result> initializeCommon(
+            std::unique_ptr<EventMessageQueueWrapperBase>& eventQueue,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+            const sp<ISensorsCallbackWrapperBase>& sensorsCallback);
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs);
+
+    Return<Result> flush(int32_t sensorHandle);
+
+    Return<Result> injectSensorData(const V1_0::Event& event);
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       ISensorsV2_0::registerDirectChannel_cb _hidl_cb);
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle);
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    ISensorsV2_0::configDirectReport_cb _hidl_cb);
+
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args);
+
+    Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+                                           int32_t subHalIndex) override;
+
+    Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved,
+                                              int32_t subHalIndex) override;
+
+    void postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+                                  V2_0::implementation::ScopedWakelock wakelock) override;
+
+    const SensorInfo& getSensorInfo(int32_t sensorHandle) override {
+        return mSensors[sensorHandle];
+    }
+
+    bool areThreadsRunning() override { return mThreadsRun.load(); }
+
+    // Below methods are from IScopedWakelockRefCounter interface
+    bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+                                                  int64_t* timeoutStart = nullptr) override;
+
+    void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override;
+
+  private:
+    using EventMessageQueueV2_1 = MessageQueue<V2_1::Event, kSynchronizedReadWrite>;
+    using EventMessageQueueV2_0 = MessageQueue<V1_0::Event, kSynchronizedReadWrite>;
+    using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+    /**
+     * The Event FMQ where sensor events are written
+     */
+    std::unique_ptr<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 and to
+     * interrupt event queue blocking write.
+     */
+    EventFlag* mEventQueueFlag = nullptr;
+
+    //! Event Flag to signal internally that the wakelock queue should stop its blocking read.
+    EventFlag* mWakelockQueueFlag = nullptr;
+
+    /**
+     * Callback to the sensors framework to inform it that new sensors have been added or removed.
+     */
+    sp<ISensorsCallbackWrapperBase> mDynamicSensorsCallback;
+
+    /**
+     * SubHal objects that have been saved from vendor dynamic libraries.
+     */
+    std::vector<std::shared_ptr<ISubHalWrapperBase>> mSubHalList;
+
+    /**
+     * Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as
+     * well as the modified sensor handle for the framework.
+     *
+     * The subhal index is encoded in the first byte of the sensor handle and the remaining
+     * bytes are generated by the subhal to identify the sensor.
+     */
+    std::map<int32_t, SensorInfo> mSensors;
+
+    //! Map of the dynamic sensors that have been added to halproxy.
+    std::map<int32_t, SensorInfo> mDynamicSensors;
+
+    //! The current operation mode for all subhals.
+    OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
+    //! The single subHal that supports directChannel reporting.
+    std::shared_ptr<ISubHalWrapperBase> mDirectChannelSubHal;
+
+    //! The timeout for each pending write on background thread for events.
+    static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
+
+    //! The bit mask used to get the subhal index from a sensor handle.
+    static constexpr int32_t kSensorHandleSubHalIndexMask = 0xFF000000;
+
+    /**
+     * A FIFO queue of pairs of vector of events and the number of wakeup events in that vector
+     * which are waiting to be written to the events fmq in the background thread.
+     */
+    std::queue<std::pair<std::vector<Event>, size_t>> mPendingWriteEventsQueue;
+
+    //! The most events observed on the pending write events queue for debug purposes.
+    size_t mMostEventsObservedPendingWriteEventsQueue = 0;
+
+    //! The max number of events allowed in the pending write events queue
+    static constexpr size_t kMaxSizePendingWriteEventsQueue = 100000;
+
+    //! The number of events in the pending write events queue
+    size_t mSizePendingWriteEventsQueue = 0;
+
+    //! The mutex protecting writing to the fmq and the pending events queue
+    std::mutex mEventQueueWriteMutex;
+
+    //! The condition variable waiting on pending write events to stack up
+    std::condition_variable mEventQueueWriteCV;
+
+    //! The thread object ptr that handles pending writes
+    std::thread mPendingWritesThread;
+
+    //! The thread object that handles wakelocks
+    std::thread mWakelockThread;
+
+    //! The bool indicating whether to end the threads started in initialize
+    std::atomic_bool mThreadsRun = true;
+
+    //! The mutex protecting access to the dynamic sensors added and removed methods.
+    std::mutex mDynamicSensorsMutex;
+
+    // WakelockRefCount membar vars below
+
+    //! The mutex protecting the wakelock refcount and subsequent wakelock releases and
+    //! acquisitions
+    std::recursive_mutex mWakelockMutex;
+
+    std::condition_variable_any mWakelockCV;
+
+    //! The refcount of how many ScopedWakelocks and pending wakeup events are active
+    size_t mWakelockRefCount = 0;
+
+    int64_t mWakelockTimeoutStartTime = V2_0::implementation::getTimeNow();
+
+    int64_t mWakelockTimeoutResetTime = V2_0::implementation::getTimeNow();
+
+    const char* kWakelockName = "SensorsHAL_WAKEUP";
+
+    /**
+     * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
+     * listed in a config file.
+     */
+    void initializeSubHalListFromConfigFile(const char* configFileName);
+
+    /**
+     * Initialize the HalProxyCallback vector using the list of subhals.
+     */
+    void initializeSubHalCallbacks();
+
+    /**
+     * Initialize the list of SensorInfo objects in mSensorList by getting sensors from each
+     * subhal.
+     */
+    void initializeSensorList();
+
+    /**
+     * Try using the default include directories as well as the directories defined in
+     * kSubHalShareObjectLocations to get a handle for dlsym for a subhal.
+     *
+     * @param filename The file name to search for.
+     *
+     * @return The handle or nullptr if search failed.
+     */
+    void* getHandleForSubHalSharedObject(const std::string& filename);
+
+    /**
+     * Calls the helper methods that all ctors use.
+     */
+    void init();
+
+    /**
+     * Stops all threads by setting the threads running flag to false and joining to them.
+     */
+    void stopThreads();
+
+    /**
+     * Disable all the sensors observed by the HalProxy.
+     */
+    void disableAllSensors();
+
+    /**
+     * Starts the thread that handles pending writes to event fmq.
+     *
+     * @param halProxy The HalProxy object pointer.
+     */
+    static void startPendingWritesThread(HalProxy* halProxy);
+
+    //! Handles the pending writes on events to eventqueue.
+    void handlePendingWrites();
+
+    /**
+     * Starts the thread that handles decrementing the ref count on wakeup events processed by the
+     * framework and timing out wakelocks.
+     *
+     * @param halProxy The HalProxy object pointer.
+     */
+    static void startWakelockThread(HalProxy* halProxy);
+
+    //! Handles the wakelocks.
+    void handleWakelocks();
+
+    /**
+     * @param timeLeft The variable that should be set to the timeleft before timeout will occur or
+     * unmodified if timeout occurred.
+     *
+     * @return true if the shared wakelock has been held passed the timeout and should be released
+     */
+    bool sharedWakelockDidTimeout(int64_t* timeLeft);
+
+    /**
+     * Reset all the member variables associated with the wakelock ref count and maybe release
+     * the shared wakelock.
+     */
+    void resetSharedWakelock();
+
+    /**
+     * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
+     * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
+     * direct channel enabled sensor seen.
+     *
+     * @param sensorInfo The SensorInfo object that may be altered to have direct channel support
+     *    disabled.
+     * @param subHal The subhal pointer that the current sensorInfo object came from.
+     */
+    void setDirectChannelFlags(SensorInfo* sensorInfo, std::shared_ptr<ISubHalWrapperBase> subHal);
+
+    /*
+     * Get the subhal pointer which can be found by indexing into the mSubHalList vector
+     * using the index from the first byte of sensorHandle.
+     *
+     * @param sensorHandle The handle used to identify a sensor in one of the subhals.
+     */
+    std::shared_ptr<ISubHalWrapperBase> getSubHalForSensorHandle(int32_t sensorHandle);
+
+    /**
+     * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList.
+     *
+     * @param sensorHandle The sensor handle to check.
+     *
+     * @return true if sensorHandles's subhal index byte is valid.
+     */
+    bool isSubHalIndexValid(int32_t sensorHandle);
+
+    /**
+     * Count the number of wakeup events in the first n events of the vector.
+     *
+     * @param events The vector of Event objects.
+     * @param n The end index not inclusive of events to consider.
+     *
+     * @return The number of wakeup events of the considered events.
+     */
+    size_t countNumWakeupEvents(const std::vector<Event>& events, size_t n);
+
+    /*
+     * Clear out the subhal index bytes from a sensorHandle.
+     *
+     * @param sensorHandle The sensor handle to modify.
+     *
+     * @return The modified version of the sensor handle.
+     */
+    static int32_t clearSubHalIndex(int32_t sensorHandle);
+
+    /**
+     * @param sensorHandle The sensor handle to modify.
+     *
+     * @return true if subHalIndex byte of sensorHandle is zeroed.
+     */
+    static bool subHalIndexIsClear(int32_t sensorHandle);
+};
+
+/**
+ * Since a newer HAL can't masquerade as a older HAL, IHalProxy enables the HalProxy to be compiled
+ * either for HAL 2.0 or HAL 2.1 depending on the build configuration.
+ */
+template <class ISensorsVersion>
+class IHalProxy : public HalProxy, public ISensorsVersion {
+    Return<void> getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) override {
+        return HalProxy::getSensorsList(_hidl_cb);
+    }
+
+    Return<Result> setOperationMode(OperationMode mode) override {
+        return HalProxy::setOperationMode(mode);
+    }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override {
+        return HalProxy::activate(sensorHandle, enabled);
+    }
+
+    Return<Result> initialize(
+            const ::android::hardware::MQDescriptorSync<V1_0::Event>& eventQueueDescriptor,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+            const sp<V2_0::ISensorsCallback>& sensorsCallback) override {
+        return HalProxy::initialize(eventQueueDescriptor, wakeLockDescriptor, sensorsCallback);
+    }
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override {
+        return HalProxy::batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+    }
+
+    Return<Result> flush(int32_t sensorHandle) override { return HalProxy::flush(sensorHandle); }
+
+    Return<Result> injectSensorData(const V1_0::Event& event) override {
+        return HalProxy::injectSensorData(event);
+    }
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       ISensorsV2_0::registerDirectChannel_cb _hidl_cb) override {
+        return HalProxy::registerDirectChannel(mem, _hidl_cb);
+    }
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+        return HalProxy::unregisterDirectChannel(channelHandle);
+    }
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    ISensorsV2_0::configDirectReport_cb _hidl_cb) override {
+        return HalProxy::configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+    }
+
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override {
+        return HalProxy::debug(fd, args);
+    }
+};
+
+class HalProxyV2_0 : public IHalProxy<V2_0::ISensors> {};
+
+class HalProxyV2_1 : public IHalProxy<V2_1::ISensors> {
+    Return<void> getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb) override {
+        return HalProxy::getSensorsList_2_1(_hidl_cb);
+    }
+
+    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 HalProxy::initialize_2_1(eventQueueDescriptor, wakeLockDescriptor, sensorsCallback);
+    }
+
+    Return<Result> injectSensorData_2_1(const Event& event) override {
+        return HalProxy::injectSensorData_2_1(event);
+    }
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/common/default/2.X/multihal/include/HalProxyCallback.h b/sensors/common/default/2.X/multihal/include/HalProxyCallback.h
new file mode 100644
index 0000000..e62b7d1
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/include/HalProxyCallback.h
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "V2_0/ScopedWakelock.h"
+#include "V2_0/SubHal.h"
+#include "V2_1/SubHal.h"
+#include "convertV2_1.h"
+
+#include <android/hardware/sensors/2.1/ISensors.h>
+#include <android/hardware/sensors/2.1/types.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+/**
+ * Interface used to communicate with the HalProxy when subHals interact with their provided
+ * callback.
+ */
+class ISubHalCallback {
+  public:
+    virtual ~ISubHalCallback() {}
+
+    // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change
+    // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework
+    // via the binder, these methods are invoked from a callback provided to sub-HALs inside the
+    // same process as the HalProxy, but potentially running on different threads.
+    virtual Return<void> onDynamicSensorsConnected(
+            const hidl_vec<V2_1::SensorInfo>& dynamicSensorsAdded, int32_t subHalIndex) = 0;
+
+    virtual Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) = 0;
+
+    /**
+     * Post events to the event message queue if there is room to write them. Otherwise post the
+     * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs
+     * timeout.
+     *
+     * @param events The list of events to post to the message queue.
+     * @param numWakeupEvents The number of wakeup events in events.
+     * @param wakelock The wakelock associated with this post of events.
+     */
+    virtual void postEventsToMessageQueue(const std::vector<V2_1::Event>& events,
+                                          size_t numWakeupEvents,
+                                          V2_0::implementation::ScopedWakelock wakelock) = 0;
+
+    /**
+     * Get the sensor info associated with that sensorHandle.
+     *
+     * @param sensorHandle The sensor handle.
+     *
+     * @return The sensor info object in the mapping.
+     */
+    virtual const V2_1::SensorInfo& getSensorInfo(int32_t sensorHandle) = 0;
+
+    virtual bool areThreadsRunning() = 0;
+};
+
+/**
+ * Callback class given to subhals that allows the HalProxy to know which subhal a given invocation
+ * is coming from.
+ */
+class HalProxyCallbackBase : public VirtualLightRefBase {
+  public:
+    HalProxyCallbackBase(ISubHalCallback* callback,
+                         V2_0::implementation::IScopedWakelockRefCounter* refCounter,
+                         int32_t subHalIndex)
+        : mCallback(callback), mRefCounter(refCounter), mSubHalIndex(subHalIndex) {}
+
+    void postEvents(const std::vector<V2_1::Event>& events,
+                    V2_0::implementation::ScopedWakelock wakelock);
+
+    V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock);
+
+  protected:
+    ISubHalCallback* mCallback;
+    V2_0::implementation::IScopedWakelockRefCounter* mRefCounter;
+    int32_t mSubHalIndex;
+
+  private:
+    std::vector<V2_1::Event> processEvents(const std::vector<V2_1::Event>& events,
+                                           size_t* numWakeupEvents) const;
+};
+
+class HalProxyCallbackV2_0 : public HalProxyCallbackBase,
+                             public V2_0::implementation::IHalProxyCallback {
+  public:
+    HalProxyCallbackV2_0(ISubHalCallback* callback,
+                         V2_0::implementation::IScopedWakelockRefCounter* refCounter,
+                         int32_t subHalIndex)
+        : HalProxyCallbackBase(callback, refCounter, subHalIndex) {}
+
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<V1_0::SensorInfo>& dynamicSensorsAdded) override {
+        return mCallback->onDynamicSensorsConnected(
+                V2_1::implementation::convertToNewSensorInfos(dynamicSensorsAdded), mSubHalIndex);
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+        return mCallback->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex);
+    }
+
+    void postEvents(const std::vector<V1_0::Event>& events,
+                    V2_0::implementation::ScopedWakelock wakelock) override {
+        HalProxyCallbackBase::postEvents(V2_1::implementation::convertToNewEvents(events),
+                                         std::move(wakelock));
+    }
+
+    V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock) override {
+        return HalProxyCallbackBase::createScopedWakelock(lock);
+    }
+};
+
+class HalProxyCallbackV2_1 : public HalProxyCallbackBase,
+                             public V2_1::implementation::IHalProxyCallback {
+  public:
+    HalProxyCallbackV2_1(ISubHalCallback* callback,
+                         V2_0::implementation::IScopedWakelockRefCounter* refCounter,
+                         int32_t subHalIndex)
+        : HalProxyCallbackBase(callback, refCounter, subHalIndex) {}
+
+    Return<void> onDynamicSensorsConnected_2_1(
+            const hidl_vec<V2_1::SensorInfo>& dynamicSensorsAdded) override {
+        return mCallback->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex);
+    }
+
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<V1_0::SensorInfo>& /* dynamicSensorsAdded */) override {
+        LOG_ALWAYS_FATAL("Old dynamic sensors method can't be used");
+        return Void();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+        return mCallback->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex);
+    }
+
+    void postEvents(const std::vector<V2_1::Event>& events,
+                    V2_0::implementation::ScopedWakelock wakelock) override {
+        return HalProxyCallbackBase::postEvents(events, std::move(wakelock));
+    }
+
+    V2_0::implementation::ScopedWakelock createScopedWakelock(bool lock) override {
+        return HalProxyCallbackBase::createScopedWakelock(lock);
+    }
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/sensors/common/default/2.X/multihal/include/SubHalWrapper.h b/sensors/common/default/2.X/multihal/include/SubHalWrapper.h
new file mode 100644
index 0000000..149bb5e
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/include/SubHalWrapper.h
@@ -0,0 +1,188 @@
+/*
+ * 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 "HalProxyCallback.h"
+#include "V2_0/SubHal.h"
+#include "V2_1/SubHal.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 {
+
+/**
+ * The following subHal wrapper classes abstract away common functionality across V2.0 and V2.1
+ * subHal interfaces. Much of the logic is common between the two versions and this allows users of
+ * the classes to only care about the type used at initialization and then interact with either
+ * version of the subHal interface without worrying about the type.
+ */
+class ISubHalWrapperBase {
+  protected:
+    using Event = ::android::hardware::sensors::V2_1::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 SensorInfo = ::android::hardware::sensors::V2_1::SensorInfo;
+    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+
+  public:
+    virtual ~ISubHalWrapperBase() {}
+
+    virtual bool supportsNewEvents() = 0;
+
+    virtual Return<Result> initialize(V2_0::implementation::ISubHalCallback* callback,
+                                      V2_0::implementation::IScopedWakelockRefCounter* refCounter,
+                                      int32_t subHalIndex) = 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> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) = 0;
+
+    virtual const std::string getName() = 0;
+};
+
+template <typename T>
+class SubHalWrapperBase : public ISubHalWrapperBase {
+  public:
+    SubHalWrapperBase(T* subHal) : mSubHal(subHal){};
+
+    virtual bool supportsNewEvents() override { return false; }
+
+    virtual Return<void> getSensorsList(
+            ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override {
+        return mSubHal->getSensorsList(
+                [&](const auto& list) { _hidl_cb(convertToNewSensorInfos(list)); });
+    }
+
+    Return<Result> setOperationMode(OperationMode mode) override {
+        return mSubHal->setOperationMode(mode);
+    }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override {
+        return mSubHal->activate(sensorHandle, enabled);
+    }
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override {
+        return mSubHal->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+    }
+
+    Return<Result> flush(int32_t sensorHandle) override { return mSubHal->flush(sensorHandle); }
+
+    virtual Return<Result> injectSensorData(const Event& event) override {
+        return mSubHal->injectSensorData(convertToOldEvent(event));
+    }
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       ISensors::registerDirectChannel_cb _hidl_cb) override {
+        return mSubHal->registerDirectChannel(mem, _hidl_cb);
+    }
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+        return mSubHal->unregisterDirectChannel(channelHandle);
+    }
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    ISensors::configDirectReport_cb _hidl_cb) override {
+        return mSubHal->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+    }
+
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override {
+        return mSubHal->debug(fd, args);
+    }
+
+    const std::string getName() override { return mSubHal->getName(); }
+
+  protected:
+    T* mSubHal;
+};
+
+class SubHalWrapperV2_0 : public SubHalWrapperBase<V2_0::implementation::ISensorsSubHal> {
+  public:
+    SubHalWrapperV2_0(V2_0::implementation::ISensorsSubHal* subHal) : SubHalWrapperBase(subHal){};
+
+    Return<Result> initialize(V2_0::implementation::ISubHalCallback* callback,
+                              V2_0::implementation::IScopedWakelockRefCounter* refCounter,
+                              int32_t subHalIndex) override {
+        return mSubHal->initialize(
+                new V2_0::implementation::HalProxyCallbackV2_0(callback, refCounter, subHalIndex));
+    }
+};
+
+class SubHalWrapperV2_1 : public SubHalWrapperBase<V2_1::implementation::ISensorsSubHal> {
+  public:
+    SubHalWrapperV2_1(V2_1::implementation::ISensorsSubHal* subHal) : SubHalWrapperBase(subHal) {}
+
+    bool supportsNewEvents() override { return true; }
+
+    virtual Return<void> getSensorsList(
+            ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override {
+        return mSubHal->getSensorsList_2_1([&](const auto& list) { _hidl_cb(list); });
+    }
+
+    virtual Return<Result> injectSensorData(const Event& event) override {
+        return mSubHal->injectSensorData_2_1(event);
+    }
+
+    Return<Result> initialize(V2_0::implementation::ISubHalCallback* callback,
+                              V2_0::implementation::IScopedWakelockRefCounter* refCounter,
+                              int32_t subHalIndex) override {
+        return mSubHal->initialize(
+                new V2_0::implementation::HalProxyCallbackV2_1(callback, refCounter, subHalIndex));
+    }
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h
new file mode 100644
index 0000000..1cc5cd5
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/include/V2_0/ScopedWakelock.h
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/sensors/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+
+const int64_t kWakelockTimeoutNs =
+        static_cast<int64_t>(SensorTimeout::WAKE_LOCK_SECONDS) * INT64_C(1000000000);
+
+int64_t getTimeNow();
+
+class IScopedWakelockRefCounter : public RefBase {
+  public:
+    /**
+     * Increment the wakelock ref count and maybe acquire the shared wakelock if incrementing
+     * from 0 then return the time of incrementing back to caller.
+     *
+     * @param delta The amount to change ref count by.
+     * @param timeoutStart The ptr to the timestamp in ns that the increment occurred which will be
+     *        set in the function or nullptr if not specified.
+     *
+     * @return true if successfully incremented the wakelock ref count.
+     */
+    virtual bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+                                                          int64_t* timeoutStart = nullptr) = 0;
+    /**
+     * Decrement the wakelock ref count and maybe release wakelock if ref count ends up 0.
+     *
+     * @param delta The amount to change ref count by.
+     * @param timeoutStart The timestamp in ns that the calling context kept track of when
+     *        incrementing the ref count or -1 by default
+     */
+    virtual void decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+                                                          int64_t timeoutStart = -1) = 0;
+    // Virtual dtor needed for compilation success
+    virtual ~IScopedWakelockRefCounter(){};
+};
+
+/**
+ * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a
+ * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block.
+ * When a ScopedWakelock is created, it increments the reference count stored in the HalProxy
+ * for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes
+ * out of scope, the ref count is decremented, potentially releasing the wake lock if no other
+ * references to the wake lock exist.
+ *
+ * This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback
+ * provided to sub-HALs during initialization and should be used for all wake lock acquisition
+ * inside of the sub-HAL to ensure wake locks are not held indefinitely.
+ *
+ * The most prevalent use case for this class will be for posting events to the framework through
+ * the postEvents HalProxy callback. The expectation is that sub-HALs will create this
+ * ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean
+ * provided to createScopedWakelock will be set the according to whether the sensor events are
+ * from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the
+ * postEvents callback passing in the previously created ScopedWakelock. At this point, ownership
+ * of the object will be passed to the HalProxy that will then be responsible for ensuring any
+ * wake locks continue to be held, if necessary.
+ */
+class ScopedWakelock {
+  public:
+    ScopedWakelock(ScopedWakelock&&) = default;
+    ScopedWakelock& operator=(ScopedWakelock&&) = default;
+    virtual ~ScopedWakelock();
+
+    bool isLocked() const { return mLocked; }
+
+  private:
+    friend class HalProxyCallbackBase;
+    IScopedWakelockRefCounter* mRefCounter;
+    int64_t mCreatedAtTimeNs;
+    bool mLocked;
+    ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked);
+    ScopedWakelock(const ScopedWakelock&) = delete;
+    ScopedWakelock& operator=(const ScopedWakelock&) = delete;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/sensors/common/default/2.X/multihal/include/V2_0/SubHal.h b/sensors/common/default/2.X/multihal/include/V2_0/SubHal.h
new file mode 100644
index 0000000..2a80e6b
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/include/V2_0/SubHal.h
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "ScopedWakelock.h"
+
+#include <android/hardware/sensors/1.0/types.h>
+#include <android/hardware/sensors/2.0/ISensors.h>
+
+#include <vector>
+
+// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 |
+// (HAL minor version) << 16 | (multiHAL version)
+#define SUB_HAL_2_0_VERSION 0x02000000
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+
+/**
+ * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor
+ * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure
+ * callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient
+ * manner.
+ */
+class IHalProxyCallback : public ISensorsCallback {
+  public:
+    /**
+     * Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this
+     * whenever new sensor events need to be delivered to the sensors framework. Once invoked, the
+     * HalProxy will attempt to send events to the sensors framework using a blocking write with a
+     * 5 second timeout. This write may be done asynchronously if the queue used to communicate
+     * with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the
+     * write fails, the events will be dropped and any wake locks held will be released.
+     *
+     * The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's
+     * not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant
+     * with the sensors HAL 2.0 specification. Additionally, since ScopedWakelock isn't copyable,
+     * the HalProxy will take ownership of the wake lock given when this method is invoked. Once the
+     * method returns, the HalProxy will handle holding the wake lock, if necessary, until the
+     * framework has successfully processed any wakeup events.
+     *
+     * No return type is used for this callback to avoid sub-HALs trying to resend events when
+     * writes fail. Writes should only fail when the framework is under inordinate stress which will
+     * likely result in a framework restart so retrying will likely only result in overloading the
+     * HalProxy. Sub-HALs should always assume that the write was a success and perform any
+     * necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and
+     * bug reports) it encounters during delivery to ensure it's obvious that a failure occurred.
+     *
+     * @param events the events that should be sent to the sensors framework
+     * @param wakelock ScopedWakelock that should be locked to send events from wake sensors and
+     *     unlocked otherwise.
+     */
+    virtual void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) = 0;
+
+    /**
+     * Initializes a ScopedWakelock on the stack that, when locked, will increment the reference
+     * count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class
+     * definition for how it should be used.
+     *
+     * @param lock whether the ScopedWakelock should be locked before it's returned.
+     * @return the created ScopedWakelock
+     */
+    virtual ScopedWakelock createScopedWakelock(bool lock) = 0;
+};
+
+/**
+ * ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with
+ * multihal 2.0 and in order for the HalProxy to successfully load and communicate with the sub-HAL.
+ *
+ * Any vendor wishing to implement this interface and support multihal 2.0 will need to create a
+ * dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by
+ * the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's
+ * implementation of sensorsHalGetSubHal.
+ *
+ * With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec.
+ * Any sensor handles given to the HalProxy, either through getSensorsList() or the
+ * onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL
+ * handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and
+ * sub-HALs can continue to use the lower 3 bytes of the handle.
+ */
+class ISensorsSubHal : public ISensors {
+  public:
+    // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement
+    // the version below to allow communciation logic to centralized in the HalProxy
+    Return<Result> initialize(
+            const ::android::hardware::MQDescriptorSync<Event>& /* eventQueueDescriptor */,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& /* wakeLockDescriptor */,
+            const sp<ISensorsCallback>& /* sensorsCallback */) final {
+        return Result::INVALID_OPERATION;
+    }
+
+    /**
+     * Method defined in ::android::hidl::base::V1_0::IBase.
+     *
+     * This method should write debug information to hidl_handle that is useful for debugging
+     * issues. Suggestions include:
+     * - Sensor info including handle values and any other state available in the SensorInfo class
+     * - List of active sensors and their current sampling period and reporting latency
+     * - Information about pending flush requests
+     * - Current operating mode
+     * - Currently registered direct channel info
+     * - A history of any of the above
+     */
+    virtual Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) = 0;
+
+    /**
+     * @return A human-readable name for use in wake locks and logging.
+     */
+    virtual const std::string getName() = 0;
+
+    /**
+     * This is the first method invoked on the sub-HAL after it's allocated through
+     * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and
+     * retain the callback given in order to communicate with the HalProxy. Method will be called
+     * anytime the sensors framework restarts. Therefore, this method will be responsible for
+     * reseting the state of the subhal and cleaning up and reallocating any previously allocated
+     * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state
+     * as well.
+     *
+     * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state
+     *     changes, new sensor events should be sent to the framework, and when a new ScopedWakelock
+     *     should be created.
+     * @return result OK on success
+     */
+    virtual Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) = 0;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+using ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
+
+/**
+ * Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic
+ * library. This function will only be invoked once at initialization time.
+ *
+ * NOTE: The supported sensors HAL version must match SUB_HAL_2_0_VERSION exactly or the HalProxy
+ *     will fail to initialize.
+ *
+ * @param uint32_t when this function returns, this parameter must contain the HAL version that
+ *     this sub-HAL supports. To support this version of multi-HAL, this must be set to
+ *     SUB_HAL_2_0_VERSION.
+ * @return A statically allocated, valid ISensorsSubHal implementation.
+ */
+__attribute__((visibility("default"))) extern "C" ISensorsSubHal* sensorsHalGetSubHal(
+        uint32_t* version);
diff --git a/sensors/common/default/2.X/multihal/include/V2_1/SubHal.h b/sensors/common/default/2.X/multihal/include/V2_1/SubHal.h
new file mode 100644
index 0000000..cd49422
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/include/V2_1/SubHal.h
@@ -0,0 +1,180 @@
+/*
+ * 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 "V2_0/ScopedWakelock.h"
+
+#include <android/hardware/sensors/2.1/ISensors.h>
+#include <android/hardware/sensors/2.1/types.h>
+
+#include <vector>
+
+// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 |
+// (HAL minor version) << 16 | (multiHAL version)
+#define SUB_HAL_2_1_VERSION 0x02010000
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+/**
+ * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor
+ * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure
+ * callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient
+ * manner.
+ */
+class IHalProxyCallback : public ISensorsCallback {
+  public:
+    using ScopedWakelock = V2_0::implementation::ScopedWakelock;
+
+    /**
+     * Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this
+     * whenever new sensor events need to be delivered to the sensors framework. Once invoked, the
+     * HalProxy will attempt to send events to the sensors framework using a blocking write with a
+     * 5 second timeout. This write may be done asynchronously if the queue used to communicate
+     * with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the
+     * write fails, the events will be dropped and any wake locks held will be released.
+     *
+     * The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's
+     * not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant
+     * with the sensors HAL specification. Additionally, since ScopedWakelock isn't copyable,
+     * the HalProxy will take ownership of the wake lock given when this method is invoked. Once the
+     * method returns, the HalProxy will handle holding the wake lock, if necessary, until the
+     * framework has successfully processed any wakeup events.
+     *
+     * No return type is used for this callback to avoid sub-HALs trying to resend events when
+     * writes fail. Writes should only fail when the framework is under inordinate stress which will
+     * likely result in a framework restart so retrying will likely only result in overloading the
+     * HalProxy. Sub-HALs should always assume that the write was a success and perform any
+     * necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and
+     * bug reports) it encounters during delivery to ensure it's obvious that a failure occurred.
+     *
+     * @param events the events that should be sent to the sensors framework
+     * @param wakelock ScopedWakelock that should be locked to send events from wake sensors and
+     *     unlocked otherwise.
+     */
+    virtual void postEvents(const std::vector<V2_1::Event>& events, ScopedWakelock wakelock) = 0;
+
+    /**
+     * Initializes a ScopedWakelock on the stack that, when locked, will increment the reference
+     * count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class
+     * definition for how it should be used.
+     *
+     * @param lock whether the ScopedWakelock should be locked before it's returned.
+     * @return the created ScopedWakelock
+     */
+    virtual ScopedWakelock createScopedWakelock(bool lock) = 0;
+};
+
+/**
+ * ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with
+ * multihal and in order for the HalProxy to successfully load and communicate with the sub-HAL.
+ *
+ * Any vendor wishing to implement this interface and support multihal will need to create a
+ * dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by
+ * the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's
+ * implementation of sensorsHalGetSubHal.
+ *
+ * With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec.
+ * Any sensor handles given to the HalProxy, either through getSensorsList() or the
+ * onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL
+ * handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and
+ * sub-HALs can continue to use the lower 3 bytes of the handle.
+ */
+class ISensorsSubHal : public ISensors {
+  public:
+    // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement
+    // the version below to allow communciation logic to centralized in the HalProxy
+    Return<V1_0::Result> initialize_2_1(
+            const ::android::hardware::MQDescriptorSync<V2_1::Event>& /* eventQueueDescriptor */,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& /* wakeLockDescriptor */,
+            const sp<ISensorsCallback>& /* sensorsCallback */) final {
+        return V1_0::Result::INVALID_OPERATION;
+    }
+
+    Return<V1_0::Result> initialize(
+            const ::android::hardware::MQDescriptorSync<V1_0::Event>& /* eventQueueDescriptor */,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& /* wakeLockDescriptor */,
+            const sp<V2_0::ISensorsCallback>& /* sensorsCallback */) final {
+        return V1_0::Result::INVALID_OPERATION;
+    }
+
+    // Several HAL 2.0 methods won't be invoked on HAL 2.1 so they are stubbed out below.
+    Return<void> getSensorsList(getSensorsList_cb /* _hidl_cb */) final { return Void(); }
+
+    Return<V1_0::Result> injectSensorData(const V1_0::Event& /* event */) final {
+        return V1_0::Result::INVALID_OPERATION;
+    }
+
+    /**
+     * Method defined in ::android::hidl::base::V1_0::IBase.
+     *
+     * This method should write debug information to hidl_handle that is useful for debugging
+     * issues. Suggestions include:
+     * - Sensor info including handle values and any other state available in the SensorInfo class
+     * - List of active sensors and their current sampling period and reporting latency
+     * - Information about pending flush requests
+     * - Current operating mode
+     * - Currently registered direct channel info
+     * - A history of any of the above
+     */
+    virtual Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) = 0;
+
+    /**
+     * @return A human-readable name for use in wake locks and logging.
+     */
+    virtual const std::string getName() = 0;
+
+    /**
+     * This is the first method invoked on the sub-HAL after it's allocated through
+     * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and
+     * retain the callback given in order to communicate with the HalProxy. Method will be called
+     * anytime the sensors framework restarts. Therefore, this method will be responsible for
+     * reseting the state of the subhal and cleaning up and reallocating any previously allocated
+     * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state
+     * as well.
+     *
+     * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state
+     *     changes, new sensor events should be sent to the framework, and when a new ScopedWakelock
+     *     should be created.
+     * @return result OK on success
+     */
+    virtual Return<V1_0::Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) = 0;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+/**
+ * Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic
+ * library. This function will only be invoked once at initialization time.
+ *
+ * NOTE: The supported sensors HAL version must match SUB_HAL_2_1_VERSION or the HalProxy
+ *     will fail to initialize.
+ *
+ * @param uint32_t when this function returns, this parameter must contain the HAL version that
+ *     this sub-HAL supports. This must be set to SUB_HAL_2_1_VERSION.
+ * @return A statically allocated, valid ISensorsSubHal implementation.
+ */
+__attribute__((visibility(
+        "default"))) extern "C" ::android::hardware::sensors::V2_1::implementation::ISensorsSubHal*
+sensorsHalGetSubHal_2_1(uint32_t* version);
diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp
new file mode 100644
index 0000000..a15faed
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/tests/Android.bp
@@ -0,0 +1,121 @@
+//
+// 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_defaults {
+    name: "android.hardware.sensors@2.X-fakesubhal-defaults",
+    srcs: [
+        "fake_subhal/*.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.0-multihal.header",
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    export_include_dirs: ["fake_subhal"],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.0-ScopedWakelock",
+        "android.hardware.sensors@2.1",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.X-multihal",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"FakeSubHal\"",
+    ],
+}
+
+cc_library {
+    name: "android.hardware.sensors@2.X-fakesubhal-config1",
+    vendor: true,
+    defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"],
+    cflags: [
+        "-DSUB_HAL_VERSION_2_0",
+        "-DSUPPORT_CONTINUOUS_SENSORS",
+        "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"",
+    ],
+}
+
+cc_library {
+    name: "android.hardware.sensors@2.X-fakesubhal-config2",
+    vendor: true,
+    defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"],
+    cflags: [
+        "-DSUB_HAL_VERSION_2_0",
+        "-DSUPPORT_ON_CHANGE_SENSORS",
+        "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"",
+    ],
+}
+
+cc_library {
+    name: "android.hardware.sensors@2.X-fakesubhal-config3",
+    vendor: true,
+    defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"],
+    cflags: [
+        "-DSUPPORT_ON_CHANGE_SENSORS",
+        "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"",
+    ],
+}
+
+cc_test_library {
+    name: "android.hardware.sensors@2.X-fakesubhal-unittest",
+    vendor_available: true,
+    defaults: ["android.hardware.sensors@2.X-fakesubhal-defaults"],
+    cflags: [
+        "-DSUPPORT_ON_CHANGE_SENSORS",
+        "-DSUPPORT_CONTINUOUS_SENSORS",
+        "-DSUB_HAL_NAME=\"FakeSubHal-Test\"",
+    ],
+}
+
+cc_test {
+    name: "android.hardware.sensors@2.X-halproxy-unit-tests",
+    srcs: ["HalProxy_test.cpp"],
+    vendor: true,
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.0-ScopedWakelock.testlib",
+        "android.hardware.sensors@2.X-multihal",
+        "android.hardware.sensors@2.X-fakesubhal-unittest",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    test_suites: ["device-tests"],
+    cflags: [
+        "-DLOG_TAG=\"HalProxyUnitTests\"",
+    ],
+}
diff --git a/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp
new file mode 100644
index 0000000..858786a
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp
@@ -0,0 +1,936 @@
+//
+// 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 <gtest/gtest.h>
+
+#include <android/hardware/sensors/1.0/types.h>
+#include <android/hardware/sensors/2.0/types.h>
+#include <android/hardware/sensors/2.1/types.h>
+#include <fmq/MessageQueue.h>
+
+#include "HalProxy.h"
+#include "SensorsSubHal.h"
+#include "V2_0/ScopedWakelock.h"
+#include "convertV2_1.h"
+
+#include <chrono>
+#include <set>
+#include <thread>
+#include <vector>
+
+namespace {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Return;
+using ::android::hardware::sensors::V1_0::EventPayload;
+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::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::HalProxyCallbackBase;
+using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
+using ::android::hardware::sensors::V2_1::implementation::convertToNewEvents;
+using ::android::hardware::sensors::V2_1::implementation::convertToNewSensorInfos;
+using ::android::hardware::sensors::V2_1::implementation::HalProxy;
+using ::android::hardware::sensors::V2_1::subhal::implementation::AddAndRemoveDynamicSensorsSubHal;
+using ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal;
+using ::android::hardware::sensors::V2_1::subhal::implementation::
+        AllSupportDirectChannelSensorsSubHal;
+using ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal;
+using ::android::hardware::sensors::V2_1::subhal::implementation::
+        DoesNotSupportDirectChannelSensorsSubHal;
+using ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal;
+using ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0;
+using ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1;
+using ::android::hardware::sensors::V2_1::subhal::implementation::
+        SetOperationModeFailingSensorsSubHal;
+
+using ISensorsCallbackV2_0 = ::android::hardware::sensors::V2_0::ISensorsCallback;
+using ISensorsCallbackV2_1 = ::android::hardware::sensors::V2_1::ISensorsCallback;
+using EventV1_0 = ::android::hardware::sensors::V1_0::Event;
+using EventV2_1 = ::android::hardware::sensors::V2_1::Event;
+using EventMessageQueueV2_1 = MessageQueue<EventV2_1, ::android::hardware::kSynchronizedReadWrite>;
+using EventMessageQueueV2_0 = MessageQueue<EventV1_0, ::android::hardware::kSynchronizedReadWrite>;
+using WakeupMessageQueue = MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite>;
+
+// The barebones sensors callback class passed into halproxy initialize calls
+class SensorsCallback : public ISensorsCallbackV2_0 {
+  public:
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo>& /*dynamicSensorsAdded*/) override {
+        // Nothing yet
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& /*dynamicSensorHandlesRemoved*/) override {
+        // Nothing yet
+        return Return<void>();
+    }
+};
+
+class SensorsCallbackV2_1 : public ISensorsCallbackV2_1 {
+  public:
+    Return<void> onDynamicSensorsConnected_2_1(
+            const hidl_vec<::android::hardware::sensors::V2_1::SensorInfo>& /*dynamicSensorsAdded*/)
+            override {
+        // Nothing yet
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo>& /*dynamicSensorsAdded*/) override {
+        // Nothing yet
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& /*dynamicSensorHandlesRemoved*/) override {
+        // Nothing yet
+        return Return<void>();
+    }
+};
+
+// The sensors callback that expects a variable list of sensors to be added
+class TestSensorsCallback : public ISensorsCallbackV2_0 {
+  public:
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+        mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(),
+                                 dynamicSensorsAdded.end());
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+        mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(),
+                                          dynamicSensorHandlesRemoved.begin(),
+                                          dynamicSensorHandlesRemoved.end());
+        return Return<void>();
+    }
+
+    const std::vector<SensorInfo>& getSensorsConnected() const { return mSensorsConnected; }
+    const std::vector<int32_t>& getSensorHandlesDisconnected() const {
+        return mSensorHandlesDisconnected;
+    }
+
+  private:
+    std::vector<SensorInfo> mSensorsConnected;
+    std::vector<int32_t> mSensorHandlesDisconnected;
+};
+
+// Helper declarations follow
+
+/**
+ * Tests that for each SensorInfo object from a proxy getSensorsList call each corresponding
+ * object from a subhal getSensorsList call has the same type and its last 3 bytes are the
+ * same for sensorHandle field.
+ *
+ * @param proxySensorsList The list of SensorInfo objects from the proxy.getSensorsList callback.
+ * @param subHalSenosrsList The list of SensorInfo objects from the subHal.getSensorsList callback.
+ */
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+                                       const std::vector<SensorInfo>& subHalSensorsList);
+
+/**
+ * Tests that there is exactly one subhal that allows its sensors to have direct channel enabled.
+ * Therefore, all SensorInfo objects that are not from the enabled subhal should be disabled for
+ * direct channel.
+ *
+ * @param sensorsList The SensorInfo object list from proxy.getSensorsList call.
+ * @param enabledSubHalIndex The index of the subhal in the halproxy that is expected to be
+ *     enabled.
+ */
+void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
+                                                     size_t enabledSubHalIndex);
+
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+                               EventFlag* wakelockQueueFlag);
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueueV2_0>& eventQueue,
+                          EventFlag* eventQueueFlag);
+
+std::unique_ptr<EventMessageQueueV2_0> makeEventFMQ(size_t size);
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size);
+
+/**
+ * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
+ *    which is a wakeup type sensor.
+ *
+ * @return A proximity event.
+ */
+EventV1_0 makeProximityEvent();
+
+/**
+ * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
+ *    which is a wakeup type sensor.
+ *
+ * @return A proximity event.
+ */
+EventV1_0 makeAccelerometerEvent();
+
+/**
+ * Make a certain number of proximity type events with the sensorHandle field set to
+ * the proper number for AllSensorsSubHal subhal type.
+ *
+ * @param numEvents The number of events to make.
+ *
+ * @return The created list of events.
+ */
+std::vector<EventV1_0> makeMultipleProximityEvents(size_t numEvents);
+
+/**
+ * Make a certain number of accelerometer type events with the sensorHandle field set to
+ * the proper number for AllSensorsSubHal subhal type.
+ *
+ * @param numEvents The number of events to make.
+ *
+ * @return The created list of events.
+ */
+std::vector<EventV1_0> makeMultipleAccelerometerEvents(size_t numEvents);
+
+/**
+ * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo
+ * objects that have the sensorHandle property set to int32_ts from start to start + size
+ * (exclusive) and push those sensorHandles also onto 'sensorHandles'.
+ *
+ * @param start The starting sensorHandle value.
+ * @param size The ending (not included) sensorHandle value.
+ * @param sensors The SensorInfo object vector reference to push_back to.
+ * @param sensorHandles The sensor handles int32_t vector reference to push_back to.
+ */
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+                                                  std::vector<SensorInfo>& sensors,
+                                                  std::vector<int32_t>& sensorHandles);
+
+// Tests follow
+TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal};
+    HalProxy proxy(fakeSubHals);
+
+    proxy.getSensorsList([&](const auto& proxySensorsList) {
+        subHal.getSensorsList([&](const auto& subHalSensorsList) {
+            testSensorsListFromProxyAndSubHal(proxySensorsList, subHalSensorsList);
+        });
+    });
+}
+
+TEST(HalProxyTest, GetSensorsListTwoSubHalTest) {
+    ContinuousSensorsSubHal<SensorsSubHalV2_0> continuousSubHal;
+    OnChangeSensorsSubHal<SensorsSubHalV2_0> onChangeSubHal;
+    std::vector<ISensorsSubHal*> fakeSubHals;
+    fakeSubHals.push_back(&continuousSubHal);
+    fakeSubHals.push_back(&onChangeSubHal);
+    HalProxy proxy(fakeSubHals);
+
+    std::vector<SensorInfo> proxySensorsList, combinedSubHalSensorsList;
+
+    proxy.getSensorsList([&](const auto& list) { proxySensorsList = list; });
+    continuousSubHal.getSensorsList([&](const auto& list) {
+        combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+    });
+    onChangeSubHal.getSensorsList([&](const auto& list) {
+        combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+    });
+
+    testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList);
+}
+
+TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) {
+    ContinuousSensorsSubHal<SensorsSubHalV2_0> subHal1;
+    OnChangeSensorsSubHal<SensorsSubHalV2_0> subHal2;
+
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+    HalProxy proxy(fakeSubHals);
+
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+
+    Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+    EXPECT_EQ(result, Result::OK);
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::DATA_INJECTION);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::DATA_INJECTION);
+}
+
+TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) {
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal1;
+    SetOperationModeFailingSensorsSubHal subHal2;
+
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+    HalProxy proxy(fakeSubHals);
+
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+
+    Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+    EXPECT_NE(result, Result::OK);
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+}
+
+TEST(HalProxyTest, InitDirectChannelTwoSubHalsUnitTest) {
+    AllSupportDirectChannelSensorsSubHal subHal1;
+    AllSupportDirectChannelSensorsSubHal subHal2;
+
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+    HalProxy proxy(fakeSubHals);
+
+    proxy.getSensorsList([&](const auto& sensorsList) {
+        testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0);
+    });
+}
+
+TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) {
+    DoesNotSupportDirectChannelSensorsSubHal subHal1;
+    AllSupportDirectChannelSensorsSubHal subHal2, subHal3;
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2, &subHal3};
+    HalProxy proxy(fakeSubHals);
+
+    proxy.getSensorsList([&](const auto& sensorsList) {
+        testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1);
+    });
+}
+
+TEST(HalProxyTest, PostSingleNonWakeupEvent) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<EventV1_0> events{makeAccelerometerEvent()};
+    subHal.postEvents(convertToNewEvents(events), false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), 1);
+}
+
+TEST(HalProxyTest, PostMultipleNonWakeupEvent) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 3;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<EventV1_0> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal.postEvents(convertToNewEvents(events), false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+}
+
+TEST(HalProxyTest, PostSingleWakeupEvent) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    EventFlag* eventQueueFlag;
+    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+    EventFlag* wakelockQueueFlag;
+    EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
+    std::vector<EventV1_0> events{makeProximityEvent()};
+    subHal.postEvents(convertToNewEvents(events), true /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), 1);
+
+    readEventsOutOfQueue(1, eventQueue, eventQueueFlag);
+    ackWakeupEventsToHalProxy(1, wakeLockQueue, wakelockQueueFlag);
+}
+
+TEST(HalProxyTest, PostMultipleWakeupEvents) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 3;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    EventFlag* eventQueueFlag;
+    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+    EventFlag* wakelockQueueFlag;
+    EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
+    std::vector<EventV1_0> events = makeMultipleProximityEvents(kNumEvents);
+    subHal.postEvents(convertToNewEvents(events), true /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+    readEventsOutOfQueue(kNumEvents, eventQueue, eventQueueFlag);
+    ackWakeupEventsToHalProxy(kNumEvents, wakeLockQueue, wakelockQueueFlag);
+}
+
+TEST(HalProxyTest, PostEventsMultipleSubhals) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 2;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<EventV1_0> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal1.postEvents(convertToNewEvents(events), false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+    subHal2.postEvents(convertToNewEvents(events), false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+TEST(HalProxyTest, PostEventsDelayedWrite) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 6;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    EventFlag* eventQueueFlag;
+    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+    std::vector<EventV1_0> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal1.postEvents(convertToNewEvents(events), false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
+
+    // readblock a full queue size worth of events out of queue, timeout for half a second
+    EXPECT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
+
+    // proxy background thread should have wrote remaining events when it saw space
+    EXPECT_TRUE(readEventsOutOfQueue(kNumEvents - kQueueSize, eventQueue, eventQueueFlag));
+
+    EXPECT_EQ(eventQueue->availableToRead(), 0);
+}
+
+TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 2;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<EventV1_0> events = makeMultipleAccelerometerEvents(kNumEvents);
+
+    std::thread t1(&AllSensorsSubHal<SensorsSubHalV2_0>::postEvents, &subHal1,
+                   convertToNewEvents(events), false);
+    std::thread t2(&AllSensorsSubHal<SensorsSubHalV2_0>::postEvents, &subHal2,
+                   convertToNewEvents(events), false);
+
+    t1.join();
+    t2.join();
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 6;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<EventV1_0> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal.postEvents(convertToNewEvents(events), false /* wakeup */);
+
+    // Destructing HalProxy object with events on the background thread
+}
+
+TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<EventV1_0> events{makeProximityEvent()};
+    subHal.postEvents(convertToNewEvents(events), true /* wakeup */);
+
+    // Not sending any acks back through wakeLockQueue
+
+    // Destructing HalProxy object with unacked wakeup events posted
+}
+
+TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 10;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<EventV1_0> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal.postEvents(convertToNewEvents(events), false /* wakeup */);
+
+    eventQueue = makeEventFMQ(kQueueSize);
+    wakeLockQueue = makeWakelockFMQ(kQueueSize);
+
+    Result secondInitResult =
+            proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+    EXPECT_EQ(secondInitResult, Result::OK);
+    // Small sleep so that pending writes thread has a change to hit writeBlocking call.
+    std::this_thread::sleep_for(std::chrono::milliseconds(5));
+    EventV1_0 eventOut;
+    EXPECT_FALSE(eventQueue->read(&eventOut));
+}
+
+TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<EventV1_0> events{makeProximityEvent()};
+    subHal.postEvents(convertToNewEvents(events), true /* wakeup */);
+
+    // Not sending any acks back through wakeLockQueue
+
+    eventQueue = makeEventFMQ(kQueueSize);
+    wakeLockQueue = makeWakelockFMQ(kQueueSize);
+
+    Result secondInitResult =
+            proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+    EXPECT_EQ(secondInitResult, Result::OK);
+}
+
+TEST(HalProxyTest, InitializeManyTimesInARow) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumTimesToInit = 100;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+
+    for (size_t i = 0; i < kNumTimesToInit; i++) {
+        Result secondInitResult =
+                proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+        EXPECT_EQ(secondInitResult, Result::OK);
+    }
+}
+
+TEST(HalProxyTest, OperationModeResetOnInitialize) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.setOperationMode(OperationMode::DATA_INJECTION);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+    EventV1_0 event = makeAccelerometerEvent();
+    // Should not be able to inject a non AdditionInfo type event because operation mode should
+    // have been reset to NORMAL
+    EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
+}
+
+TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumSensors = 5;
+    AddAndRemoveDynamicSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    HalProxy proxy(subHals);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToAttemptToRemove;
+    makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToAttemptToRemove);
+
+    std::vector<int32_t> nonDynamicSensorHandles;
+    for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+        nonDynamicSensorHandles.push_back(sensorHandle);
+    }
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallbackV2_0> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect));
+
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+    std::vector<int32_t> sensorHandlesActuallyRemoved = callback->getSensorHandlesDisconnected();
+
+    // Should not have received the sensorHandles for any dynamic sensors that were removed since
+    // all of them should have been removed in the second initialize call.
+    EXPECT_TRUE(sensorHandlesActuallyRemoved.empty());
+}
+
+TEST(HalProxyTest, DynamicSensorsConnectedTest) {
+    constexpr size_t kNumSensors = 3;
+    AddAndRemoveDynamicSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(0);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToExpect;
+    makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToExpect);
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallbackV2_0> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect));
+
+    std::vector<SensorInfo> sensorsSeen = callback->getSensorsConnected();
+    EXPECT_EQ(kNumSensors, sensorsSeen.size());
+    for (size_t i = 0; i < kNumSensors; i++) {
+        auto sensorHandleSeen = sensorsSeen[i].sensorHandle;
+        // Note since only one subhal we do not need to change first byte for expected
+        auto sensorHandleExpected = sensorHandlesToExpect[i];
+        EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
+    }
+}
+
+TEST(HalProxyTest, DynamicSensorsDisconnectedTest) {
+    constexpr size_t kNumSensors = 3;
+    AddAndRemoveDynamicSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(0);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToExpect;
+    makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToExpect);
+
+    std::vector<int32_t> nonDynamicSensorHandles;
+    for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+        nonDynamicSensorHandles.push_back(sensorHandle);
+    }
+
+    std::set<int32_t> nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(),
+                                                 nonDynamicSensorHandles.end());
+
+    std::vector<int32_t> sensorHandlesToAttemptToRemove;
+    sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+                                          sensorHandlesToExpect.begin(),
+                                          sensorHandlesToExpect.end());
+    sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+                                          nonDynamicSensorHandles.begin(),
+                                          nonDynamicSensorHandles.end());
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallbackV2_0> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(convertToNewSensorInfos(sensorsToConnect));
+    subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+    std::vector<int32_t> sensorHandlesSeen = callback->getSensorHandlesDisconnected();
+    EXPECT_EQ(kNumSensors, sensorHandlesSeen.size());
+    for (size_t i = 0; i < kNumSensors; i++) {
+        auto sensorHandleSeen = sensorHandlesSeen[i];
+        // Note since only one subhal we do not need to change first byte for expected
+        auto sensorHandleExpected = sensorHandlesToExpect[i];
+        EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
+        EXPECT_TRUE(nonDynamicSensorHandlesSet.find(sensorHandleSeen) ==
+                    nonDynamicSensorHandlesSet.end());
+    }
+}
+
+TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) {
+    constexpr size_t kNumSubHals = 3;
+    constexpr size_t kQueueSize = 5;
+    int32_t kNumSubHalsInt32 = static_cast<int32_t>(kNumSubHals);
+    std::vector<AllSensorsSubHal<SensorsSubHalV2_0>> subHalObjs(kNumSubHals);
+    std::vector<ISensorsSubHal*> subHals;
+    for (const auto& subHal : subHalObjs) {
+        subHals.push_back((ISensorsSubHal*)(&subHal));
+    }
+
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    // Initialize for the injectSensorData call so callback postEvents is valid
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    // For testing proxy.injectSensorData properly
+    proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+    // kNumSubHalsInt32 index is one off the end of mSubHalList in proxy object
+    EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE);
+    EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE);
+    EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE);
+    EventV1_0 event;
+    event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24);
+    EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
+}
+
+TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) {
+    constexpr size_t kQueueSize = 5;
+    constexpr int32_t subhal1Index = 0;
+    constexpr int32_t subhal2Index = 1;
+    AllSensorsSubHal<SensorsSubHalV2_0> subhal1;
+    AllSensorsSubHal<SensorsSubHalV2_0> subhal2;
+    std::vector<ISensorsSubHal*> subHals{&subhal1, &subhal2};
+
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    int32_t sensorHandleToPost = 0x00000001;
+    EventV1_0 eventIn = makeAccelerometerEvent();
+    eventIn.sensorHandle = sensorHandleToPost;
+    std::vector<EventV1_0> eventsToPost{eventIn};
+    subhal1.postEvents(convertToNewEvents(eventsToPost), false);
+
+    EventV1_0 eventOut;
+    EXPECT_TRUE(eventQueue->read(&eventOut));
+
+    EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost);
+
+    subhal2.postEvents(convertToNewEvents(eventsToPost), false);
+
+    EXPECT_TRUE(eventQueue->read(&eventOut));
+
+    EXPECT_EQ(eventOut.sensorHandle, (subhal2Index << 24) | sensorHandleToPost);
+}
+
+TEST(HalProxyTest, FillAndDrainPendingQueueTest) {
+    constexpr size_t kQueueSize = 5;
+    // TODO: Make this constant linked to same limit in HalProxy.h
+    constexpr size_t kMaxPendingQueueSize = 100000;
+    AllSensorsSubHal<SensorsSubHalV2_0> subhal;
+    std::vector<ISensorsSubHal*> subHals{&subhal};
+
+    std::unique_ptr<EventMessageQueueV2_0> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_0> callback = new SensorsCallback();
+    EventFlag* eventQueueFlag;
+    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    // Fill pending queue
+    std::vector<EventV1_0> events = makeMultipleAccelerometerEvents(kQueueSize);
+    subhal.postEvents(convertToNewEvents(events), false);
+    events = makeMultipleAccelerometerEvents(kMaxPendingQueueSize);
+    subhal.postEvents(convertToNewEvents(events), false);
+
+    // Drain pending queue
+    for (int i = 0; i < kMaxPendingQueueSize + kQueueSize; i += kQueueSize) {
+        ASSERT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
+    }
+
+    // Put one event on pending queue
+    events = makeMultipleAccelerometerEvents(kQueueSize);
+    subhal.postEvents(convertToNewEvents(events), false);
+    events = {makeAccelerometerEvent()};
+    subhal.postEvents(convertToNewEvents(events), false);
+
+    // Read out to make room for one event on pending queue to write to FMQ
+    ASSERT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
+
+    // Should be able to read that last event off queue
+    EXPECT_TRUE(readEventsOutOfQueue(1, eventQueue, eventQueueFlag));
+}
+
+TEST(HalProxyTest, PostEventsMultipleSubhalsThreadedV2_1) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 2;
+    AllSensorsSubHal<SensorsSubHalV2_0> subHal1;
+    AllSensorsSubHal<SensorsSubHalV2_1> subHal2;
+    std::vector<::android::hardware::sensors::V2_0::implementation::ISensorsSubHal*> subHalsV2_0{
+            &subHal1};
+    std::vector<::android::hardware::sensors::V2_1::implementation::ISensorsSubHal*> subHalsV2_1{
+            &subHal2};
+    HalProxy proxy(subHalsV2_0, subHalsV2_1);
+    std::unique_ptr<EventMessageQueueV2_1> eventQueue =
+            std::make_unique<EventMessageQueueV2_1>(kQueueSize, true);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallbackV2_1> callback = new SensorsCallbackV2_1();
+    proxy.initialize_2_1(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<EventV1_0> events = makeMultipleAccelerometerEvents(kNumEvents);
+
+    std::thread t1(&AllSensorsSubHal<SensorsSubHalV2_0>::postEvents, &subHal1,
+                   convertToNewEvents(events), false);
+    std::thread t2(&AllSensorsSubHal<SensorsSubHalV2_1>::postEvents, &subHal2,
+                   convertToNewEvents(events), false);
+
+    t1.join();
+    t2.join();
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+// Helper implementations follow
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+                                       const std::vector<SensorInfo>& subHalSensorsList) {
+    EXPECT_EQ(proxySensorsList.size(), subHalSensorsList.size());
+
+    for (size_t i = 0; i < proxySensorsList.size(); i++) {
+        const SensorInfo& proxySensor = proxySensorsList[i];
+        const SensorInfo& subHalSensor = subHalSensorsList[i];
+
+        EXPECT_EQ(proxySensor.type, subHalSensor.type);
+        EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle);
+    }
+}
+
+void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
+                                                     size_t enabledSubHalIndex) {
+    for (const SensorInfo& sensor : sensorsList) {
+        size_t subHalIndex = static_cast<size_t>(sensor.sensorHandle >> 24);
+        if (subHalIndex == enabledSubHalIndex) {
+            // First subhal should have been picked as the direct channel subhal
+            // and so have direct channel enabled on all of its sensors
+            EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
+            EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
+        } else {
+            // All other subhals should have direct channel disabled for all sensors
+            EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
+            EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
+        }
+    }
+}
+
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+                               EventFlag* wakelockQueueFlag) {
+    uint32_t numEventsUInt32 = static_cast<uint32_t>(numEvents);
+    wakelockQueue->write(&numEventsUInt32);
+    wakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+}
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueueV2_0>& eventQueue,
+                          EventFlag* eventQueueFlag) {
+    constexpr int64_t kReadBlockingTimeout = INT64_C(500000000);
+    std::vector<EventV1_0> events(numEvents);
+    return eventQueue->readBlocking(events.data(), numEvents,
+                                    static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+                                    static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+                                    kReadBlockingTimeout, eventQueueFlag);
+}
+
+std::unique_ptr<EventMessageQueueV2_0> makeEventFMQ(size_t size) {
+    return std::make_unique<EventMessageQueueV2_0>(size, true);
+}
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size) {
+    return std::make_unique<WakeupMessageQueue>(size, true);
+}
+
+EventV1_0 makeProximityEvent() {
+    EventV1_0 event;
+    event.timestamp = 0xFF00FF00;
+    // This is the sensorhandle of proximity, which is wakeup type
+    event.sensorHandle = 0x00000008;
+    event.sensorType = SensorType::PROXIMITY;
+    event.u = EventPayload();
+    return event;
+}
+
+EventV1_0 makeAccelerometerEvent() {
+    EventV1_0 event;
+    event.timestamp = 0xFF00FF00;
+    // This is the sensorhandle of proximity, which is wakeup type
+    event.sensorHandle = 0x00000001;
+    event.sensorType = SensorType::ACCELEROMETER;
+    event.u = EventPayload();
+    return event;
+}
+
+std::vector<EventV1_0> makeMultipleProximityEvents(size_t numEvents) {
+    std::vector<EventV1_0> events;
+    for (size_t i = 0; i < numEvents; i++) {
+        events.push_back(makeProximityEvent());
+    }
+    return events;
+}
+
+std::vector<EventV1_0> makeMultipleAccelerometerEvents(size_t numEvents) {
+    std::vector<EventV1_0> events;
+    for (size_t i = 0; i < numEvents; i++) {
+        events.push_back(makeAccelerometerEvent());
+    }
+    return events;
+}
+
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+                                                  std::vector<SensorInfo>& sensors,
+                                                  std::vector<int32_t>& sensorHandles) {
+    for (int32_t sensorHandle = start; sensorHandle < start + static_cast<int32_t>(size);
+         sensorHandle++) {
+        SensorInfo sensor;
+        // Just set the sensorHandle field to the correct value so as to not have
+        // to compare every field
+        sensor.sensorHandle = sensorHandle;
+        sensors.push_back(sensor);
+        sensorHandles.push_back(sensorHandle);
+    }
+}
+
+}  // namespace
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h
new file mode 100644
index 0000000..4542bfd
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/IHalProxyCallbackWrapper.h
@@ -0,0 +1,107 @@
+/*
+ * 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 "V2_0/SubHal.h"
+#include "V2_1/SubHal.h"
+#include "convertV2_1.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace subhal {
+namespace implementation {
+
+/**
+ * The following callback wrapper classes abstract away common functionality across V2.0 and V2.1
+ * interfaces. Much of the logic is common between the two versions and this allows users of the
+ * classes to only care about the type used at initialization and then interact with either version
+ * of the callback interface without worrying about the type.
+ */
+class IHalProxyCallbackWrapperBase {
+  protected:
+    using ScopedWakelock = V2_0::implementation::ScopedWakelock;
+
+  public:
+    virtual ~IHalProxyCallbackWrapperBase() {}
+
+    virtual Return<void> onDynamicSensorsConnected(
+            const hidl_vec<V2_1::SensorInfo>& sensorInfos) = 0;
+
+    virtual Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& sensorHandles) = 0;
+
+    virtual void postEvents(const std::vector<V2_1::Event>& events, ScopedWakelock wakelock) = 0;
+
+    virtual ScopedWakelock createScopedWakelock(bool lock) = 0;
+};
+
+template <typename T>
+class HalProxyCallbackWrapperBase : public IHalProxyCallbackWrapperBase {
+  public:
+    HalProxyCallbackWrapperBase(sp<T> callback) : mCallback(callback){};
+
+    Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& sensorHandles) override {
+        return mCallback->onDynamicSensorsDisconnected(sensorHandles);
+    }
+
+    ScopedWakelock createScopedWakelock(bool lock) override {
+        return mCallback->createScopedWakelock(lock);
+    }
+
+  protected:
+    sp<T> mCallback;
+};
+
+class HalProxyCallbackWrapperV2_0
+    : public HalProxyCallbackWrapperBase<V2_0::implementation::IHalProxyCallback> {
+  public:
+    HalProxyCallbackWrapperV2_0(sp<V2_0::implementation::IHalProxyCallback> callback)
+        : HalProxyCallbackWrapperBase(callback){};
+
+    Return<void> onDynamicSensorsConnected(const hidl_vec<V2_1::SensorInfo>& sensorInfos) override {
+        return mCallback->onDynamicSensorsConnected(
+                V2_1::implementation::convertToOldSensorInfos(sensorInfos));
+    }
+
+    void postEvents(const std::vector<V2_1::Event>& events, ScopedWakelock wakelock) override {
+        return mCallback->postEvents(V2_1::implementation::convertToOldEvents(events),
+                                     std::move(wakelock));
+    }
+};
+
+class HalProxyCallbackWrapperV2_1
+    : public HalProxyCallbackWrapperBase<V2_1::implementation::IHalProxyCallback> {
+  public:
+    HalProxyCallbackWrapperV2_1(sp<V2_1::implementation::IHalProxyCallback> callback)
+        : HalProxyCallbackWrapperBase(callback){};
+
+    Return<void> onDynamicSensorsConnected(const hidl_vec<V2_1::SensorInfo>& sensorInfos) override {
+        return mCallback->onDynamicSensorsConnected_2_1(sensorInfos);
+    }
+
+    void postEvents(const std::vector<V2_1::Event>& events, ScopedWakelock wakelock) {
+        return mCallback->postEvents(events, std::move(wakelock));
+    }
+};
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/README b/sensors/common/default/2.X/multihal/tests/fake_subhal/README
similarity index 100%
rename from sensors/2.0/multihal/tests/fake_subhal/README
rename to sensors/common/default/2.X/multihal/tests/fake_subhal/README
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
new file mode 100644
index 0000000..1efd971
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
@@ -0,0 +1,354 @@
+/*
+ * 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 "Sensor.h"
+
+#include <hardware/sensors.h>
+#include <utils/SystemClock.h>
+
+#include <cmath>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace subhal {
+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;
+using ::android::hardware::sensors::V2_1::Event;
+using ::android::hardware::sensors::V2_1::SensorInfo;
+using ::android::hardware::sensors::V2_1::SensorType;
+
+Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : mIsEnabled(false),
+      mSamplingPeriodNs(0),
+      mLastSampleTimeNs(0),
+      mCallback(callback),
+      mMode(OperationMode::NORMAL) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    constexpr float kDefaultMaxDelayUs = 1000 * 1000;
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = 0;
+    mRunThread = std::thread(startThread, this);
+}
+
+Sensor::~Sensor() {
+    // Ensure that lock is unlocked before calling mRunThread.join() or a
+    // deadlock will occur.
+    {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mStopThread = true;
+        mIsEnabled = false;
+        mWaitCV.notify_all();
+    }
+    mRunThread.join();
+}
+
+const SensorInfo& Sensor::getSensorInfo() const {
+    return mSensorInfo;
+}
+
+void Sensor::batch(int32_t samplingPeriodNs) {
+    samplingPeriodNs =
+            std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000);
+
+    if (mSamplingPeriodNs != samplingPeriodNs) {
+        mSamplingPeriodNs = samplingPeriodNs;
+        // Wake up the 'run' thread to check if a new event should be generated now
+        mWaitCV.notify_all();
+    }
+}
+
+void Sensor::activate(bool enable) {
+    if (mIsEnabled != enable) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mIsEnabled = enable;
+        mWaitCV.notify_all();
+    }
+}
+
+Result Sensor::flush() {
+    // Only generate a flush complete event if the sensor is enabled and if the sensor is not a
+    // one-shot sensor.
+    if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) {
+        return Result::BAD_VALUE;
+    }
+
+    // Note: If a sensor supports batching, write all of the currently batched events for the sensor
+    // to the Event FMQ prior to writing the flush complete event.
+    Event ev;
+    ev.sensorHandle = mSensorInfo.sensorHandle;
+    ev.sensorType = SensorType::META_DATA;
+    ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
+    std::vector<Event> evs{ev};
+    mCallback->postEvents(evs, isWakeUpSensor());
+
+    return Result::OK;
+}
+
+void Sensor::startThread(Sensor* sensor) {
+    sensor->run();
+}
+
+void Sensor::run() {
+    std::unique_lock<std::mutex> runLock(mRunMutex);
+    constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
+
+    while (!mStopThread) {
+        if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
+            mWaitCV.wait(runLock, [&] {
+                return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
+            });
+        } else {
+            timespec curTime;
+            clock_gettime(CLOCK_REALTIME, &curTime);
+            int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
+            int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+
+            if (now >= nextSampleTime) {
+                mLastSampleTimeNs = now;
+                nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+                mCallback->postEvents(readEvents(), isWakeUpSensor());
+            }
+
+            mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
+        }
+    }
+}
+
+bool Sensor::isWakeUpSensor() {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+}
+
+std::vector<Event> Sensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 0;
+    event.u.vec3.z = 0;
+    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+    events.push_back(event);
+    return events;
+}
+
+void Sensor::setOperationMode(OperationMode mode) {
+    if (mMode != mode) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mMode = mode;
+        mWaitCV.notify_all();
+    }
+}
+
+bool Sensor::supportsDataInjection() const {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
+}
+
+Result Sensor::injectEvent(const Event& event) {
+    Result result = Result::OK;
+    if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+        // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
+        // environment data into the device.
+    } else if (!supportsDataInjection()) {
+        result = Result::INVALID_OPERATION;
+    } else if (mMode == OperationMode::DATA_INJECTION) {
+        mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
+    } else {
+        result = Result::BAD_VALUE;
+    }
+    return result;
+}
+
+OnChangeSensor::OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : Sensor(sensorHandle, callback), mPreviousEventSet(false) {
+    mSensorInfo.flags |= SensorFlagBits::ON_CHANGE_MODE;
+}
+
+void OnChangeSensor::activate(bool enable) {
+    Sensor::activate(enable);
+    if (!enable) {
+        mPreviousEventSet = false;
+    }
+}
+
+std::vector<Event> OnChangeSensor::readEvents() {
+    std::vector<Event> events = Sensor::readEvents();
+    std::vector<Event> outputEvents;
+
+    for (auto iter = events.begin(); iter != events.end(); ++iter) {
+        Event ev = *iter;
+        if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) {
+            outputEvents.push_back(ev);
+            mPreviousEvent = ev;
+            mPreviousEventSet = true;
+        }
+    }
+    return outputEvents;
+}
+
+ContinuousSensor::ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : Sensor(sensorHandle, callback) {
+    mSensorInfo.flags |= SensorFlagBits::CONTINUOUS_MODE;
+}
+
+AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Accel Sensor";
+    mSensorInfo.type = SensorType::ACCELEROMETER;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_ACCELEROMETER;
+    mSensorInfo.maxRange = 78.4f;  // +/- 8g
+    mSensorInfo.resolution = 1.52e-5;
+    mSensorInfo.power = 0.001f;        // mA
+    mSensorInfo.minDelay = 20 * 1000;  // microseconds
+    mSensorInfo.flags |= SensorFlagBits::DATA_INJECTION;
+}
+
+std::vector<Event> AccelSensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 0;
+    event.u.vec3.z = -9.815;
+    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+    events.push_back(event);
+    return events;
+}
+
+PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Pressure Sensor";
+    mSensorInfo.type = SensorType::PRESSURE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PRESSURE;
+    mSensorInfo.maxRange = 1100.0f;     // hPa
+    mSensorInfo.resolution = 0.005f;    // hPa
+    mSensorInfo.power = 0.001f;         // mA
+    mSensorInfo.minDelay = 100 * 1000;  // microseconds
+}
+
+MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Magnetic Field Sensor";
+    mSensorInfo.type = SensorType::MAGNETIC_FIELD;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_MAGNETIC_FIELD;
+    mSensorInfo.maxRange = 1300.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;        // mA
+    mSensorInfo.minDelay = 20 * 1000;  // microseconds
+}
+
+LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Light Sensor";
+    mSensorInfo.type = SensorType::LIGHT;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_LIGHT;
+    mSensorInfo.maxRange = 43000.0f;
+    mSensorInfo.resolution = 10.0f;
+    mSensorInfo.power = 0.001f;         // mA
+    mSensorInfo.minDelay = 200 * 1000;  // microseconds
+}
+
+ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Proximity Sensor";
+    mSensorInfo.type = SensorType::PROXIMITY;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PROXIMITY;
+    mSensorInfo.maxRange = 5.0f;
+    mSensorInfo.resolution = 1.0f;
+    mSensorInfo.power = 0.012f;         // mA
+    mSensorInfo.minDelay = 200 * 1000;  // microseconds
+    mSensorInfo.flags |= SensorFlagBits::WAKE_UP;
+}
+
+GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Gyro Sensor";
+    mSensorInfo.type = SensorType::GYROSCOPE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_GYROSCOPE;
+    mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
+    mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 2.5f * 1000;  // microseconds
+}
+
+std::vector<Event> GyroSensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 0;
+    event.u.vec3.z = 0;
+    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+    events.push_back(event);
+    return events;
+}
+
+AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Ambient Temp Sensor";
+    mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
+    mSensorInfo.maxRange = 80.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+}
+
+DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Device Temp Sensor";
+    mSensorInfo.type = SensorType::TEMPERATURE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE;
+    mSensorInfo.maxRange = 80.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+}
+
+RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
+                                               ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Relative Humidity Sensor";
+    mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
+    mSensorInfo.maxRange = 100.0f;
+    mSensorInfo.resolution = 0.1f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+}
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h
new file mode 100644
index 0000000..5cf9f83
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/sensors/2.1/types.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V2_1::Event;
+using ::android::hardware::sensors::V2_1::SensorInfo;
+using ::android::hardware::sensors::V2_1::SensorType;
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace subhal {
+namespace implementation {
+
+class ISensorsEventCallback {
+  public:
+    virtual ~ISensorsEventCallback(){};
+    virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
+};
+
+class Sensor {
+  public:
+    Sensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+    virtual ~Sensor();
+
+    const SensorInfo& getSensorInfo() const;
+    void batch(int32_t samplingPeriodNs);
+    virtual void activate(bool enable);
+    Result flush();
+
+    void setOperationMode(OperationMode mode);
+    bool supportsDataInjection() const;
+    Result injectEvent(const Event& event);
+
+  protected:
+    void run();
+    virtual std::vector<Event> readEvents();
+    static void startThread(Sensor* sensor);
+
+    bool isWakeUpSensor();
+
+    bool mIsEnabled;
+    int64_t mSamplingPeriodNs;
+    int64_t mLastSampleTimeNs;
+    SensorInfo mSensorInfo;
+
+    std::atomic_bool mStopThread;
+    std::condition_variable mWaitCV;
+    std::mutex mRunMutex;
+    std::thread mRunThread;
+
+    ISensorsEventCallback* mCallback;
+
+    OperationMode mMode;
+};
+
+class OnChangeSensor : public Sensor {
+  public:
+    OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+    virtual void activate(bool enable) override;
+
+  protected:
+    virtual std::vector<Event> readEvents() override;
+
+  protected:
+    Event mPreviousEvent;
+    bool mPreviousEventSet;
+};
+
+class ContinuousSensor : public Sensor {
+  public:
+    ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class AccelSensor : public ContinuousSensor {
+  public:
+    AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    std::vector<Event> readEvents() override;
+};
+
+class GyroSensor : public ContinuousSensor {
+  public:
+    GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    std::vector<Event> readEvents() override;
+};
+
+class DeviceTempSensor : public ContinuousSensor {
+  public:
+    DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class PressureSensor : public ContinuousSensor {
+  public:
+    PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class MagnetometerSensor : public ContinuousSensor {
+  public:
+    MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class AmbientTempSensor : public OnChangeSensor {
+  public:
+    AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class LightSensor : public OnChangeSensor {
+  public:
+    LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class ProximitySensor : public OnChangeSensor {
+  public:
+    ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class RelativeHumiditySensor : public OnChangeSensor {
+  public:
+    RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp
new file mode 100644
index 0000000..20a4e9d
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp
@@ -0,0 +1,248 @@
+/*
+ * 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 "SensorsSubHal.h"
+
+#include <android/hardware/sensors/2.1/types.h>
+#include <log/log.h>
+
+#ifdef SUB_HAL_VERSION_2_0
+::android::hardware::sensors::V2_0::implementation::ISensorsSubHal* sensorsHalGetSubHal(
+        uint32_t* version) {
+#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+    static ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal<
+            ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0>
+            subHal;
+#elif defined SUPPORT_CONTINUOUS_SENSORS
+    static ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal<
+            ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0>
+            subHal;
+#elif defined SUPPORT_ON_CHANGE_SENSORS
+    static ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal<
+            ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0>
+            subHal;
+#else
+    static ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHal<
+            ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_0>
+            subHal;
+#endif  // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+    *version = SUB_HAL_2_0_VERSION;
+    return &subHal;
+}
+
+#else  // SUB_HAL_VERSION_2_0
+
+::android::hardware::sensors::V2_1::implementation::ISensorsSubHal* sensorsHalGetSubHal_2_1(
+        uint32_t* version) {
+#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+    static ::android::hardware::sensors::V2_1::subhal::implementation::AllSensorsSubHal<
+            ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1>
+            subHal;
+#elif defined SUPPORT_CONTINUOUS_SENSORS
+    static ::android::hardware::sensors::V2_1::subhal::implementation::ContinuousSensorsSubHal<
+            ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1>
+            subHal;
+#elif defined SUPPORT_ON_CHANGE_SENSORS
+    static ::android::hardware::sensors::V2_1::subhal::implementation::OnChangeSensorsSubHal<
+            ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1>
+            subHal;
+#else
+    static ::android::hardware::sensors::V2_1::subhal::implementation::SensorsSubHalV2_1 subHal;
+#endif  // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+    *version = SUB_HAL_2_1_VERSION;
+    return &subHal;
+}
+
+#endif  // SUB_HAL_VERSION_2_0
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::Void;
+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;
+using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
+using ::android::hardware::sensors::V2_1::Event;
+
+ISensorsSubHalBase::ISensorsSubHalBase() : mCallback(nullptr), mNextHandle(1) {}
+
+// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+Return<void> ISensorsSubHalBase::getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        sensors.push_back(sensor.second->getSensorInfo());
+    }
+
+    _hidl_cb(sensors);
+    return Void();
+}
+
+Return<Result> ISensorsSubHalBase::setOperationMode(OperationMode mode) {
+    for (auto sensor : mSensors) {
+        sensor.second->setOperationMode(mode);
+    }
+    mCurrentOperationMode = mode;
+    return Result::OK;
+}
+
+Return<Result> ISensorsSubHalBase::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> ISensorsSubHalBase::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> ISensorsSubHalBase::flush(int32_t sensorHandle) {
+    auto sensor = mSensors.find(sensorHandle);
+    if (sensor != mSensors.end()) {
+        return sensor->second->flush();
+    }
+    return Result::BAD_VALUE;
+}
+
+Return<Result> ISensorsSubHalBase::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> ISensorsSubHalBase::registerDirectChannel(
+        const SharedMemInfo& /* mem */, V2_0::ISensors::registerDirectChannel_cb _hidl_cb) {
+    _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+    return Return<void>();
+}
+
+Return<Result> ISensorsSubHalBase::unregisterDirectChannel(int32_t /* channelHandle */) {
+    return Result::INVALID_OPERATION;
+}
+
+Return<void> ISensorsSubHalBase::configDirectReport(
+        int32_t /* sensorHandle */, int32_t /* channelHandle */, RateLevel /* rate */,
+        V2_0::ISensors::configDirectReport_cb _hidl_cb) {
+    _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
+    return Return<void>();
+}
+
+Return<void> ISensorsSubHalBase::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+        ALOGE("%s: missing fd for writing", __FUNCTION__);
+        return Void();
+    }
+
+    FILE* out = fdopen(dup(fd->data[0]), "w");
+
+    if (args.size() != 0) {
+        fprintf(out,
+                "Note: sub-HAL %s currently does not support args. Input arguments are "
+                "ignored.\n",
+                getName().c_str());
+    }
+
+    std::ostringstream stream;
+    stream << "Available sensors:" << std::endl;
+    for (auto sensor : mSensors) {
+        SensorInfo info = sensor.second->getSensorInfo();
+        stream << "Name: " << info.name << std::endl;
+        stream << "Min delay: " << info.minDelay << std::endl;
+        stream << "Flags: " << info.flags << std::endl;
+    }
+    stream << std::endl;
+
+    fprintf(out, "%s", stream.str().c_str());
+
+    fclose(out);
+    return Return<void>();
+}
+
+Return<Result> ISensorsSubHalBase::initialize(
+        std::unique_ptr<IHalProxyCallbackWrapperBase>& halProxyCallback) {
+    mCallback = std::move(halProxyCallback);
+    setOperationMode(OperationMode::NORMAL);
+    return Result::OK;
+}
+
+void ISensorsSubHalBase::postEvents(const std::vector<Event>& events, bool wakeup) {
+    ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup);
+    mCallback->postEvents(events, std::move(wakelock));
+}
+
+Return<Result> SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) {
+    return Result::BAD_VALUE;
+}
+
+Return<void> AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        SensorInfo sensorInfo = sensor.second->getSensorInfo();
+        sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL;
+        sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT;
+        sensors.push_back(sensorInfo);
+    }
+    _hidl_cb(V2_1::implementation::convertToOldSensorInfos(sensors));
+    return Void();
+}
+
+Return<void> DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        SensorInfo sensorInfo = sensor.second->getSensorInfo();
+        sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
+        sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_REPORT);
+        sensors.push_back(sensorInfo);
+    }
+    _hidl_cb(V2_1::implementation::convertToOldSensorInfos(sensors));
+    return Void();
+}
+
+void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors(
+        const std::vector<SensorInfo>& sensorsAdded) {
+    mCallback->onDynamicSensorsConnected(sensorsAdded);
+}
+
+void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors(
+        const std::vector<int32_t>& sensorHandlesRemoved) {
+    mCallback->onDynamicSensorsDisconnected(sensorHandlesRemoved);
+}
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h
new file mode 100644
index 0000000..1a78e84
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h
@@ -0,0 +1,268 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "V2_0/SubHal.h"
+#include "V2_1/SubHal.h"
+
+#include "IHalProxyCallbackWrapper.h"
+#include "Sensor.h"
+
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
+
+/**
+ * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0.
+ * See the README file for more details on how this class can be used for testing.
+ */
+class ISensorsSubHalBase : public ISensorsEventCallback {
+  protected:
+    using Event = ::android::hardware::sensors::V2_1::Event;
+    using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
+    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+
+  public:
+    ISensorsSubHalBase();
+
+    Return<void> getSensorsList(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb);
+    Return<Result> injectSensorData(const Event& event);
+    Return<Result> initialize(std::unique_ptr<IHalProxyCallbackWrapperBase>& halProxyCallback);
+
+    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+    virtual Return<Result> setOperationMode(OperationMode mode);
+
+    OperationMode getOperationMode() const { return mCurrentOperationMode; }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled);
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs);
+
+    Return<Result> flush(int32_t sensorHandle);
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       V2_0::ISensors::registerDirectChannel_cb _hidl_cb);
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle);
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    V2_0::ISensors::configDirectReport_cb _hidl_cb);
+
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args);
+
+    // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow.
+    const std::string getName() {
+#ifdef SUB_HAL_NAME
+        return SUB_HAL_NAME;
+#else   // SUB_HAL_NAME
+        return "FakeSubHal";
+#endif  // SUB_HAL_NAME
+    }
+
+    // Method from ISensorsEventCallback.
+    void postEvents(const std::vector<Event>& events, bool wakeup) override;
+
+  protected:
+    template <class SensorType>
+    void AddSensor() {
+        std::shared_ptr<SensorType> sensor =
+                std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
+        mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
+    }
+
+    /**
+     * A map of the available sensors
+     */
+    std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
+
+    /**
+     * Callback used to communicate to the HalProxy when dynamic sensors are connected /
+     * disconnected, sensor events need to be sent to the framework, and when a wakelock should be
+     * acquired.
+     */
+    std::unique_ptr<IHalProxyCallbackWrapperBase> mCallback;
+
+  private:
+    /**
+     * The current operation mode of the multihal framework. Ensures that all subhals are set to
+     * the same operation mode.
+     */
+    OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
+    /**
+     * The next available sensor handle
+     */
+    int32_t mNextHandle;
+};
+
+template <class SubHalClass>
+class SensorsSubHalBase : public ISensorsSubHalBase, public SubHalClass {
+  public:
+    Return<Result> setOperationMode(OperationMode mode) override {
+        return ISensorsSubHalBase::setOperationMode(mode);
+    }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override {
+        return ISensorsSubHalBase::activate(sensorHandle, enabled);
+    }
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override {
+        return ISensorsSubHalBase::batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+    }
+
+    Return<Result> flush(int32_t sensorHandle) override {
+        return ISensorsSubHalBase::flush(sensorHandle);
+    }
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       V2_0::ISensors::registerDirectChannel_cb _hidl_cb) override {
+        return ISensorsSubHalBase::registerDirectChannel(mem, _hidl_cb);
+    }
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+        return ISensorsSubHalBase::unregisterDirectChannel(channelHandle);
+    }
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    V2_0::ISensors::configDirectReport_cb _hidl_cb) override {
+        return ISensorsSubHalBase::configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+    }
+
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override {
+        return ISensorsSubHalBase::debug(fd, args);
+    }
+
+    const std::string getName() override { return ISensorsSubHalBase::getName(); }
+};
+
+class SensorsSubHalV2_0 : public SensorsSubHalBase<V2_0::implementation::ISensorsSubHal> {
+  public:
+    virtual Return<void> getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override {
+        return ISensorsSubHalBase::getSensorsList([&](const auto& list) {
+            _hidl_cb(V2_1::implementation::convertToOldSensorInfos(list));
+        });
+    }
+
+    Return<Result> injectSensorData(const V1_0::Event& event) override {
+        return ISensorsSubHalBase::injectSensorData(V2_1::implementation::convertToNewEvent(event));
+    }
+
+    Return<Result> initialize(
+            const sp<V2_0::implementation::IHalProxyCallback>& halProxyCallback) override {
+        std::unique_ptr<IHalProxyCallbackWrapperBase> wrapper =
+                std::make_unique<HalProxyCallbackWrapperV2_0>(halProxyCallback);
+        return ISensorsSubHalBase::initialize(wrapper);
+    }
+};
+
+class SensorsSubHalV2_1 : public SensorsSubHalBase<V2_1::implementation::ISensorsSubHal> {
+  public:
+    Return<void> getSensorsList_2_1(V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override {
+        return ISensorsSubHalBase::getSensorsList(_hidl_cb);
+    }
+
+    Return<Result> injectSensorData_2_1(const V2_1::Event& event) override {
+        return ISensorsSubHalBase::injectSensorData(event);
+    }
+
+    Return<Result> initialize(
+            const sp<V2_1::implementation::IHalProxyCallback>& halProxyCallback) override {
+        std::unique_ptr<IHalProxyCallbackWrapperBase> wrapper =
+                std::make_unique<HalProxyCallbackWrapperV2_1>(halProxyCallback);
+        return ISensorsSubHalBase::initialize(wrapper);
+    }
+};
+
+// SubHal that has continuous sensors for testing purposes.
+template <class SubHalVersion>
+class ContinuousSensorsSubHal : public SubHalVersion {
+  public:
+    ContinuousSensorsSubHal() {
+        ISensorsSubHalBase::AddSensor<AccelSensor>();
+        ISensorsSubHalBase::AddSensor<GyroSensor>();
+        ISensorsSubHalBase::AddSensor<MagnetometerSensor>();
+        ISensorsSubHalBase::AddSensor<PressureSensor>();
+        ISensorsSubHalBase::AddSensor<DeviceTempSensor>();
+    }
+};
+
+// SubHal that has on-change sensors for testing purposes.
+template <class SubHalVersion>
+class OnChangeSensorsSubHal : public SubHalVersion {
+  public:
+    OnChangeSensorsSubHal() {
+        ISensorsSubHalBase::AddSensor<AmbientTempSensor>();
+        ISensorsSubHalBase::AddSensor<LightSensor>();
+        ISensorsSubHalBase::AddSensor<ProximitySensor>();
+        ISensorsSubHalBase::AddSensor<RelativeHumiditySensor>();
+    }
+};
+
+// SubHal that has both continuous and on-change sensors for testing purposes.
+template <class SubHalVersion>
+class AllSensorsSubHal : public SubHalVersion {
+  public:
+    AllSensorsSubHal() {
+        ISensorsSubHalBase::AddSensor<AccelSensor>();
+        ISensorsSubHalBase::AddSensor<GyroSensor>();
+        ISensorsSubHalBase::AddSensor<MagnetometerSensor>();
+        ISensorsSubHalBase::AddSensor<PressureSensor>();
+        ISensorsSubHalBase::AddSensor<DeviceTempSensor>();
+        ISensorsSubHalBase::AddSensor<AmbientTempSensor>();
+        ISensorsSubHalBase::AddSensor<LightSensor>();
+        ISensorsSubHalBase::AddSensor<ProximitySensor>();
+        ISensorsSubHalBase::AddSensor<RelativeHumiditySensor>();
+    }
+};
+
+class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal<SensorsSubHalV2_0> {
+  public:
+    Return<Result> setOperationMode(OperationMode mode) override;
+};
+
+class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal<SensorsSubHalV2_0> {
+  public:
+    Return<void> getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override;
+};
+
+class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal<SensorsSubHalV2_0> {
+  public:
+    Return<void> getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override;
+};
+
+class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal<SensorsSubHalV2_0> {
+  public:
+    void addDynamicSensors(const std::vector<SensorInfo>& sensorsAdded);
+    void removeDynamicSensors(const std::vector<int32_t>& sensorHandlesAdded);
+};
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
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..c4f92c8
--- /dev/null
+++ b/sensors/common/utils/EventMessageQueueWrapper.h
@@ -0,0 +1,145 @@
+/*
+ * 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 size_t availableToWrite() = 0;
+    virtual bool read(V2_1::Event* events, size_t numToRead) = 0;
+    virtual bool write(const V2_1::Event* events, size_t numToWrite) = 0;
+    virtual bool write(const std::vector<V2_1::Event>& events) = 0;
+    virtual bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification,
+                               uint32_t writeNotification, int64_t timeOutNanos,
+                               android::hardware::EventFlag* evFlag) = 0;
+    virtual size_t getQuantumCount() = 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(); }
+
+    size_t availableToWrite() override { return mQueue->availableToWrite(); }
+
+    virtual bool read(V2_1::Event* events, size_t numToRead) override {
+        return mQueue->read(reinterpret_cast<V1_0::Event*>(events), numToRead);
+    }
+
+    bool write(const V2_1::Event* events, size_t numToWrite) override {
+        return mQueue->write(reinterpret_cast<const V1_0::Event*>(events), numToWrite);
+    }
+
+    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());
+    }
+
+    bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification,
+                       uint32_t writeNotification, int64_t timeOutNanos,
+                       android::hardware::EventFlag* evFlag) override {
+        return mQueue->writeBlocking(reinterpret_cast<const V1_0::Event*>(events), count,
+                                     readNotification, writeNotification, timeOutNanos, evFlag);
+    }
+
+    size_t getQuantumCount() override { return mQueue->getQuantumCount(); }
+
+  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(); }
+
+    size_t availableToWrite() override { return mQueue->availableToWrite(); }
+
+    virtual bool read(V2_1::Event* events, size_t numToRead) override {
+        return mQueue->read(events, numToRead);
+    }
+
+    bool write(const V2_1::Event* events, size_t numToWrite) override {
+        return mQueue->write(events, numToWrite);
+    }
+
+    bool write(const std::vector<V2_1::Event>& events) override {
+        return mQueue->write(events.data(), events.size());
+    }
+
+    bool writeBlocking(const V2_1::Event* events, size_t count, uint32_t readNotification,
+                       uint32_t writeNotification, int64_t timeOutNanos,
+                       android::hardware::EventFlag* evFlag) override {
+        return mQueue->writeBlocking(events, count, readNotification, writeNotification,
+                                     timeOutNanos, evFlag);
+    }
+
+    size_t getQuantumCount() override { return mQueue->getQuantumCount(); }
+
+  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/ISensorsCallbackWrapper.h b/sensors/common/utils/ISensorsCallbackWrapper.h
new file mode 100644
index 0000000..816b225
--- /dev/null
+++ b/sensors/common/utils/ISensorsCallbackWrapper.h
@@ -0,0 +1,96 @@
+/*
+ * 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_ISENSORSCALLBACKWRAPPER_H
+#define ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_H
+
+#include "convertV2_1.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 {
+
+/**
+ * The ISensorsCallbackWrapper classes below abstract away the common logic between both the V2.0
+ * and V2.1 versions of the Sensors HAL interface. This allows users of these classes to only care
+ * about the HAL version at init time and then interact with either version of the callback without
+ * worrying about the class type by utilizing the base class.
+ */
+class ISensorsCallbackWrapperBase : public VirtualLightRefBase {
+  public:
+    virtual Return<void> onDynamicSensorsConnected(
+            const hidl_vec<V2_1::SensorInfo>& sensorInfos) = 0;
+
+    virtual Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& sensorHandles) = 0;
+};
+
+template <typename T>
+class SensorsCallbackWrapperBase : public ISensorsCallbackWrapperBase {
+  public:
+    SensorsCallbackWrapperBase(sp<T> sensorsCallback) : mSensorsCallback(sensorsCallback){};
+
+    virtual Return<void> onDynamicSensorsConnected(
+            const hidl_vec<V2_1::SensorInfo>& sensorInfos) override {
+        return mSensorsCallback->onDynamicSensorsConnected(convertToOldSensorInfos(sensorInfos));
+    }
+
+    Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& sensorHandles) {
+        return mSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
+    }
+
+  protected:
+    sp<T> mSensorsCallback;
+};
+
+class ISensorsCallbackWrapperV2_0
+    : public SensorsCallbackWrapperBase<hardware::sensors::V2_0::ISensorsCallback> {
+  public:
+    ISensorsCallbackWrapperV2_0(sp<hardware::sensors::V2_0::ISensorsCallback> sensorsCallback)
+        : SensorsCallbackWrapperBase(sensorsCallback){};
+};
+
+class ISensorsCallbackWrapperV2_1
+    : public SensorsCallbackWrapperBase<hardware::sensors::V2_1::ISensorsCallback> {
+  public:
+    ISensorsCallbackWrapperV2_1(sp<hardware::sensors::V2_1::ISensorsCallback> sensorsCallback)
+        : SensorsCallbackWrapperBase(sensorsCallback) {}
+
+    Return<void> onDynamicSensorsConnected(const hidl_vec<V2_1::SensorInfo>& sensorInfos) override {
+        return mSensorsCallback->onDynamicSensorsConnected_2_1(sensorInfos);
+    }
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSCALLBACKWRAPPER_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..e5eceb5
--- /dev/null
+++ b/sensors/common/vts/2_X/Android.bp
@@ -0,0 +1,50 @@
+//
+// 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.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/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp
new file mode 100644
index 0000000..a8c2513
--- /dev/null
+++ b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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 <android/hardware/sensors/2.0/types.h>
+#include <android/hardware/sensors/2.1/types.h>
+
+#include <log/log.h>
+
+#include <algorithm>
+#include <vector>
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::sensors::V1_0::Result;
+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;
+#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);
+}
+
+void SensorsHalDeathRecipient::serviceDied(
+        uint64_t /* cookie */,
+        const ::android::wp<::android::hidl::base::V1_0::IBase>& /* service */) {
+    ALOGE("Sensors HAL died (likely crashed) during test");
+    FAIL() << "Sensors HAL died during test";
+}
+
+bool SensorsHidlEnvironmentV2_X::resetHal() {
+    bool succeed = false;
+    do {
+        mSensors = wrapISensors(ISensors::getService(mServiceName));
+        if (mSensors == nullptr) {
+            break;
+        }
+        mSensors->linkToDeath(mDeathRecipient, 0 /* cookie */);
+
+        // Initialize FMQs
+        mWakeLockQueue = std::make_unique<WakeLockQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+                                                         true /* configureEventFlagWord */);
+
+        if (mWakeLockQueue == nullptr) {
+            break;
+        }
+
+        EventFlag::deleteEventFlag(&mEventQueueFlag);
+        EventFlag::createEventFlag(mSensors->getEventQueue()->getEventFlagWord(), &mEventQueueFlag);
+        if (mEventQueueFlag == nullptr) {
+            break;
+        }
+
+        mSensors->initialize(*mWakeLockQueue->getDesc(), new NoOpSensorsCallback());
+
+        std::vector<SensorInfo> sensorList;
+        if (!mSensors->getSensorsList([&](const hidl_vec<SensorInfo>& list) { sensorList = list; })
+                     .isOk()) {
+            break;
+        }
+
+        // stop each sensor individually
+        bool ok = true;
+        for (const auto& i : sensorList) {
+            if (!mSensors->activate(i.sensorHandle, false).isOk()) {
+                ok = false;
+                break;
+            }
+        }
+        if (!ok) {
+            break;
+        }
+
+        // mark it done
+        succeed = true;
+    } while (0);
+
+    if (!succeed) {
+        mSensors = nullptr;
+    }
+
+    return succeed;
+}
+
+void SensorsHidlEnvironmentV2_X::HidlTearDown() {
+    mStopThread = true;
+
+    if (mEventQueueFlag != nullptr) {
+        // Wake up the event queue so the poll thread can exit
+        mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::READ_AND_PROCESS));
+        if (mPollThread.joinable()) {
+            mPollThread.join();
+        }
+
+        EventFlag::deleteEventFlag(&mEventQueueFlag);
+    }
+}
+
+void SensorsHidlEnvironmentV2_X::startPollingThread() {
+    mStopThread = false;
+    mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
+    mPollThread = std::thread(pollingThread, this);
+}
+
+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 = mSensors->getEventQueue()->availableToRead();
+    }
+
+    size_t eventsToRead = std::min(availableEvents, mEventBuffer.size());
+    if (eventsToRead > 0) {
+        if (mSensors->getEventQueue()->read(mEventBuffer.data(), eventsToRead)) {
+            mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::EVENTS_READ));
+            for (size_t i = 0; i < eventsToRead; i++) {
+                addEvent(mEventBuffer[i]);
+            }
+        }
+    }
+}
+
+void SensorsHidlEnvironmentV2_X::pollingThread(SensorsHidlEnvironmentV2_X* env) {
+    ALOGD("polling thread start");
+
+    while (!env->mStopThread.load()) {
+        env->readEvents();
+    }
+
+    ALOGD("polling thread end");
+}
diff --git a/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.h b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.h
new file mode 100644
index 0000000..01f451f
--- /dev/null
+++ b/sensors/common/vts/2_X/SensorsHidlEnvironmentV2_X.h
@@ -0,0 +1,118 @@
+/*
+ * 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_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/2.1/ISensors.h>
+#include <android/hardware/sensors/2.1/types.h>
+
+#include <fmq/MessageQueue.h>
+#include <utils/StrongPointer.h>
+
+#include <array>
+#include <atomic>
+#include <memory>
+
+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;
+
+class SensorsHalDeathRecipient : public ::android::hardware::hidl_death_recipient {
+    virtual void serviceDied(
+            uint64_t cookie,
+            const ::android::wp<::android::hidl::base::V1_0::IBase>& service) override;
+};
+
+class SensorsHidlEnvironmentV2_X
+    : public SensorsHidlEnvironmentBase<::android::hardware::sensors::V2_1::Event> {
+  public:
+    virtual void HidlTearDown() override;
+
+  protected:
+    friend SensorsHidlTest;
+    SensorsHidlEnvironmentV2_X(const std::string& service_name)
+        : SensorsHidlEnvironmentBase(service_name), mEventQueueFlag(nullptr) {}
+
+    /**
+     * Resets the HAL with new FMQs and a new Event Flag
+     *
+     * @return bool true if successful, false otherwise
+     */
+    bool resetHal() override;
+
+    /**
+     * Starts the polling thread that reads sensor events from the Event FMQ
+     */
+    void startPollingThread() override;
+
+    /**
+     * Thread responsible for calling functions to read Event FMQ
+     *
+     * @param env SensorEnvironment to being polling for events on
+     */
+    static void pollingThread(SensorsHidlEnvironmentV2_X* env);
+
+    /**
+     * Reads and saves sensor events from the Event FMQ
+     */
+    void readEvents();
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV2_X);
+
+    /**
+     * Pointer to the Sensors HAL Interface that allows the test to call HAL functions.
+     */
+    sp<ISensorsWrapperBase> mSensors;
+
+    /**
+     * Monitors the HAL for crashes, triggering test failure if seen
+     */
+    sp<SensorsHalDeathRecipient> mDeathRecipient = new SensorsHalDeathRecipient();
+
+    /**
+     * Type used to simplify the creation of the Wake Lock FMQ
+     */
+    typedef MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite> WakeLockQueue;
+
+    /**
+     * The Wake Lock FMQ is used by the test to notify the Sensors HAL whenever it has processed
+     * WAKE_UP sensor events.
+     */
+    std::unique_ptr<WakeLockQueue> mWakeLockQueue;
+
+    /**
+     * The Event Queue Flag notifies the test framework when sensor events have been written to the
+     * Event FMQ by the Sensors HAL.
+     */
+    ::android::hardware::EventFlag* mEventQueueFlag;
+
+    /**
+     * An array that is used to store sensor events read from the Event FMQ
+     */
+    std::array<::android::hardware::sensors::V2_1::Event, MAX_RECEIVE_BUFFER_EVENT_COUNT>
+            mEventBuffer;
+};
+
+#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..2e5aca4
--- /dev/null
+++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
@@ -0,0 +1,964 @@
+/*
+ * 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 type string non-empty only for private sensor types.
+            if (s.type >= SensorTypeVersion::DEVICE_PRIVATE_BASE) {
+                EXPECT_FALSE(s.typeAsString.empty());
+            } else if (!s.typeAsString.empty()) {
+                // Test type string matches framework string if specified for non-private types.
+                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();
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
+                     << " name=" << s.name);
+
+        // 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));
+}
+
+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++) {
+            SCOPED_TRACE(::testing::Message()
+                         << "Flush " << i << "/" << flushCalls << ": "
+                         << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                         << sensor.sensorHandle << std::dec
+                         << " type=" << static_cast<int>(sensor.type) << " name=" << sensor.name);
+
+            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) {
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                     << " name=" << sensor.name);
+        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, Batch) {
+    if (getSensorsList().size() == 0) {
+        return;
+    }
+
+    activateAllSensors(false /* enable */);
+    for (const SensorInfoType& sensor : getSensorsList()) {
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                     << " name=" << sensor.name);
+
+        // 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()) {
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                     << " name=" << sensor.name);
+
+        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) {
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                     << " name=" << sensor.name);
+        // 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);
+
+    getEnvironment()->unregisterCallback();
+
+    for (const SensorInfoType& sensor : sensors) {
+        SCOPED_TRACE(::testing::Message()
+                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                     << " name=" << sensor.name);
+
+        // 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) {
+                           SCOPED_TRACE(::testing::Message()
+                                        << " handle=0x" << std::hex << std::setw(8)
+                                        << std::setfill('0') << sensor.sensorHandle << std::dec
+                                        << " type=" << static_cast<int>(sensor.type)
+                                        << " name=" << sensor.name);
+
+                           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) {
+    SCOPED_TRACE(::testing::Message()
+                 << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                 << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+                 << " name=" << sensor.name);
+
+    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;
+}
diff --git a/sensors/common/vts/OWNERS b/sensors/common/vts/OWNERS
index 759d87b..892da15 100644
--- a/sensors/common/vts/OWNERS
+++ b/sensors/common/vts/OWNERS
@@ -1,6 +1,7 @@
 # Sensors team
+arthuri@google.com
 bduddie@google.com
-bstack@google.com
+stange@google.com
 
 # VTS team
 trong@google.com
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index bb4d329..baaed6c 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,12 +27,21 @@
     local_include_dirs: [
         "include/sensors-vts-utils",
     ],
+    shared_libs: [
+        "libutils",
+    ],
     static_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+    ],
+    whole_static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.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.graphics.mapper@4.0",
     ],
 }
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
index e63faa2..47d1f42 100644
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -18,9 +18,11 @@
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <android/hardware/graphics/mapper/2.1/IMapper.h>
 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 
 #include <utils/Log.h>
 
@@ -29,19 +31,19 @@
 
 using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
 using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
+using IAllocator4 = ::android::hardware::graphics::allocator::V4_0::IAllocator;
 using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
 using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
 using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapper4 = ::android::hardware::graphics::mapper::V4_0::IMapper;
 
 using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
 using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
+using Error4 = ::android::hardware::graphics::mapper::V4_0::Error;
 
 using ::android::hardware::graphics::common::V1_0::BufferUsage;
 using ::android::hardware::graphics::common::V1_0::PixelFormat;
 
-// This is a typedef to the same underlying type across v2.0 and v3.0
-using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
@@ -58,7 +60,6 @@
     virtual ~IGrallocHalWrapper() = default;
 
     // IAllocator
-    virtual std::string dumpDebugInfo() = 0;
     virtual native_handle_t* allocate(uint32_t size) = 0;
     virtual void freeBuffer(native_handle_t* bufferHandle) = 0;
 
@@ -75,6 +76,24 @@
 bool failed(Error3 error) {
     return (error != Error3::NONE);
 }
+bool failed(Error4 error) {
+    return (error != Error4::NONE);
+}
+
+template <typename>
+struct FirstArg;
+
+// Template specialization for pointer to a non-static member function, which exposes
+// the type of the first argument given to said function
+template <typename ReturnType, typename ClassT, typename Arg1, typename... OtherArgs>
+struct FirstArg<ReturnType (ClassT::*)(Arg1, OtherArgs...)> {
+    using type = Arg1;
+};
+
+// Alias to FirstArg which also removes any reference type and const associated
+template <typename T>
+using BaseTypeOfFirstArg = typename std::remove_const<
+        typename std::remove_reference<typename FirstArg<T>::type>::type>::type;
 
 // Since all the type and function names are the same for the things we use across the major HAL
 // versions, we use template magic to avoid repeating ourselves.
@@ -88,7 +107,6 @@
         }
     }
 
-    virtual std::string dumpDebugInfo() override;
     virtual native_handle_t* allocate(uint32_t size) override;
     virtual void freeBuffer(native_handle_t* bufferHandle) override;
 
@@ -101,21 +119,19 @@
     sp<AllocatorT> mAllocator;
     sp<MapperT> mMapper;
 
-    BufferDescriptor getDescriptor(uint32_t size);
+    // v2.0 and v3.0 use vec<uint32_t> for BufferDescriptor, but v4.0 uses vec<uint8_t>, so use
+    // some template magic to deduce the right type based off of the first argument to allocate(),
+    // which is always the version-specific BufferDescriptor type
+    typedef BaseTypeOfFirstArg<decltype(&AllocatorT::allocate)> BufferDescriptorT;
+
+    BufferDescriptorT getDescriptor(uint32_t size);
     native_handle_t* importBuffer(const hidl_handle& rawHandle);
 };
 
 template <typename AllocatorT, typename MapperT>
-std::string GrallocHalWrapper<AllocatorT, MapperT>::dumpDebugInfo() {
-    std::string debugInfo;
-    mAllocator->dumpDebugInfo([&](const hidl_string& tmpDebugInfo) { debugInfo = tmpDebugInfo; });
-    return debugInfo;
-}
-
-template <typename AllocatorT, typename MapperT>
 native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::allocate(uint32_t size) {
     constexpr uint32_t kBufferCount = 1;
-    BufferDescriptor descriptor = getDescriptor(size);
+    BufferDescriptorT descriptor = getDescriptor(size);
     native_handle_t* bufferHandle = nullptr;
 
     auto callback = [&](auto error, uint32_t /*stride*/, const hidl_vec<hidl_handle>& buffers) {
@@ -142,7 +158,8 @@
 }
 
 template <typename AllocatorT, typename MapperT>
-BufferDescriptor GrallocHalWrapper<AllocatorT, MapperT>::getDescriptor(uint32_t size) {
+typename GrallocHalWrapper<AllocatorT, MapperT>::BufferDescriptorT
+GrallocHalWrapper<AllocatorT, MapperT>::getDescriptor(uint32_t size) {
     typename MapperT::BufferDescriptorInfo descriptorInfo = {
             .width = size,
             .height = 1,
@@ -151,8 +168,8 @@
             .usage = kBufferUsage,
     };
 
-    BufferDescriptor descriptor;
-    auto callback = [&](auto error, const BufferDescriptor& tmpDescriptor) {
+    BufferDescriptorT descriptor;
+    auto callback = [&](auto error, const BufferDescriptorT& tmpDescriptor) {
         if (failed(error)) {
             ALOGE("Failed to create descriptor: %" PRId32, static_cast<int32_t>(error));
         } else {
@@ -189,7 +206,7 @@
 
     void* data = nullptr;
     mMapper->lock(bufferHandle, kBufferUsage, accessRegion, acquireFenceHandle,
-                  [&](auto error, void* tmpData, ...) {  // V3_0 passes extra args we don't use
+                  [&](auto error, void* tmpData, ...) {  // V3/4 pass extra args we don't use
                       if (failed(error)) {
                           ALOGE("Failed to lock buffer %p: %" PRId32, bufferHandle,
                                 static_cast<int32_t>(error));
@@ -214,28 +231,40 @@
 }  // anonymous namespace
 
 GrallocWrapper::GrallocWrapper() {
-    sp<IAllocator3> allocator3 = IAllocator3::getService();
-    sp<IMapper3> mapper3 = IMapper3::getService();
+    sp<IAllocator4> allocator4 = IAllocator4::getService();
+    sp<IMapper4> mapper4 = IMapper4::getService();
 
-    if (allocator3 != nullptr && mapper3 != nullptr) {
+    if (allocator4 != nullptr && mapper4 != nullptr) {
+        ALOGD("Using IAllocator/IMapper v4.0");
         mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
-                new GrallocHalWrapper<IAllocator3, IMapper3>(allocator3, mapper3));
+                new GrallocHalWrapper<IAllocator4, IMapper4>(allocator4, mapper4));
     } else {
-        ALOGD("Graphics HALs 3.0 not found (allocator %d mapper %d), falling back to 2.x",
-              (allocator3 != nullptr), (mapper3 != nullptr));
+        ALOGD("Graphics HALs 4.0 not found (allocator %d mapper %d), falling back to 3.0",
+              (allocator4 != nullptr), (mapper4 != nullptr));
 
-        sp<IAllocator2> allocator2 = IAllocator2::getService();
-        sp<IMapper2> mapper2 = IMapper2_1::getService();
-        if (mapper2 == nullptr) {
-            mapper2 = IMapper2::getService();
-        }
+        sp<IAllocator3> allocator3 = IAllocator3::getService();
+        sp<IMapper3> mapper3 = IMapper3::getService();
 
-        if (allocator2 != nullptr && mapper2 != nullptr) {
+        if (allocator3 != nullptr && mapper3 != nullptr) {
             mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
-                    new GrallocHalWrapper<IAllocator2, IMapper2>(allocator2, mapper2));
+                    new GrallocHalWrapper<IAllocator3, IMapper3>(allocator3, mapper3));
         } else {
-            ALOGE("Couldn't open 2.x/3.0 graphics HALs (2.x allocator %d mapper %d)",
-                  (allocator2 != nullptr), (mapper2 != nullptr));
+            ALOGD("Graphics HALs 3.0 not found (allocator %d mapper %d), falling back to 2.x",
+                  (allocator3 != nullptr), (mapper3 != nullptr));
+
+            sp<IAllocator2> allocator2 = IAllocator2::getService();
+            sp<IMapper2> mapper2 = IMapper2_1::getService();
+            if (mapper2 == nullptr) {
+                mapper2 = IMapper2::getService();
+            }
+
+            if (allocator2 != nullptr && mapper2 != nullptr) {
+                mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
+                        new GrallocHalWrapper<IAllocator2, IMapper2>(allocator2, mapper2));
+            } else {
+                ALOGE("Couldn't open graphics HALs (2.x allocator %d mapper %d)",
+                      (allocator2 != nullptr), (mapper2 != nullptr));
+            }
         }
     }
 }
@@ -248,10 +277,6 @@
     mAllocatedBuffers.clear();
 }
 
-std::string GrallocWrapper::dumpDebugInfo() {
-    return mGrallocHal->dumpDebugInfo();
-}
-
 std::pair<native_handle_t*, void*> GrallocWrapper::allocate(uint32_t size) {
     native_handle_t* bufferHandle = mGrallocHal->allocate(size);
     void* buffer = nullptr;
diff --git a/sensors/common/vts/utils/OWNERS b/sensors/common/vts/utils/OWNERS
index 759d87b..892da15 100644
--- a/sensors/common/vts/utils/OWNERS
+++ b/sensors/common/vts/utils/OWNERS
@@ -1,6 +1,7 @@
 # Sensors team
+arthuri@google.com
 bduddie@google.com
-bstack@google.com
+stange@google.com
 
 # VTS team
 trong@google.com
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/GrallocWrapper.h b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
index 41e6334..ebbcb2c 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
@@ -37,8 +37,6 @@
     // returns false, other methods are not safe to call.
     bool isInitialized() const { return (mGrallocHal != nullptr); };
 
-    std::string dumpDebugInfo();
-
     // Allocates a gralloc buffer suitable for direct channel sensors usage with the given size.
     // The buffer should be freed using freeBuffer when it's not needed anymore; otherwise it'll
     // be freed when this object is destroyed.
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..19dfbe5 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,54 @@
 #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() = 0;
 
     // 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 +81,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 +102,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.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
index d7a7d08..63edec5 100644
--- a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
+++ b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
@@ -293,22 +293,6 @@
     EXPECT_NE(0, hidlReturn);
 }
 
-/**
- * Test ISoundTriggerHw::stopAllRecognitions() method
- *
- * Verifies that:
- *  - the implementation implements this optional method or indicates it is not support by
- *  returning -ENOSYS
- */
-TEST_P(SoundTriggerHidlTest, stopAllRecognitions) {
-    Return<int32_t> hidlReturn(0);
-
-    hidlReturn = mSoundTriggerHal->stopAllRecognitions();
-
-    EXPECT_TRUE(hidlReturn.isOk());
-    EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
-}
-
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, SoundTriggerHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
diff --git a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
index 7f06ed9..392679d 100644
--- a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
+++ b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
@@ -172,61 +172,6 @@
 };
 
 /**
- * Test ISoundTriggerHw::getProperties() method
- *
- * Verifies that:
- *  - the implementation implements the method
- *  - the method returns 0 (no error)
- *  - the implementation supports at least one sound model and one key phrase
- *  - the implementation supports at least VOICE_TRIGGER recognition mode
- */
-TEST_P(SoundTriggerHidlTest, GetProperties) {
-    ISoundTriggerHw::Properties halProperties;
-    Return<void> hidlReturn;
-    int ret = -ENODEV;
-
-    hidlReturn = mSoundTriggerHal->getProperties([&](int rc, auto res) {
-        ret = rc;
-        halProperties = res;
-    });
-
-    EXPECT_TRUE(hidlReturn.isOk());
-    EXPECT_EQ(0, ret);
-    EXPECT_GT(halProperties.maxSoundModels, 0u);
-    EXPECT_GT(halProperties.maxKeyPhrases, 0u);
-    EXPECT_NE(0u, (halProperties.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER));
-}
-
-/**
- * Test ISoundTriggerHw::loadPhraseSoundModel() method
- *
- * Verifies that:
- *  - the implementation implements the method
- *  - the implementation returns an error when passed a malformed sound model
- *
- * There is no way to verify that implementation actually can load a sound model because each
- * sound model is vendor specific.
- */
-TEST_P(SoundTriggerHidlTest, LoadInvalidModelFail) {
-    Return<void> hidlReturn;
-    int ret = -ENODEV;
-    V2_0_ISoundTriggerHw::PhraseSoundModel model;
-    SoundModelHandle handle;
-
-    model.common.type = SoundModelType::UNKNOWN;
-
-    hidlReturn =
-        mSoundTriggerHal->loadPhraseSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
-            ret = retval;
-            handle = res;
-        });
-
-    EXPECT_TRUE(hidlReturn.isOk());
-    EXPECT_NE(0, ret);
-    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
-}
-
-/**
  * Test ISoundTriggerHw::loadPhraseSoundModel_2_1() method
  *
  * Verifies that:
@@ -280,34 +225,6 @@
 }
 
 /**
- * Test ISoundTriggerHw::loadSoundModel() method
- *
- * Verifies that:
- *  - the implementation returns error when passed a sound model with random data.
- */
-TEST_P(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
-    int ret = -ENODEV;
-    V2_0_ISoundTriggerHw::SoundModel model;
-    SoundModelHandle handle = 0;
-
-    model.type = SoundModelType::GENERIC;
-    model.data.resize(100);
-    for (auto& d : model.data) {
-        d = rand();
-    }
-
-    Return<void> loadReturn =
-        mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
-            ret = retval;
-            handle = res;
-        });
-
-    EXPECT_TRUE(loadReturn.isOk());
-    EXPECT_NE(0, ret);
-    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
-}
-
-/**
  * Test ISoundTriggerHw::loadSoundModel_2_1() method
  *
  * Verifies that:
@@ -371,54 +288,6 @@
 }
 
 /**
- * Test ISoundTriggerHw::unloadSoundModel() method
- *
- * Verifies that:
- *  - the implementation implements the method
- *  - the implementation returns an error when called without a valid loaded sound model
- *
- */
-TEST_P(SoundTriggerHidlTest, UnloadModelNoModelFail) {
-    Return<int32_t> hidlReturn(0);
-    SoundModelHandle halHandle = 0;
-
-    hidlReturn = mSoundTriggerHal->unloadSoundModel(halHandle);
-
-    EXPECT_TRUE(hidlReturn.isOk());
-    EXPECT_NE(0, hidlReturn);
-}
-
-/**
- * Test ISoundTriggerHw::startRecognition() method
- *
- * Verifies that:
- *  - the implementation implements the method
- *  - the implementation returns an error when called without a valid loaded sound model
- *
- * There is no way to verify that implementation actually starts recognition because no model can
- * be loaded.
- */
-TEST_P(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
-    Return<int32_t> hidlReturn(0);
-    SoundModelHandle handle = 0;
-    PhraseRecognitionExtra phrase;
-    V2_0_ISoundTriggerHw::RecognitionConfig config;
-
-    config.captureHandle = 0;
-    config.captureDevice = AudioDevice::IN_BUILTIN_MIC;
-    phrase.id = 0;
-    phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
-    phrase.confidenceLevel = 0;
-
-    config.phrases.setToExternal(&phrase, 1);
-
-    hidlReturn = mSoundTriggerHal->startRecognition(handle, config, mCallback, 0);
-
-    EXPECT_TRUE(hidlReturn.isOk());
-    EXPECT_NE(0, hidlReturn);
-}
-
-/**
  * Test ISoundTriggerHw::startRecognition_2_1() method
  *
  * Verifies that:
@@ -448,40 +317,6 @@
     EXPECT_NE(0, hidlReturn);
 }
 
-/**
- * Test ISoundTriggerHw::stopRecognition() method
- *
- * Verifies that:
- *  - the implementation implements the method
- *  - the implementation returns an error when called without an active recognition running
- *
- */
-TEST_P(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
-    Return<int32_t> hidlReturn(0);
-    SoundModelHandle handle = 0;
-
-    hidlReturn = mSoundTriggerHal->stopRecognition(handle);
-
-    EXPECT_TRUE(hidlReturn.isOk());
-    EXPECT_NE(0, hidlReturn);
-}
-
-/**
- * Test ISoundTriggerHw::stopAllRecognitions() method
- *
- * Verifies that:
- *  - the implementation implements this optional method or indicates it is not supported by
- *  returning -ENOSYS
- */
-TEST_P(SoundTriggerHidlTest, stopAllRecognitions) {
-    Return<int32_t> hidlReturn(0);
-
-    hidlReturn = mSoundTriggerHal->stopAllRecognitions();
-
-    EXPECT_TRUE(hidlReturn.isOk());
-    EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
-}
-
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, SoundTriggerHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
diff --git a/soundtrigger/2.3/Android.bp b/soundtrigger/2.3/Android.bp
new file mode 100644
index 0000000..480df4d
--- /dev/null
+++ b/soundtrigger/2.3/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.soundtrigger@2.3",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "ISoundTriggerHw.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@2.0",
+        "android.hardware.soundtrigger@2.0",
+        "android.hardware.soundtrigger@2.1",
+        "android.hardware.soundtrigger@2.2",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/soundtrigger/2.3/ISoundTriggerHw.hal b/soundtrigger/2.3/ISoundTriggerHw.hal
new file mode 100644
index 0000000..3e761e5
--- /dev/null
+++ b/soundtrigger/2.3/ISoundTriggerHw.hal
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+package android.hardware.soundtrigger@2.3;
+
+import @2.0::SoundModelHandle;
+import @2.0::ISoundTriggerHwCallback.CallbackCookie;
+import @2.2::ISoundTriggerHw;
+import @2.1::ISoundTriggerHwCallback;
+
+/**
+ * SoundTrigger HAL interface. Used for hardware recognition of hotwords
+ * and other sounds.
+ */
+interface ISoundTriggerHw extends @2.2::ISoundTriggerHw {
+
+    /**
+     * Retrieve extended implementation properties.
+     * The returned properties includes what is returned from the
+     * getProperties along with expanded implementation details.
+     *
+     * @return retval Operation completion status: 0 in case of success,
+     *                -ENODEV in case of initialization error.
+     * @return properties A Properties structure containing implementation
+     *                    description and capabilities.
+     */
+    getProperties_2_3() generates (int32_t retval, Properties properties);
+
+    /**
+     * Start recognition on a given model. Only one recognition active
+     * at a time per model. Once recognition succeeds or fails, the callback
+     * associated with the model handle is called.
+     *
+     * Must have the exact same semantics as startRecognition from
+     * ISoundTriggerHw@2.1 except that the RecognitionConfig includes audio
+     * capabilities applied when the recognition is active.
+     *
+     * @param modelHandle the handle of the sound model to use for recognition
+     * @param config A RecognitionConfig structure containing attributes of the
+     *     recognition to perform
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid recognition attributes,
+     *     -ENOSYS in case of invalid model handle,
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     */
+    startRecognition_2_3(SoundModelHandle modelHandle, RecognitionConfig config)
+            generates (int32_t retval);
+
+    /**
+     * Set a model specific parameter with the given value. This parameter
+     * will keep its value for the duration the model is loaded regardless of starting and stopping
+     * recognition. Once the model is unloaded, the value will be lost.
+     * It is expected to check if the handle supports the parameter via the queryParameter
+     * API prior to calling this method.
+     *
+     * @param modelHandle The sound model handle indicating which model to modify parameters
+     * @param modelParam Parameter to set which will be validated against the
+     *                   ModelParameter type. Not putting ModelParameter type
+     *                   directly in the definition and validating internally
+     *                   allows for forward compatibility.
+     * @param value The value to set for the given model parameter
+     * @return status Operation completion status: 0 in case of success,
+     *                -ENODEV if the native service cannot be reached
+     *                -EINVAL invalid input parameter
+     */
+    setParameter(SoundModelHandle modelHandle, ModelParameter modelParam, int32_t value)
+            generates (int32_t status);
+
+    /**
+     * Get a model specific parameter. This parameter will keep its value
+     * for the duration the model is loaded regardless of starting and stopping recognition.
+     * Once the model is unloaded, the value will be lost. If the value is not set, a default
+     * value is returned. See ModelParameter for parameter default values.
+     * It is expected to check if the handle supports the parameter via the queryParameter
+     * API prior to calling this method.
+     *
+     * @param modelHandle The sound model associated with given modelParam
+     * @param modelParam Parameter to set which will be validated against the
+     *                   ModelParameter type. Not putting ModelParameter type
+     *                   directly in the definition and validating internally
+     *                   allows for forward compatibility.
+     * @return status Operation completion status: 0 in case of success,
+     *                -ENODEV if the native service cannot be reached
+     *                -EINVAL invalid input parameter
+     * @return value Value set to the requested parameter. Value is only set when status
+     *                indicates success.
+     */
+    getParameter(SoundModelHandle modelHandle, ModelParameter modelParam)
+            generates (int32_t status, int32_t value);
+
+    /**
+     * Get supported parameter attributes with respect to the provided model
+     * handle. Along with determining the valid range, this API is also used
+     * to determine if a given parameter ID is supported at all by the
+     * modelHandle for use with getParameter and setParameter APIs.
+     *
+     * @param modelHandle The sound model handle indicating which model to query
+     * @param modelParam Parameter to set which will be validated against the
+     *                   ModelParameter type
+     * @return status Operation completion status: 0 in case of success
+     *                -ENODEV if the native service cannot be reached
+     *                -EINVAL invalid input parameter
+     * @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/Android.bp b/soundtrigger/2.3/default/Android.bp
new file mode 100644
index 0000000..be2c8b0
--- /dev/null
+++ b/soundtrigger/2.3/default/Android.bp
@@ -0,0 +1,37 @@
+//
+// 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_library_shared {
+    name: "android.hardware.soundtrigger@2.3-impl",
+    relative_install_path: "hw",
+    vendor: true,
+    srcs: [
+        "SoundTriggerHw.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "liblog",
+        "libhidlmemory",
+        "libutils",
+        "libhardware",
+        "android.hardware.soundtrigger@2.0",
+        "android.hardware.soundtrigger@2.0-core",
+        "android.hardware.soundtrigger@2.1",
+        "android.hardware.soundtrigger@2.2",
+        "android.hardware.soundtrigger@2.3",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+    ],
+}
diff --git a/soundtrigger/2.3/default/SoundTriggerHw.cpp b/soundtrigger/2.3/default/SoundTriggerHw.cpp
new file mode 100644
index 0000000..8fe3108
--- /dev/null
+++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp
@@ -0,0 +1,920 @@
+/*
+ * 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 "SoundTriggerHw"
+
+#include "SoundTriggerHw.h"
+
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/log.h>
+#include <hidlmemory/mapping.h>
+#include <utility>
+
+using android::hardware::hidl_memory;
+using android::hidl::allocator::V1_0::IAllocator;
+using android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_3 {
+namespace implementation {
+
+/**
+ * According to the HIDL C++ Users Guide: client and server implementations
+ * should never directly refer to anything other than the interface header
+ * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so
+ * this V2_3 implementation copies the previous implementations and
+ * then adds the new implementation.
+ */
+
+// Begin V2_0 implementation, copied from
+// hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
+
+// static
+void soundModelCallback_(struct sound_trigger_model_event* halEvent, void* cookie) {
+    if (halEvent == NULL) {
+        ALOGW("soundModelCallback called with NULL event");
+        return;
+    }
+    sp<SoundTriggerHw::SoundModelClient> client =
+            wp<SoundTriggerHw::SoundModelClient>(
+                    static_cast<SoundTriggerHw::SoundModelClient*>(cookie))
+                    .promote();
+    if (client == 0) {
+        ALOGW("soundModelCallback called on stale client");
+        return;
+    }
+    if (halEvent->model != client->getHalHandle()) {
+        ALOGW("soundModelCallback call with wrong handle %d on client with handle %d",
+              (int)halEvent->model, (int)client->getHalHandle());
+        return;
+    }
+
+    client->soundModelCallback(halEvent);
+}
+
+// static
+void recognitionCallback_(struct sound_trigger_recognition_event* halEvent, void* cookie) {
+    if (halEvent == NULL) {
+        ALOGW("recognitionCallback call NULL event");
+        return;
+    }
+    sp<SoundTriggerHw::SoundModelClient> client =
+            wp<SoundTriggerHw::SoundModelClient>(
+                    static_cast<SoundTriggerHw::SoundModelClient*>(cookie))
+                    .promote();
+    if (client == 0) {
+        ALOGW("recognitionCallback called on stale client");
+        return;
+    }
+
+    client->recognitionCallback(halEvent);
+}
+
+Return<void> SoundTriggerHw::getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb) {
+    ALOGV("getProperties() mHwDevice %p", mHwDevice);
+    int ret;
+    struct sound_trigger_properties halProperties;
+    V2_0::ISoundTriggerHw::Properties properties;
+
+    if (mHwDevice == NULL) {
+        ret = -ENODEV;
+        goto exit;
+    }
+
+    ret = mHwDevice->get_properties(mHwDevice, &halProperties);
+
+    convertPropertiesFromHal(&properties, &halProperties);
+
+    ALOGV("getProperties implementor %s recognitionModes %08x", properties.implementor.c_str(),
+          properties.recognitionModes);
+
+exit:
+    _hidl_cb(ret, properties);
+    return Void();
+}
+
+int SoundTriggerHw::doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+                                     sp<SoundTriggerHw::SoundModelClient> client) {
+    int32_t ret = 0;
+    struct sound_trigger_sound_model* halSoundModel;
+
+    ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size());
+
+    if (mHwDevice == NULL) {
+        ret = -ENODEV;
+        goto exit;
+    }
+
+    halSoundModel = convertSoundModelToHal(&soundModel);
+    if (halSoundModel == NULL) {
+        ret = -EINVAL;
+        goto exit;
+    }
+
+    sound_model_handle_t halHandle;
+    ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback_, client.get(),
+                                      &halHandle);
+
+    free(halSoundModel);
+
+    if (ret != 0) {
+        goto exit;
+    }
+
+    client->setHalHandle(halHandle);
+    {
+        AutoMutex lock(mLock);
+        mClients.add(client->getId(), client);
+    }
+
+exit:
+    return ret;
+}
+
+Return<void> SoundTriggerHw::loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+                                            const sp<V2_0::ISoundTriggerHwCallback>& callback,
+                                            V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
+                                            ISoundTriggerHw::loadSoundModel_cb _hidl_cb) {
+    sp<SoundTriggerHw::SoundModelClient> client =
+            new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+    _hidl_cb(doLoadSoundModel(soundModel, client), client->getId());
+    return Void();
+}
+
+Return<void> SoundTriggerHw::loadPhraseSoundModel(
+        const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel,
+        const sp<V2_0::ISoundTriggerHwCallback>& callback,
+        V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
+        ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) {
+    sp<SoundTriggerHw::SoundModelClient> client =
+            new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+    _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel, client),
+             client->getId());
+    return Void();
+}
+
+Return<int32_t> SoundTriggerHw::unloadSoundModel(int32_t modelHandle) {
+    int32_t ret;
+    sp<SoundTriggerHw::SoundModelClient> client;
+
+    if (mHwDevice == NULL) {
+        ret = -ENODEV;
+        goto exit;
+    }
+
+    {
+        AutoMutex lock(mLock);
+        client = mClients.valueFor(modelHandle);
+        if (client == 0) {
+            ret = -ENOSYS;
+            goto exit;
+        }
+    }
+
+    ret = mHwDevice->unload_sound_model(mHwDevice, client->getHalHandle());
+
+    mClients.removeItem(modelHandle);
+
+exit:
+    return ret;
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition(
+        int32_t modelHandle, const V2_0::ISoundTriggerHw::RecognitionConfig& config,
+        const sp<V2_0::ISoundTriggerHwCallback>& /* callback */, int32_t /* cookie */) {
+    int32_t ret;
+    sp<SoundTriggerHw::SoundModelClient> client;
+    struct sound_trigger_recognition_config* halConfig;
+
+    if (mHwDevice == NULL) {
+        ret = -ENODEV;
+        goto exit;
+    }
+
+    {
+        AutoMutex lock(mLock);
+        client = mClients.valueFor(modelHandle);
+        if (client == 0) {
+            ret = -ENOSYS;
+            goto exit;
+        }
+    }
+
+    halConfig =
+            convertRecognitionConfigToHal((const V2_0::ISoundTriggerHw::RecognitionConfig*)&config);
+
+    if (halConfig == NULL) {
+        ret = -EINVAL;
+        goto exit;
+    }
+    ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig,
+                                       recognitionCallback_, client.get());
+
+    free(halConfig);
+
+exit:
+    return ret;
+}
+
+Return<int32_t> SoundTriggerHw::stopRecognition(int32_t modelHandle) {
+    int32_t ret;
+    sp<SoundTriggerHw::SoundModelClient> client;
+    if (mHwDevice == NULL) {
+        ret = -ENODEV;
+        goto exit;
+    }
+
+    {
+        AutoMutex lock(mLock);
+        client = mClients.valueFor(modelHandle);
+        if (client == 0) {
+            ret = -ENOSYS;
+            goto exit;
+        }
+    }
+
+    ret = mHwDevice->stop_recognition(mHwDevice, client->getHalHandle());
+
+exit:
+    return ret;
+}
+
+Return<int32_t> SoundTriggerHw::stopAllRecognitions() {
+    int32_t ret;
+    if (mHwDevice == NULL) {
+        ret = -ENODEV;
+        goto exit;
+    }
+
+    ret = mHwDevice->stop_all_recognitions(mHwDevice);
+
+exit:
+    return ret;
+}
+
+SoundTriggerHw::SoundTriggerHw() : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) {}
+
+void SoundTriggerHw::onFirstRef() {
+    const hw_module_t* mod;
+    int rc;
+
+    rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
+    if (rc != 0) {
+        ALOGE("couldn't load sound trigger module %s.%s (%s)", SOUND_TRIGGER_HARDWARE_MODULE_ID,
+              mModuleName, strerror(-rc));
+        return;
+    }
+    rc = sound_trigger_hw_device_open(mod, &mHwDevice);
+    if (rc != 0) {
+        ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
+              SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+        mHwDevice = NULL;
+        return;
+    }
+    if (mHwDevice->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_1_3) {
+        ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
+        sound_trigger_hw_device_close(mHwDevice);
+        mHwDevice = NULL;
+        return;
+    }
+
+    ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice);
+}
+
+SoundTriggerHw::~SoundTriggerHw() {
+    if (mHwDevice != NULL) {
+        sound_trigger_hw_device_close(mHwDevice);
+    }
+}
+
+uint32_t SoundTriggerHw::nextUniqueModelId() {
+    uint32_t modelId = 0;
+    {
+        AutoMutex lock(mLock);
+        do {
+            modelId = atomic_fetch_add_explicit(&mNextModelId, (uint_fast32_t)1,
+                                                memory_order_acq_rel);
+        } while (mClients.valueFor(modelId) != 0 && modelId != 0);
+    }
+    LOG_ALWAYS_FATAL_IF(modelId == 0, "wrap around in sound model IDs, num loaded models %zu",
+                        mClients.size());
+    return modelId;
+}
+
+void SoundTriggerHw::convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid) {
+    uuid->timeLow = halUuid->timeLow;
+    uuid->timeMid = halUuid->timeMid;
+    uuid->versionAndTimeHigh = halUuid->timeHiAndVersion;
+    uuid->variantAndClockSeqHigh = halUuid->clockSeq;
+    memcpy(&uuid->node[0], &halUuid->node[0], 6);
+}
+
+void SoundTriggerHw::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid) {
+    halUuid->timeLow = uuid->timeLow;
+    halUuid->timeMid = uuid->timeMid;
+    halUuid->timeHiAndVersion = uuid->versionAndTimeHigh;
+    halUuid->clockSeq = uuid->variantAndClockSeqHigh;
+    memcpy(&halUuid->node[0], &uuid->node[0], 6);
+}
+
+void SoundTriggerHw::convertPropertiesFromHal(
+        V2_0::ISoundTriggerHw::Properties* properties,
+        const struct sound_trigger_properties* halProperties) {
+    properties->implementor = halProperties->implementor;
+    properties->description = halProperties->description;
+    properties->version = halProperties->version;
+    convertUuidFromHal(&properties->uuid, &halProperties->uuid);
+    properties->maxSoundModels = halProperties->max_sound_models;
+    properties->maxKeyPhrases = halProperties->max_key_phrases;
+    properties->maxUsers = halProperties->max_users;
+    properties->recognitionModes = halProperties->recognition_modes;
+    properties->captureTransition = halProperties->capture_transition;
+    properties->maxBufferMs = halProperties->max_buffer_ms;
+    properties->concurrentCapture = halProperties->concurrent_capture;
+    properties->triggerInEvent = halProperties->trigger_in_event;
+    properties->powerConsumptionMw = halProperties->power_consumption_mw;
+}
+
+void SoundTriggerHw::convertPropertiesFromHal(
+        V2_3::Properties* properties, const struct sound_trigger_properties_header* header) {
+    if (header->version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_3) {
+        const struct sound_trigger_properties_extended_1_3* halProperties =
+                (const struct sound_trigger_properties_extended_1_3*)header;
+        convertPropertiesFromHal(&properties->base, &halProperties->base);
+        properties->supportedModelArch = halProperties->supported_model_arch;
+        properties->audioCapabilities = halProperties->audio_capabilities;
+    }
+}
+
+void SoundTriggerHw::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+                                               const ISoundTriggerHw::Phrase* triggerPhrase) {
+    halTriggerPhrase->id = triggerPhrase->id;
+    halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes;
+    unsigned int i;
+
+    halTriggerPhrase->num_users =
+            std::min((int)triggerPhrase->users.size(), SOUND_TRIGGER_MAX_USERS);
+    for (i = 0; i < halTriggerPhrase->num_users; i++) {
+        halTriggerPhrase->users[i] = triggerPhrase->users[i];
+    }
+
+    strlcpy(halTriggerPhrase->locale, triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
+    strlcpy(halTriggerPhrase->text, triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+}
+
+struct sound_trigger_sound_model* SoundTriggerHw::convertSoundModelToHal(
+        const V2_0::ISoundTriggerHw::SoundModel* soundModel) {
+    struct sound_trigger_sound_model* halModel = NULL;
+    if (soundModel->type == V2_0::SoundModelType::KEYPHRASE) {
+        size_t allocSize =
+                sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
+        struct sound_trigger_phrase_sound_model* halKeyPhraseModel =
+                static_cast<struct sound_trigger_phrase_sound_model*>(malloc(allocSize));
+        LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL,
+                            "malloc failed for size %zu in convertSoundModelToHal PHRASE",
+                            allocSize);
+
+        const V2_0::ISoundTriggerHw::PhraseSoundModel* keyPhraseModel =
+                reinterpret_cast<const V2_0::ISoundTriggerHw::PhraseSoundModel*>(soundModel);
+
+        size_t i;
+        for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
+            convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], &keyPhraseModel->phrases[i]);
+        }
+        halKeyPhraseModel->num_phrases = (unsigned int)i;
+        halModel = reinterpret_cast<struct sound_trigger_sound_model*>(halKeyPhraseModel);
+        halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model);
+    } else {
+        size_t allocSize = sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
+        halModel = static_cast<struct sound_trigger_sound_model*>(malloc(allocSize));
+        LOG_ALWAYS_FATAL_IF(halModel == NULL,
+                            "malloc failed for size %zu in convertSoundModelToHal GENERIC",
+                            allocSize);
+
+        halModel->data_offset = sizeof(struct sound_trigger_sound_model);
+    }
+    halModel->type = (sound_trigger_sound_model_type_t)soundModel->type;
+    convertUuidToHal(&halModel->uuid, &soundModel->uuid);
+    convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid);
+    halModel->data_size = soundModel->data.size();
+    uint8_t* dst = reinterpret_cast<uint8_t*>(halModel) + halModel->data_offset;
+    const uint8_t* src = reinterpret_cast<const uint8_t*>(&soundModel->data[0]);
+    memcpy(dst, src, soundModel->data.size());
+
+    return halModel;
+}
+
+void SoundTriggerHw::convertPhraseRecognitionExtraToHal(
+        struct sound_trigger_phrase_recognition_extra* halExtra,
+        const V2_0::PhraseRecognitionExtra* extra) {
+    halExtra->id = extra->id;
+    halExtra->recognition_modes = extra->recognitionModes;
+    halExtra->confidence_level = extra->confidenceLevel;
+
+    unsigned int i;
+    for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) {
+        halExtra->levels[i].user_id = extra->levels[i].userId;
+        halExtra->levels[i].level = extra->levels[i].levelPercent;
+    }
+    halExtra->num_levels = i;
+}
+
+struct sound_trigger_recognition_config* SoundTriggerHw::convertRecognitionConfigToHal(
+        const V2_0::ISoundTriggerHw::RecognitionConfig* config) {
+    size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size();
+    struct sound_trigger_recognition_config* halConfig =
+            static_cast<struct sound_trigger_recognition_config*>(malloc(allocSize));
+
+    LOG_ALWAYS_FATAL_IF(halConfig == NULL,
+                        "malloc failed for size %zu in convertRecognitionConfigToHal", allocSize);
+
+    halConfig->capture_handle = (audio_io_handle_t)config->captureHandle;
+    halConfig->capture_device = (audio_devices_t)config->captureDevice;
+    halConfig->capture_requested = config->captureRequested;
+
+    unsigned int i;
+    for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
+        convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], &config->phrases[i]);
+    }
+    halConfig->num_phrases = i;
+
+    halConfig->data_offset = sizeof(struct sound_trigger_recognition_config);
+    halConfig->data_size = config->data.size();
+    uint8_t* dst = reinterpret_cast<uint8_t*>(halConfig) + halConfig->data_offset;
+    const uint8_t* src = reinterpret_cast<const uint8_t*>(&config->data[0]);
+    memcpy(dst, src, config->data.size());
+    return halConfig;
+}
+
+struct sound_trigger_recognition_config_header* SoundTriggerHw::convertRecognitionConfigToHalHeader(
+        const V2_3::RecognitionConfig* config) {
+    sp<IMemory> memory;
+    const V2_1::ISoundTriggerHw::RecognitionConfig* config_2_1 = &config->base;
+    const V2_0::ISoundTriggerHw::RecognitionConfig* config_2_0 = &config_2_1->header;
+
+    size_t allocSize =
+            sizeof(struct sound_trigger_recognition_config_extended_1_3) + config_2_1->data.size();
+    struct sound_trigger_recognition_config_extended_1_3* halConfigExtended =
+            static_cast<struct sound_trigger_recognition_config_extended_1_3*>(malloc(allocSize));
+    LOG_ALWAYS_FATAL_IF(halConfigExtended == nullptr,
+                        "malloc failed for size %zu in convertRecognitionConfigToHalHeader",
+                        allocSize);
+    halConfigExtended->header.version = SOUND_TRIGGER_DEVICE_API_VERSION_1_3;
+    halConfigExtended->header.size = allocSize;
+
+    struct sound_trigger_recognition_config* halConfigBase = &halConfigExtended->base;
+
+    halConfigBase->capture_handle = (audio_io_handle_t)config_2_0->captureHandle;
+    halConfigBase->capture_device = (audio_devices_t)config_2_0->captureDevice;
+    halConfigBase->capture_requested = config_2_0->captureRequested;
+
+    unsigned int i;
+    for (i = 0; i < config_2_0->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
+        convertPhraseRecognitionExtraToHal(&halConfigBase->phrases[i], &config_2_0->phrases[i]);
+    }
+    halConfigBase->num_phrases = i;
+
+    halConfigBase->data_offset = sizeof(struct sound_trigger_recognition_config_extended_1_3);
+    halConfigBase->data_size = config_2_1->data.size();
+    if (config_2_1->data.size() != 0) {
+        memory = mapMemory(config_2_1->data);
+        LOG_ALWAYS_FATAL_IF(memory == nullptr,
+                            "failed to map config memory in convertRecognitionConfigToHalHeader");
+        memory->read();
+
+        uint8_t* dst = reinterpret_cast<uint8_t*>(halConfigExtended) + halConfigBase->data_offset;
+        const uint8_t* src = static_cast<const uint8_t*>(static_cast<void*>(memory->getPointer()));
+        memcpy(dst, src, config_2_1->data.size());
+
+        memory->commit();
+    }
+
+    halConfigExtended->audio_capabilities = config->audioCapabilities;
+
+    return &halConfigExtended->header;
+}
+
+// static
+void SoundTriggerHw::convertSoundModelEventFromHal(
+        V2_0::ISoundTriggerHwCallback::ModelEvent* event,
+        const struct sound_trigger_model_event* halEvent) {
+    event->status = (V2_0::ISoundTriggerHwCallback::SoundModelStatus)halEvent->status;
+    // event->model to be remapped by called
+    event->data.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) +
+                                      halEvent->data_offset,
+                              halEvent->data_size);
+}
+
+// static
+void SoundTriggerHw::convertPhaseRecognitionEventFromHal(
+        V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+        const struct sound_trigger_phrase_recognition_event* halEvent) {
+    event->phraseExtras.resize(halEvent->num_phrases);
+    for (unsigned int i = 0; i < halEvent->num_phrases; i++) {
+        convertPhraseRecognitionExtraFromHal(&event->phraseExtras[i], &halEvent->phrase_extras[i]);
+    }
+    convertRecognitionEventFromHal(&event->common, &halEvent->common);
+}
+
+// static
+void SoundTriggerHw::convertRecognitionEventFromHal(
+        V2_0::ISoundTriggerHwCallback::RecognitionEvent* event,
+        const struct sound_trigger_recognition_event* halEvent) {
+    event->status = static_cast<V2_0::ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status);
+    event->type = static_cast<V2_0::SoundModelType>(halEvent->type);
+    // event->model to be remapped by called
+    event->captureAvailable = halEvent->capture_available;
+    event->captureSession = halEvent->capture_session;
+    event->captureDelayMs = halEvent->capture_delay_ms;
+    event->capturePreambleMs = halEvent->capture_preamble_ms;
+    event->triggerInData = halEvent->trigger_in_data;
+    event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate;
+    event->audioConfig.channelMask =
+            (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
+    event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format;
+    event->data.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) +
+                                      halEvent->data_offset,
+                              halEvent->data_size);
+}
+
+// static
+void SoundTriggerHw::convertPhraseRecognitionExtraFromHal(
+        V2_0::PhraseRecognitionExtra* extra,
+        const struct sound_trigger_phrase_recognition_extra* halExtra) {
+    extra->id = halExtra->id;
+    extra->recognitionModes = halExtra->recognition_modes;
+    extra->confidenceLevel = halExtra->confidence_level;
+
+    extra->levels.resize(halExtra->num_levels);
+    for (unsigned int i = 0; i < halExtra->num_levels; i++) {
+        extra->levels[i].userId = halExtra->levels[i].user_id;
+        extra->levels[i].levelPercent = halExtra->levels[i].level;
+    }
+}
+
+void SoundTriggerHw::SoundModelClient_2_0::recognitionCallback(
+        struct sound_trigger_recognition_event* halEvent) {
+    if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+        V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+        convertPhaseRecognitionEventFromHal(
+                &event, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+        event.common.model = mId;
+        mCallback->phraseRecognitionCallback(event, mCookie);
+    } else {
+        V2_0::ISoundTriggerHwCallback::RecognitionEvent event;
+        convertRecognitionEventFromHal(&event, halEvent);
+        event.model = mId;
+        mCallback->recognitionCallback(event, mCookie);
+    }
+}
+
+void SoundTriggerHw::SoundModelClient_2_0::soundModelCallback(
+        struct sound_trigger_model_event* halEvent) {
+    V2_0::ISoundTriggerHwCallback::ModelEvent event;
+    convertSoundModelEventFromHal(&event, halEvent);
+    event.model = mId;
+    mCallback->soundModelCallback(event, mCookie);
+}
+
+// Begin V2_1 implementation, copied from
+// hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.cpp
+
+namespace {
+
+// Backs up by the vector with the contents of shared memory.
+// It is assumed that the passed hidl_vector is empty, so it's
+// not cleared if the memory is a null object.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> memoryAsVector(const hidl_memory& m, hidl_vec<uint8_t>* vec) {
+    sp<IMemory> memory;
+    if (m.size() == 0) {
+        return std::make_pair(true, memory);
+    }
+    memory = mapMemory(m);
+    if (memory != nullptr) {
+        memory->read();
+        vec->setToExternal(static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())),
+                           memory->getSize());
+        return std::make_pair(true, memory);
+    }
+    ALOGE("%s: Could not map HIDL memory to IMemory", __func__);
+    return std::make_pair(false, memory);
+}
+
+// Moves the data from the vector into allocated shared memory,
+// emptying the vector.
+// It is assumed that the passed hidl_memory is a null object, so it's
+// not reset if the vector is empty.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> moveVectorToMemory(hidl_vec<uint8_t>* v, hidl_memory* mem) {
+    sp<IMemory> memory;
+    if (v->size() == 0) {
+        return std::make_pair(true, memory);
+    }
+    sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+    if (ashmem == 0) {
+        ALOGE("Failed to retrieve ashmem allocator service");
+        return std::make_pair(false, memory);
+    }
+    bool success = false;
+    Return<void> r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) {
+        success = s;
+        if (success) *mem = m;
+    });
+    if (r.isOk() && success) {
+        memory = hardware::mapMemory(*mem);
+        if (memory != 0) {
+            memory->update();
+            memcpy(memory->getPointer(), v->data(), v->size());
+            memory->commit();
+            v->resize(0);
+            return std::make_pair(true, memory);
+        } else {
+            ALOGE("Failed to map allocated ashmem");
+        }
+    } else {
+        ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size());
+    }
+    return std::make_pair(false, memory);
+}
+
+}  // namespace
+
+Return<void> SoundTriggerHw::loadSoundModel_2_1(
+        const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+        const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+        V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb) {
+    // It is assumed that legacy data vector is empty, thus making copy is cheap.
+    V2_0::ISoundTriggerHw::SoundModel soundModel_2_0(soundModel.header);
+    auto result = memoryAsVector(soundModel.data, &soundModel_2_0.data);
+    if (result.first) {
+        sp<SoundModelClient> client =
+                new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+        _hidl_cb(doLoadSoundModel(soundModel_2_0, client), client->getId());
+        return Void();
+    }
+    _hidl_cb(-ENOMEM, 0);
+    return Void();
+}
+
+Return<void> SoundTriggerHw::loadPhraseSoundModel_2_1(
+        const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+        const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+        V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb) {
+    V2_0::ISoundTriggerHw::PhraseSoundModel soundModel_2_0;
+    // It is assumed that legacy data vector is empty, thus making copy is cheap.
+    soundModel_2_0.common = soundModel.common.header;
+    // Avoid copying phrases data.
+    soundModel_2_0.phrases.setToExternal(
+            const_cast<V2_0::ISoundTriggerHw::Phrase*>(soundModel.phrases.data()),
+            soundModel.phrases.size());
+    auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data);
+    if (result.first) {
+        sp<SoundModelClient> client =
+                new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+        _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel_2_0, client),
+                 client->getId());
+        return Void();
+    }
+    _hidl_cb(-ENOMEM, 0);
+    return Void();
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition_2_1(
+        int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config,
+        const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie) {
+    // It is assumed that legacy data vector is empty, thus making copy is cheap.
+    V2_0::ISoundTriggerHw::RecognitionConfig config_2_0(config.header);
+    auto result = memoryAsVector(config.data, &config_2_0.data);
+    return result.first ? startRecognition(modelHandle, config_2_0, callback, cookie)
+                        : Return<int32_t>(-ENOMEM);
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::recognitionCallback(
+        struct sound_trigger_recognition_event* halEvent) {
+    if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+        V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0;
+        convertPhaseRecognitionEventFromHal(
+                &event_2_0, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+        event_2_0.common.model = mId;
+        V2_1::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+        event.phraseExtras.setToExternal(event_2_0.phraseExtras.data(),
+                                         event_2_0.phraseExtras.size());
+        auto result = moveVectorToMemory(&event_2_0.common.data, &event.common.data);
+        if (result.first) {
+            // The data vector is now empty, thus copying is cheap.
+            event.common.header = event_2_0.common;
+            mCallback->phraseRecognitionCallback_2_1(event, mCookie);
+        }
+    } else {
+        V2_1::ISoundTriggerHwCallback::RecognitionEvent event;
+        convertRecognitionEventFromHal(&event.header, halEvent);
+        event.header.model = mId;
+        auto result = moveVectorToMemory(&event.header.data, &event.data);
+        if (result.first) {
+            mCallback->recognitionCallback_2_1(event, mCookie);
+        }
+    }
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::soundModelCallback(
+        struct sound_trigger_model_event* halEvent) {
+    V2_1::ISoundTriggerHwCallback::ModelEvent event;
+    convertSoundModelEventFromHal(&event.header, halEvent);
+    event.header.model = mId;
+    auto result = moveVectorToMemory(&event.header.data, &event.data);
+    if (result.first) {
+        mCallback->soundModelCallback_2_1(event, mCookie);
+    }
+}
+
+// Begin V2_2 implementation, copied from
+// hardware/interfaces/soundtrigger/2.2/default/SoundTriggerHw.cpp
+
+Return<int32_t> SoundTriggerHw::getModelState(int32_t modelHandle) {
+    sp<SoundModelClient> client;
+    if (mHwDevice == NULL) {
+        return -ENODEV;
+    }
+
+    {
+        AutoMutex lock(mLock);
+        client = mClients.valueFor(modelHandle);
+        if (client == 0) {
+            return -ENOSYS;
+        }
+    }
+
+    return mHwDevice->get_model_state(mHwDevice, client->getHalHandle());
+}
+
+// Begin V2_3 implementation
+
+Return<void> SoundTriggerHw::getProperties_2_3(ISoundTriggerHw::getProperties_2_3_cb _hidl_cb) {
+    ALOGV("getProperties_2_3() mHwDevice %p", mHwDevice);
+    int ret = 0;
+    V2_3::Properties properties;
+    const struct sound_trigger_properties_header* header;
+
+    if (mHwDevice == NULL) {
+        ret = -ENODEV;
+        goto exit;
+    }
+
+    header = mHwDevice->get_properties_extended(mHwDevice);
+
+    convertPropertiesFromHal(&properties, header);
+
+    ALOGV("getProperties_2_3 implementor %s supportedModelArch %s",
+          properties.base.implementor.c_str(), properties.supportedModelArch.c_str());
+
+exit:
+    _hidl_cb(ret, properties);
+    return Void();
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition_2_3(int32_t modelHandle,
+                                                     const V2_3::RecognitionConfig& config) {
+    int32_t ret;
+    sp<SoundTriggerHw::SoundModelClient> client;
+    struct sound_trigger_recognition_config_header* header;
+
+    if (mHwDevice == NULL) {
+        ret = -ENODEV;
+        goto exit;
+    }
+
+    {
+        AutoMutex lock(mLock);
+        client = mClients.valueFor(modelHandle);
+        if (client == 0) {
+            ret = -ENOSYS;
+            goto exit;
+        }
+    }
+
+    header = convertRecognitionConfigToHalHeader(&config);
+
+    if (header == nullptr) {
+        ret = -EINVAL;
+        goto exit;
+    }
+    ret = mHwDevice->start_recognition_extended(mHwDevice, client->getHalHandle(), header,
+                                                recognitionCallback_, client.get());
+
+    free(header);
+
+exit:
+    return ret;
+}
+
+Return<int32_t> SoundTriggerHw::setParameter(V2_0::SoundModelHandle modelHandle,
+                                             ModelParameter modelParam, int32_t value) {
+    sp<SoundModelClient> client;
+    if (mHwDevice == NULL) {
+        return -ENODEV;
+    }
+
+    {
+        AutoMutex lock(mLock);
+        client = mClients.valueFor(modelHandle);
+        if (client == 0) {
+            return -EINVAL;
+        }
+    }
+
+    return mHwDevice->set_parameter(mHwDevice, client->getHalHandle(),
+                                    convertModelParameterToHal(modelParam), value);
+}
+
+Return<void> SoundTriggerHw::getParameter(V2_0::SoundModelHandle modelHandle,
+                                          ModelParameter modelParam, getParameter_cb _hidl_cb) {
+    sp<SoundModelClient> client;
+    if (mHwDevice == NULL) {
+        _hidl_cb(-ENODEV, 0);
+        return Void();
+    }
+
+    {
+        AutoMutex lock(mLock);
+        client = mClients.valueFor(modelHandle);
+        if (client == 0) {
+            _hidl_cb(-EINVAL, 0);
+            return Void();
+        }
+    }
+
+    int32_t value;
+    int32_t status = mHwDevice->get_parameter(mHwDevice, client->getHalHandle(),
+                                              convertModelParameterToHal(modelParam), &value);
+    _hidl_cb(status, value);
+    return Void();
+}
+
+Return<void> SoundTriggerHw::queryParameter(V2_0::SoundModelHandle modelHandle,
+                                            ModelParameter modelParam, queryParameter_cb _hidl_cb) {
+    OptionalModelParameterRange optionalParamRange;
+    sp<SoundModelClient> client;
+    if (mHwDevice == NULL) {
+        _hidl_cb(-ENODEV, optionalParamRange);
+        return Void();
+    }
+
+    {
+        AutoMutex lock(mLock);
+        client = mClients.valueFor(modelHandle);
+        if (client == 0) {
+            _hidl_cb(-EINVAL, optionalParamRange);
+            return Void();
+        }
+    }
+
+    sound_trigger_model_parameter_range_t paramRange;
+    int32_t status = mHwDevice->query_parameter(
+            mHwDevice, client->getHalHandle(), convertModelParameterToHal(modelParam), &paramRange);
+
+    if (status == 0 && paramRange.is_supported) {
+        optionalParamRange.range({.start = paramRange.start, .end = paramRange.end});
+    }
+    _hidl_cb(status, optionalParamRange);
+    return Void();
+}
+
+// static
+sound_trigger_model_parameter_t SoundTriggerHw::convertModelParameterToHal(ModelParameter param) {
+    switch (param) {
+        case ModelParameter::THRESHOLD_FACTOR:
+            return MODEL_PARAMETER_THRESHOLD_FACTOR;
+        case ModelParameter::INVALID:
+        default:
+            return MODEL_PARAMETER_INVALID;
+    }
+}
+
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+
+ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) {
+    return new SoundTriggerHw();
+}
+
+}  // namespace implementation
+}  // namespace V2_3
+}  // namespace soundtrigger
+}  // namespace hardware
+}  // namespace android
diff --git a/soundtrigger/2.3/default/SoundTriggerHw.h b/soundtrigger/2.3/default/SoundTriggerHw.h
new file mode 100644
index 0000000..ccd468c
--- /dev/null
+++ b/soundtrigger/2.3/default/SoundTriggerHw.h
@@ -0,0 +1,214 @@
+/*
+ * 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_SOUNDTRIGGER_V2_3_SOUNDTRIGGERHW_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_3_SOUNDTRIGGERHW_H
+
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
+#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.3/types.h>
+#include <hardware/sound_trigger.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <stdatomic.h>
+#include <system/sound_trigger.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_3 {
+namespace implementation {
+
+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;
+using ::android::hardware::audio::common::V2_0::Uuid;
+
+/**
+ * According to the HIDL C++ Users Guide: client and server implementations
+ * should never directly refer to anything other than the interface header
+ * generated from the HIDL definition file (ie. ISoundTriggerHw.hal), so
+ * this V2_3 implementation copies the previous implementations and
+ * then adds the new implementation.
+ */
+struct SoundTriggerHw : public ISoundTriggerHw {
+    // Methods from V2_0::ISoundTriggerHw follow.
+    Return<void> getProperties(getProperties_cb _hidl_cb) override;
+    Return<void> loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+                                const sp<V2_0::ISoundTriggerHwCallback>& callback, int32_t cookie,
+                                loadSoundModel_cb _hidl_cb) override;
+    Return<void> loadPhraseSoundModel(const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel,
+                                      const sp<V2_0::ISoundTriggerHwCallback>& callback,
+                                      int32_t cookie, loadPhraseSoundModel_cb _hidl_cb) override;
+    Return<int32_t> unloadSoundModel(int32_t modelHandle) override;
+    Return<int32_t> startRecognition(int32_t modelHandle,
+                                     const V2_0::ISoundTriggerHw::RecognitionConfig& config,
+                                     const sp<V2_0::ISoundTriggerHwCallback>& callback,
+                                     int32_t cookie) override;
+    Return<int32_t> stopRecognition(int32_t modelHandle) override;
+    Return<int32_t> stopAllRecognitions() override;
+
+    // Methods from V2_1::ISoundTriggerHw follow.
+    Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+                                    const sp<V2_1::ISoundTriggerHwCallback>& callback,
+                                    int32_t cookie, loadSoundModel_2_1_cb _hidl_cb) override;
+    Return<void> loadPhraseSoundModel_2_1(const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+                                          const sp<V2_1::ISoundTriggerHwCallback>& callback,
+                                          int32_t cookie,
+                                          loadPhraseSoundModel_2_1_cb _hidl_cb) override;
+    Return<int32_t> startRecognition_2_1(int32_t modelHandle,
+                                         const V2_1::ISoundTriggerHw::RecognitionConfig& config,
+                                         const sp<V2_1::ISoundTriggerHwCallback>& callback,
+                                         int32_t cookie) override;
+
+    // Methods from V2_2::ISoundTriggerHw follow.
+    Return<int32_t> getModelState(int32_t modelHandle) override;
+
+    // Methods from V2_3::ISoundTriggerHw follow.
+    Return<void> getProperties_2_3(getProperties_2_3_cb _hidl_cb) override;
+    Return<int32_t> startRecognition_2_3(int32_t modelHandle,
+                                         const V2_3::RecognitionConfig& config) override;
+    Return<int32_t> setParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam,
+                                 int32_t value) override;
+    Return<void> getParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam,
+                              ISoundTriggerHw::getParameter_cb _hidl_cb) override;
+    Return<void> queryParameter(V2_0::SoundModelHandle modelHandle, ModelParameter modelParam,
+                                ISoundTriggerHw::queryParameter_cb _hidl_cb) override;
+
+    SoundTriggerHw();
+
+    // Copied from hardware/interfaces/soundtrigger/2.0/default/SoundTriggerHalImpl.h
+
+    /**
+     * Client object holding active handles and callback sctructures. Used for referencing
+     * which models map to which client of the HAL. SoundModelClients are stored in the
+     * mClients object while the model is active.
+     */
+    class SoundModelClient : public RefBase {
+      public:
+        SoundModelClient(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie)
+            : mId(id), mCookie(cookie) {}
+        virtual ~SoundModelClient() {}
+
+        uint32_t getId() const { return mId; }
+        sound_model_handle_t getHalHandle() const { return mHalHandle; }
+        void setHalHandle(sound_model_handle_t handle) { mHalHandle = handle; }
+
+        virtual void recognitionCallback(struct sound_trigger_recognition_event* halEvent) = 0;
+        virtual void soundModelCallback(struct sound_trigger_model_event* halEvent) = 0;
+
+      protected:
+        const uint32_t mId;
+        sound_model_handle_t mHalHandle;
+        V2_0::ISoundTriggerHwCallback::CallbackCookie mCookie;
+    };
+
+  private:
+    static void convertPhaseRecognitionEventFromHal(
+            V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+            const struct sound_trigger_phrase_recognition_event* halEvent);
+    static void convertRecognitionEventFromHal(
+            V2_0::ISoundTriggerHwCallback::RecognitionEvent* event,
+            const struct sound_trigger_recognition_event* halEvent);
+    static void convertSoundModelEventFromHal(V2_0::ISoundTriggerHwCallback::ModelEvent* event,
+                                              const struct sound_trigger_model_event* halEvent);
+
+    virtual ~SoundTriggerHw();
+
+    uint32_t nextUniqueModelId();
+    int doLoadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+                         sp<SoundModelClient> client);
+
+    // RefBase
+    void onFirstRef() override;
+
+    class SoundModelClient_2_0 : public SoundModelClient {
+      public:
+        SoundModelClient_2_0(uint32_t id, V2_0::ISoundTriggerHwCallback::CallbackCookie cookie,
+                             sp<V2_0::ISoundTriggerHwCallback> callback)
+            : SoundModelClient(id, cookie), mCallback(callback) {}
+
+        void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+        void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
+
+      private:
+        sp<V2_0::ISoundTriggerHwCallback> mCallback;
+    };
+
+    void convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid);
+    void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid);
+    void convertPropertiesFromHal(V2_0::ISoundTriggerHw::Properties* properties,
+                                  const struct sound_trigger_properties* halProperties);
+    void convertPropertiesFromHal(V2_3::Properties* properties,
+                                  const struct sound_trigger_properties_header* header);
+    static sound_trigger_model_parameter_t convertModelParameterToHal(ModelParameter param);
+    void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+                                   const V2_0::ISoundTriggerHw::Phrase* triggerPhrase);
+    // returned HAL sound model must be freed by caller
+    struct sound_trigger_sound_model* convertSoundModelToHal(
+            const V2_0::ISoundTriggerHw::SoundModel* soundModel);
+    void convertPhraseRecognitionExtraToHal(struct sound_trigger_phrase_recognition_extra* halExtra,
+                                            const V2_0::PhraseRecognitionExtra* extra);
+    // returned recognition config must be freed by caller
+    struct sound_trigger_recognition_config* convertRecognitionConfigToHal(
+            const V2_0::ISoundTriggerHw::RecognitionConfig* config);
+    struct sound_trigger_recognition_config_header* convertRecognitionConfigToHalHeader(
+            const V2_3::RecognitionConfig* config);
+
+    static void convertPhraseRecognitionExtraFromHal(
+            V2_0::PhraseRecognitionExtra* extra,
+            const struct sound_trigger_phrase_recognition_extra* halExtra);
+
+    static void soundModelCallback(struct sound_trigger_model_event* halEvent, void* cookie);
+    static void recognitionCallback(struct sound_trigger_recognition_event* halEvent, void* cookie);
+
+    const char* mModuleName;
+    struct sound_trigger_hw_device* mHwDevice;
+    volatile atomic_uint_fast32_t mNextModelId;
+    DefaultKeyedVector<int32_t, sp<SoundModelClient>> mClients;
+    Mutex mLock;
+
+    // Copied from hardware/interfaces/soundtrigger/2.1/default/SoundTriggerHw.h
+    class SoundModelClient_2_1 : public SoundModelClient {
+      public:
+        SoundModelClient_2_1(uint32_t id, V2_1::ISoundTriggerHwCallback::CallbackCookie cookie,
+                             sp<V2_1::ISoundTriggerHwCallback> callback)
+            : SoundModelClient(id, cookie), mCallback(callback) {}
+
+        void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+        void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
+
+      private:
+        sp<V2_1::ISoundTriggerHwCallback> mCallback;
+    };
+};
+
+extern "C" ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* name);
+
+}  // namespace implementation
+}  // namespace V2_3
+}  // namespace soundtrigger
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SOUNDTRIGGER_V2_2_SOUNDTRIGGERHW_H
diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal
new file mode 100644
index 0000000..10fc34e
--- /dev/null
+++ b/soundtrigger/2.3/types.hal
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+package android.hardware.soundtrigger@2.3;
+
+import android.hidl.safe_union@1.0::Monostate;
+import @2.0::ISoundTriggerHw.Properties;
+import @2.1::ISoundTriggerHw.RecognitionConfig;
+
+/**
+ * AudioCapabilities supported by the implemented HAL
+ * driver.
+ */
+enum AudioCapabilities : uint32_t {
+    /**
+     * If set the underlying module supports AEC.
+     */
+    ECHO_CANCELLATION = 1 << 0,
+    /**
+     * If set, the underlying module supports noise suppression.
+     */
+    NOISE_SUPPRESSION = 1 << 1,
+};
+
+/**
+ * Extended implementation properties providing verbose implementation
+ * details.
+ */
+struct Properties {
+    @2.0::ISoundTriggerHw.Properties base;
+
+    /**
+     * String naming the architecture used for running the supported models.
+     * (eg. DSP architecture)
+     */
+    string supportedModelArch;
+
+    /**
+     * Bit field encoding of the AudioCapabilities
+     * supported by the firmware.
+     */
+    bitfield<AudioCapabilities> audioCapabilities;
+};
+
+/**
+ * Configuration for sound trigger capture session passed to
+ * startRecognition_2_1() method.
+ */
+struct RecognitionConfig {
+    @2.1::ISoundTriggerHw.RecognitionConfig base;
+
+    /**
+     * Bit field encoding of the AudioCapabilities
+     * supported by the firmware.
+     */
+    bitfield<AudioCapabilities> audioCapabilities;
+};
+
+/**
+ * Model specific parameters to be used with parameter set and get APIs
+ */
+enum ModelParameter : int32_t {
+    /**
+     * Placeholder for invalid model parameter used for returning error or
+     * passing an invalid value.
+     */
+    INVALID = -1,
+
+    /**
+     * Controls the sensitivity threshold adjustment factor for a given model.
+     * Negative value corresponds to less sensitive model (high threshold) and
+     * a positive value corresponds to a more sensitive model (low threshold).
+     * Default value is 0.
+     */
+    THRESHOLD_FACTOR = 0
+};
+
+/**
+ * Safe union wrapping ModelParameterRange.
+ * Monostate is used to indicate there is no valid range
+ */
+safe_union OptionalModelParameterRange {
+    Monostate noinit;
+    ModelParameterRange range;
+};
+
+/**
+ * Model specific range support for a given parameter
+ */
+struct ModelParameterRange {
+    /**
+     * start of supported value range inclusive
+     */
+    int32_t start;
+    /**
+     * end of supported value range inclusive
+     */
+    int32_t end;
+};
diff --git a/soundtrigger/2.3/vts/functional/Android.bp b/soundtrigger/2.3/vts/functional/Android.bp
new file mode 100644
index 0000000..e3855fc
--- /dev/null
+++ b/soundtrigger/2.3/vts/functional/Android.bp
@@ -0,0 +1,31 @@
+//
+// 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: "VtsHalSoundtriggerV2_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalSoundtriggerV2_3TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.soundtrigger@2.0",
+        "android.hardware.soundtrigger@2.1",
+        "android.hardware.soundtrigger@2.2",
+        "android.hardware.soundtrigger@2.3",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
new file mode 100644
index 0000000..2d147e4
--- /dev/null
+++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "SoundTriggerHidlHalTest"
+
+#include <android-base/logging.h>
+#include <android/hardware/audio/common/2.0/types.h>
+#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.3/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::soundtrigger::V2_0::RecognitionMode;
+using ::android::hardware::soundtrigger::V2_3::AudioCapabilities;
+using ::android::hardware::soundtrigger::V2_3::ISoundTriggerHw;
+using ::android::hardware::soundtrigger::V2_3::Properties;
+
+/**
+ * Test class holding the instance of the SoundTriggerHW service to test.
+ * The passed parameter is the registered name of the implementing service
+ * supplied by INSTANTIATE_TEST_SUITE_P() call.
+ */
+class SoundTriggerHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        soundtrigger = ISoundTriggerHw::getService(GetParam());
+
+        ASSERT_NE(soundtrigger, nullptr);
+        LOG(INFO) << "Test is remote " << soundtrigger->isRemote();
+    }
+
+    sp<ISoundTriggerHw> soundtrigger;
+};
+
+/**
+ * Empty test is in place to ensure service is initalized.
+ * Due to the nature of SoundTrigger HAL providing an interface for
+ * proprietary or vendor specific implementations, limited testing on
+ * individual APIs is possible.
+ */
+TEST_P(SoundTriggerHidlTest, ServiceIsInstantiated) {}
+
+/**
+ * Test ISoundTriggerHw::getProperties_2_3 method
+ *
+ * Verifies that:
+ * - the implementation implements the method
+ * - the method returns no error
+ * - the implementation supports at least one sound model and one key phrase
+ * - the implementation supports at least VOICE_TRIGGER recognition mode
+ */
+TEST_P(SoundTriggerHidlTest, GetProperties_2_3) {
+    Properties halProperties;
+    Return<void> hidlReturn;
+    int ret = -ENODEV;
+
+    hidlReturn = soundtrigger->getProperties_2_3([&](int rc, auto res) {
+        ret = rc;
+        halProperties = res;
+    });
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_EQ(0, ret);
+    EXPECT_GT(halProperties.base.maxSoundModels, 0u);
+    EXPECT_GT(halProperties.base.maxKeyPhrases, 0u);
+    EXPECT_NE(0u, (halProperties.base.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER));
+    EXPECT_TRUE(halProperties.audioCapabilities <=
+                (AudioCapabilities::ECHO_CANCELLATION | AudioCapabilities::NOISE_SUPPRESSION));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, SoundTriggerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/tv/cec/1.0/config/sadConfig.xsd b/tv/cec/1.0/config/sadConfig.xsd
new file mode 100644
index 0000000..7f99311
--- /dev/null
+++ b/tv/cec/1.0/config/sadConfig.xsd
@@ -0,0 +1,86 @@
+<?xml version="1.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.
+-->
+<xs:schema version="1.0"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <xs:include schemaLocation="../../../../audio/4.0/config/audio_policy_configuration.xsd"/>
+    <xs:complexType name="config">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                List the config versions supported by Short Audio Descriptor(SAD) config.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="device" type="device" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="version" type="version"/>
+    </xs:complexType>
+    <xs:complexType name="device">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Device section:
+                There is a list of configurations in this SAD config for all the input audio
+                devices that the current Android device supports.
+                Each device has the following attributes:
+                    "type": type of the audio device.
+                And the following element
+                    <supportedFormat/>: the supported format info of the device. There can be
+                                        multiple formats supported by one audio device.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="supportedFormat" type="supportedFormat" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="supportedFormat">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                SupportedFormat section:
+                The details of the short audio descriptor of a specific audio format
+                supported by the audio device. Attributes as follows:
+                    "format": format enum of the current supported format.
+                    "descriptor": three-byte short audio descriptor for the given format in hex.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="format" type="hdmiAudioFormat" use="required"/>
+        <xs:attribute name="descriptor" type="descriptor" use="required"/>
+    </xs:complexType>
+    <xs:simpleType name="descriptor">
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[a-fA-F0-9]{6}"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="hdmiAudioFormat">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_FORMAT_NONE"/>
+            <xs:enumeration value="AUDIO_FORMAT_LPCM"/>
+            <xs:enumeration value="AUDIO_FORMAT_DD"/>
+            <xs:enumeration value="AUDIO_FORMAT_MPEG1"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+            <xs:enumeration value="AUDIO_FORMAT_MPEG2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_ATRAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_ONEBITAUDIO"/>
+            <xs:enumeration value="AUDIO_FORMAT_DDP"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTSHD"/>
+            <xs:enumeration value="AUDIO_FORMAT_TRUEHD"/>
+            <xs:enumeration value="AUDIO_FORMAT_DST"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMAPRO"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="config" type="config"/>
+</xs:schema>
diff --git a/tv/input/1.0/vts/functional/Android.bp b/tv/input/1.0/vts/functional/Android.bp
index 29181b0..5d20bce 100644
--- a/tv/input/1.0/vts/functional/Android.bp
+++ b/tv/input/1.0/vts/functional/Android.bp
@@ -19,6 +19,9 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalTvInputV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.tv.input@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+    require_root: true,
 }
-
diff --git a/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp b/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp
index 573a1d6..8092d5e 100644
--- a/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp
+++ b/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp
@@ -17,11 +17,12 @@
 #define LOG_TAG "tv_input_hidl_hal_test"
 #include <android-base/logging.h>
 
-#include <android/hardware/tv/input/1.0/types.h>
 #include <android/hardware/tv/input/1.0/ITvInput.h>
 #include <android/hardware/tv/input/1.0/ITvInputCallback.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/tv/input/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <utils/KeyedVector.h>
 #include <mutex>
 #include <vector>
@@ -42,179 +43,161 @@
 #define WAIT_FOR_EVENT_TIMEOUT 5
 #define DEFAULT_ID INT32_MIN
 
-// Test environment for TvInput HIDL HAL.
-class TvInputHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static TvInputHidlEnvironment* Instance() {
-    static TvInputHidlEnvironment* instance = new TvInputHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<ITvInput>(); }
-
- private:
-  TvInputHidlEnvironment() {}
-};
-
 /* The main test class for TV Input HIDL HAL. */
-class TvInputHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
-  virtual void SetUp() override {
-    tv_input_ = ::testing::VtsHalHidlTargetTestBase::getService<ITvInput>(
-          TvInputHidlEnvironment::Instance()->getServiceName<ITvInput>());
-    ASSERT_NE(tv_input_, nullptr);
-    tv_input_callback_ = new TvInputCallback(*this);
-    ASSERT_NE(tv_input_callback_, nullptr);
-    tv_input_->setCallback(tv_input_callback_);
-    // All events received within the timeout should be handled.
-    sleep(WAIT_FOR_EVENT_TIMEOUT);
-  }
-
-  virtual void TearDown() override {}
-
-  /* Called when a DEVICE_AVAILABLE event is received. */
-  void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
-    device_info_.add(deviceInfo.deviceId, deviceInfo);
-  }
-
-  /* Called when a DEVICE_UNAVAILABLE event is received. */
-  void onDeviceUnavailable(int32_t deviceId) {
-    device_info_.removeItem(deviceId);
-  }
-
-  /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */
-  Result onStreamConfigurationsChanged(int32_t deviceId) {
-    return updateStreamConfigurations(deviceId);
-  }
-
-  /* Gets and updates the stream configurations for a device. */
-  Result updateStreamConfigurations(int32_t deviceId) {
-    stream_config_.removeItem(deviceId);
-    Result result = Result::UNKNOWN;
-    hidl_vec<TvStreamConfig> list;
-    tv_input_->getStreamConfigurations(deviceId,
-        [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) {
-          result = res;
-          if (res == Result::OK) {
-            list = configs;
-          }
-        });
-    if (result == Result::OK) {
-      stream_config_.add(deviceId, list);
-    }
-    return result;
-  }
-
-  /* Gets and updates the stream configurations for all existing devices. */
-  void updateAllStreamConfigurations() {
-    for (size_t i = 0; i < device_info_.size(); i++) {
-      int32_t device_id = device_info_.keyAt(i);
-      updateStreamConfigurations(device_id);
-    }
-  }
-
-  /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
-  std::vector<size_t> getConfigIndices() {
-    std::vector<size_t> indices;
-    for (size_t i = 0; i < stream_config_.size(); i++) {
-      if (stream_config_.valueAt(i).size() != 0) {
-        indices.push_back(i);
-      }
-    }
-    return indices;
-  }
-
-  /*
-   * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums).
-   * Otherwise, returns the smallest missing non-negative integer.
-   */
-  int32_t getNumNotIn(std::vector<int32_t>& nums) {
-    int32_t result = DEFAULT_ID;
-    int32_t size = static_cast<int32_t>(nums.size());
-    for (int32_t i = 0; i < size; i++) {
-      // Put every element to its target position, if possible.
-      int32_t target_pos = nums[i];
-      while (target_pos >= 0 && target_pos < size && i != target_pos && nums[i] != nums[target_pos]) {
-        std::swap(nums[i], nums[target_pos]);
-        target_pos = nums[i];
-      }
+class TvInputHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        tv_input_ = ITvInput::getService(GetParam());
+        tv_input_callback_ = new TvInputCallback(*this);
+        ASSERT_NE(tv_input_callback_, nullptr);
+        tv_input_->setCallback(tv_input_callback_);
+        // All events received within the timeout should be handled.
+        sleep(WAIT_FOR_EVENT_TIMEOUT);
     }
 
-    for (int32_t i = 0; i < size; i++) {
-      if (nums[i] != i) {
-        return i;
-      }
+    virtual void TearDown() override {}
+
+    /* Called when a DEVICE_AVAILABLE event is received. */
+    void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
+        device_info_.add(deviceInfo.deviceId, deviceInfo);
     }
-    return result;
-  }
 
-  /* A simple test implementation of TvInputCallback for TV Input Events. */
-  class TvInputCallback : public ITvInputCallback {
-    public:
-     TvInputCallback(TvInputHidlTest& parent) : parent_(parent){};
+    /* Called when a DEVICE_UNAVAILABLE event is received. */
+    void onDeviceUnavailable(int32_t deviceId) { device_info_.removeItem(deviceId); }
 
-     virtual ~TvInputCallback() = default;
+    /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */
+    Result onStreamConfigurationsChanged(int32_t deviceId) {
+        return updateStreamConfigurations(deviceId);
+    }
 
-     /*
-      * Notifies the client that an event has occured. For possible event types,
-      * check TvInputEventType.
-      */
-     Return<void> notify(const TvInputEvent& event) override {
-       std::unique_lock<std::mutex> lock(parent_.mutex_);
-       switch(event.type) {
-         case TvInputEventType::DEVICE_AVAILABLE:
-           parent_.onDeviceAvailable(event.deviceInfo);
-           break;
-         case TvInputEventType::DEVICE_UNAVAILABLE:
-           parent_.onDeviceUnavailable(event.deviceInfo.deviceId);
-           break;
-         case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
-           parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId);
-           break;
-       }
-       return Void();
-     };
-    private:
-     /* The test contains this callback instance. */
-     TvInputHidlTest& parent_;
-  };
+    /* Gets and updates the stream configurations for a device. */
+    Result updateStreamConfigurations(int32_t deviceId) {
+        stream_config_.removeItem(deviceId);
+        Result result = Result::UNKNOWN;
+        hidl_vec<TvStreamConfig> list;
+        tv_input_->getStreamConfigurations(
+                deviceId, [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) {
+                    result = res;
+                    if (res == Result::OK) {
+                        list = configs;
+                    }
+                });
+        if (result == Result::OK) {
+            stream_config_.add(deviceId, list);
+        }
+        return result;
+    }
 
-  /* The TvInput used for the test. */
-  sp<ITvInput> tv_input_;
+    /* Gets and updates the stream configurations for all existing devices. */
+    void updateAllStreamConfigurations() {
+        for (size_t i = 0; i < device_info_.size(); i++) {
+            int32_t device_id = device_info_.keyAt(i);
+            updateStreamConfigurations(device_id);
+        }
+    }
 
-  /* The TvInputCallback used for the test. */
-  sp<ITvInputCallback> tv_input_callback_;
+    /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
+    std::vector<size_t> getConfigIndices() {
+        std::vector<size_t> indices;
+        for (size_t i = 0; i < stream_config_.size(); i++) {
+            if (stream_config_.valueAt(i).size() != 0) {
+                indices.push_back(i);
+            }
+        }
+        return indices;
+    }
 
-  /*
-   * A KeyedVector stores device information of every available device.
-   * A key is a device ID and the corresponding value is the TvInputDeviceInfo.
-   */
-  android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_;
+    /*
+     * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums).
+     * Otherwise, returns the smallest missing non-negative integer.
+     */
+    int32_t getNumNotIn(std::vector<int32_t>& nums) {
+        int32_t result = DEFAULT_ID;
+        int32_t size = static_cast<int32_t>(nums.size());
+        for (int32_t i = 0; i < size; i++) {
+            // Put every element to its target position, if possible.
+            int32_t target_pos = nums[i];
+            while (target_pos >= 0 && target_pos < size && i != target_pos &&
+                   nums[i] != nums[target_pos]) {
+                std::swap(nums[i], nums[target_pos]);
+                target_pos = nums[i];
+            }
+        }
 
-  /*
-   * A KeyedVector stores a list of stream configurations of every available device.
-   * A key is a device ID and the corresponding value is the stream configuration list.
-   */
-  android::KeyedVector<int32_t, hidl_vec<TvStreamConfig>> stream_config_;
+        for (int32_t i = 0; i < size; i++) {
+            if (nums[i] != i) {
+                return i;
+            }
+        }
+        return result;
+    }
 
-  /* The mutex controls the access of shared data. */
-  std::mutex mutex_;
+    /* A simple test implementation of TvInputCallback for TV Input Events. */
+    class TvInputCallback : public ITvInputCallback {
+      public:
+        TvInputCallback(TvInputHidlTest& parent) : parent_(parent){};
+
+        virtual ~TvInputCallback() = default;
+
+        /*
+         * Notifies the client that an event has occurred. For possible event types,
+         * check TvInputEventType.
+         */
+        Return<void> notify(const TvInputEvent& event) override {
+            std::unique_lock<std::mutex> lock(parent_.mutex_);
+            switch (event.type) {
+                case TvInputEventType::DEVICE_AVAILABLE:
+                    parent_.onDeviceAvailable(event.deviceInfo);
+                    break;
+                case TvInputEventType::DEVICE_UNAVAILABLE:
+                    parent_.onDeviceUnavailable(event.deviceInfo.deviceId);
+                    break;
+                case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
+                    parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId);
+                    break;
+            }
+            return Void();
+        };
+
+      private:
+        /* The test contains this callback instance. */
+        TvInputHidlTest& parent_;
+    };
+
+    /* The TvInput used for the test. */
+    sp<ITvInput> tv_input_;
+
+    /* The TvInputCallback used for the test. */
+    sp<ITvInputCallback> tv_input_callback_;
+
+    /*
+     * A KeyedVector stores device information of every available device.
+     * A key is a device ID and the corresponding value is the TvInputDeviceInfo.
+     */
+    android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_;
+
+    /*
+     * A KeyedVector stores a list of stream configurations of every available device.
+     * A key is a device ID and the corresponding value is the stream configuration list.
+     */
+    android::KeyedVector<int32_t, hidl_vec<TvStreamConfig>> stream_config_;
+
+    /* The mutex controls the access of shared data. */
+    std::mutex mutex_;
 };
 
-
 /*
  * GetStreamConfigTest:
  * Calls updateStreamConfigurations() for each existing device
  * Checks returned results
  */
-TEST_F(TvInputHidlTest, GetStreamConfigTest) {
-  std::unique_lock<std::mutex> lock(mutex_);
-  for (size_t i = 0; i < device_info_.size(); i++) {
-    int32_t device_id = device_info_.keyAt(i);
-    Result result = updateStreamConfigurations(device_id);
-    EXPECT_EQ(Result::OK, result);
-  }
+TEST_P(TvInputHidlTest, GetStreamConfigTest) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    for (size_t i = 0; i < device_info_.size(); i++) {
+        int32_t device_id = device_info_.keyAt(i);
+        Result result = updateStreamConfigurations(device_id);
+        EXPECT_EQ(Result::OK, result);
+    }
 }
 
 /*
@@ -222,26 +205,24 @@
  * Calls openStream() and then closeStream() for each existing stream
  * Checks returned results
  */
-TEST_F(TvInputHidlTest, OpenAndCloseStreamTest) {
-  std::unique_lock<std::mutex> lock(mutex_);
-  updateAllStreamConfigurations();
-  for (size_t j = 0; j < stream_config_.size(); j++) {
-    int32_t device_id = stream_config_.keyAt(j);
-    hidl_vec<TvStreamConfig> config = stream_config_.valueAt(j);
-    for (size_t i = 0; i < config.size(); i++) {
-      Result result = Result::UNKNOWN;
-      int32_t stream_id = config[i].streamId;
-      tv_input_->openStream(device_id, stream_id,
-          [&result](Result res, const native_handle_t*) {
-              result = res;
-          });
-      EXPECT_EQ(Result::OK, result);
+TEST_P(TvInputHidlTest, OpenAndCloseStreamTest) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    updateAllStreamConfigurations();
+    for (size_t j = 0; j < stream_config_.size(); j++) {
+        int32_t device_id = stream_config_.keyAt(j);
+        hidl_vec<TvStreamConfig> config = stream_config_.valueAt(j);
+        for (size_t i = 0; i < config.size(); i++) {
+            Result result = Result::UNKNOWN;
+            int32_t stream_id = config[i].streamId;
+            tv_input_->openStream(device_id, stream_id,
+                                  [&result](Result res, const native_handle_t*) { result = res; });
+            EXPECT_EQ(Result::OK, result);
 
-      result = Result::UNKNOWN;
-      result = tv_input_->closeStream(device_id, stream_id);
-      EXPECT_EQ(Result::OK, result);
+            result = Result::UNKNOWN;
+            result = tv_input_->closeStream(device_id, stream_id);
+            EXPECT_EQ(Result::OK, result);
+        }
     }
-  }
 }
 
 /*
@@ -251,28 +232,26 @@
  * Checks returned results
  * The results should be Result::INVALID_ARGUMENTS
  */
-TEST_F(TvInputHidlTest, InvalidDeviceIdTest) {
-  std::unique_lock<std::mutex> lock(mutex_);
+TEST_P(TvInputHidlTest, InvalidDeviceIdTest) {
+    std::unique_lock<std::mutex> lock(mutex_);
 
-  std::vector<int32_t> device_ids;
-  for (size_t i = 0; i < device_info_.size(); i++) {
-    device_ids.push_back(device_info_.keyAt(i));
-  }
-  // Get a non-existing device ID.
-  int32_t id = getNumNotIn(device_ids);
-  EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id));
+    std::vector<int32_t> device_ids;
+    for (size_t i = 0; i < device_info_.size(); i++) {
+        device_ids.push_back(device_info_.keyAt(i));
+    }
+    // Get a non-existing device ID.
+    int32_t id = getNumNotIn(device_ids);
+    EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id));
 
-  Result result = Result::UNKNOWN;
-  int32_t stream_id = 0;
-  tv_input_->openStream(id, stream_id,
-      [&result](Result res, const native_handle_t*) {
-          result = res;
-      });
-  EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+    Result result = Result::UNKNOWN;
+    int32_t stream_id = 0;
+    tv_input_->openStream(id, stream_id,
+                          [&result](Result res, const native_handle_t*) { result = res; });
+    EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
 
-  result = Result::UNKNOWN;
-  result = tv_input_->closeStream(id, stream_id);
-  EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+    result = Result::UNKNOWN;
+    result = tv_input_->closeStream(id, stream_id);
+    EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
 }
 
 /*
@@ -281,35 +260,33 @@
  * Checks returned results
  * The results should be Result::INVALID_ARGUMENTS
  */
-TEST_F(TvInputHidlTest, InvalidStreamIdTest) {
-  std::unique_lock<std::mutex> lock(mutex_);
-  if (device_info_.isEmpty()) {
-    return;
-  }
-  updateAllStreamConfigurations();
-
-  int32_t device_id = device_info_.keyAt(0);
-  // Get a non-existing stream ID.
-  int32_t id = DEFAULT_ID;
-  if (stream_config_.indexOfKey(device_id) >= 0) {
-    std::vector<int32_t> stream_ids;
-    hidl_vec<TvStreamConfig> config = stream_config_.valueFor(device_id);
-    for (size_t i = 0; i < config.size(); i++) {
-      stream_ids.push_back(config[i].streamId);
+TEST_P(TvInputHidlTest, InvalidStreamIdTest) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    if (device_info_.isEmpty()) {
+        return;
     }
-    id = getNumNotIn(stream_ids);
-  }
+    updateAllStreamConfigurations();
 
-  Result result = Result::UNKNOWN;
-  tv_input_->openStream(device_id, id,
-      [&result](Result res, const native_handle_t*) {
-          result = res;
-      });
-  EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+    int32_t device_id = device_info_.keyAt(0);
+    // Get a non-existing stream ID.
+    int32_t id = DEFAULT_ID;
+    if (stream_config_.indexOfKey(device_id) >= 0) {
+        std::vector<int32_t> stream_ids;
+        hidl_vec<TvStreamConfig> config = stream_config_.valueFor(device_id);
+        for (size_t i = 0; i < config.size(); i++) {
+            stream_ids.push_back(config[i].streamId);
+        }
+        id = getNumNotIn(stream_ids);
+    }
 
-  result = Result::UNKNOWN;
-  result = tv_input_->closeStream(device_id, id);
-  EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+    Result result = Result::UNKNOWN;
+    tv_input_->openStream(device_id, id,
+                          [&result](Result res, const native_handle_t*) { result = res; });
+    EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+
+    result = Result::UNKNOWN;
+    result = tv_input_->closeStream(device_id, id);
+    EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
 }
 
 /*
@@ -318,28 +295,24 @@
  * Checks returned results
  * The result of the second call should be Result::INVALID_STATE
  */
-TEST_F(TvInputHidlTest, OpenAnOpenedStreamsTest) {
-  std::unique_lock<std::mutex> lock(mutex_);
-  updateAllStreamConfigurations();
-  std::vector<size_t> indices = getConfigIndices();
-  if (indices.empty()) {
-    return;
-  }
-  int32_t device_id = stream_config_.keyAt(indices[0]);
-  int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
+TEST_P(TvInputHidlTest, OpenAnOpenedStreamsTest) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    updateAllStreamConfigurations();
+    std::vector<size_t> indices = getConfigIndices();
+    if (indices.empty()) {
+        return;
+    }
+    int32_t device_id = stream_config_.keyAt(indices[0]);
+    int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
 
-  Result result = Result::UNKNOWN;
-  tv_input_->openStream(device_id, stream_id,
-      [&result](Result res, const native_handle_t*) {
-          result = res;
-      });
-  EXPECT_EQ(Result::OK, result);
+    Result result = Result::UNKNOWN;
+    tv_input_->openStream(device_id, stream_id,
+                          [&result](Result res, const native_handle_t*) { result = res; });
+    EXPECT_EQ(Result::OK, result);
 
-  tv_input_->openStream(device_id, stream_id,
-      [&result](Result res, const native_handle_t*) {
-          result = res;
-      });
-  EXPECT_EQ(Result::INVALID_STATE, result);
+    tv_input_->openStream(device_id, stream_id,
+                          [&result](Result res, const native_handle_t*) { result = res; });
+    EXPECT_EQ(Result::INVALID_STATE, result);
 }
 
 /*
@@ -348,24 +321,22 @@
  * Checks the returned result
  * The result should be Result::INVALID_STATE
  */
-TEST_F(TvInputHidlTest, CloseStreamBeforeOpenTest) {
-  std::unique_lock<std::mutex> lock(mutex_);
-  updateAllStreamConfigurations();
-  std::vector<size_t> indices = getConfigIndices();
-  if (indices.empty()) {
-    return;
-  }
-  int32_t device_id = stream_config_.keyAt(indices[0]);
-  int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
-  EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id));
+TEST_P(TvInputHidlTest, CloseStreamBeforeOpenTest) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    updateAllStreamConfigurations();
+    std::vector<size_t> indices = getConfigIndices();
+    if (indices.empty()) {
+        return;
+    }
+    int32_t device_id = stream_config_.keyAt(indices[0]);
+    int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
+    EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id));
 }
 
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(TvInputHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  TvInputHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TvInputHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITvInput::descriptor)),
+        android::hardware::PrintInstanceNameToString);
 
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TvInputHidlTest);
diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
index ceda2b3..756ab46 100644
--- a/tv/tuner/1.0/IFrontend.hal
+++ b/tv/tuner/1.0/IFrontend.hal
@@ -20,15 +20,16 @@
 import ILnb;
 
 /**
- * A Tuner Frontend is used to tune to a frequency and lock signal. It provide
- * live data feed to Tuner Demux interface.
+ * A Tuner Frontend is used to tune to a frequency and lock signal.
+ *
+ * IFrontend provides a bit stream to the Tuner Demux interface.
  */
 interface IFrontend {
     /**
-     * Set the callback
+     * Set the frontend callback.
      *
-     * It is used by the client to receive events from the Frontend.
-     * Only one callback for one Frontend instance is supported. The callback
+     * IFrontendCallback is used by the client to receive events from the Frontend.
+     * Only one callback per IFrontend instance is supported. The callback
      * will be replaced if it's set again.
      *
      * @param callback Callback object to pass Frontend events to the system.
@@ -42,14 +43,14 @@
     setCallback(IFrontendCallback callback) generates (Result result);
 
     /**
-     * Tuning Frontend
+     * Tunes the frontend to using the settings given.
      *
-     * It is used by the client to lock a frequency by providing signal
-     * delivery information. If previous tuning isn't completed, this call must
-     * stop previous tuning, and start a new tuning. Tune is a async call.
-     * LOCKED or NO_SIGNAL eventi is sent back to caller through callback.
+     * This locks the frontend to a frequency by providing signal
+     * delivery information. If previous tuning isn't completed, this call MUST
+     * stop previous tuning, and start a new tuning.
+     * Tune is an async call, with LOCKED or NO_SIGNAL events sent via callback.
      *
-     * @param settings Signal delivery information which frontend can use to
+     * @param settings Signal delivery information the frontend uses to
      * search and lock the signal.
      *
      * @return result Result status of the operation.
@@ -60,9 +61,10 @@
     tune(FrontendSettings settings) generates (Result result);
 
     /**
-     * Stop the tuning
+     * Stops a previous tuning.
      *
-     * It is used by the client to stop a previous tuning.
+     * If the method completes successfully the frontend is no longer tuned and no data
+     * will be sent to attached demuxes.
      *
      * @return result Result status of the operation.
      *         SUCCESS if successfully stop tuning.
@@ -71,10 +73,10 @@
     stopTune() generates (Result result);
 
     /**
-     * Release the Frontend instance
+     * Releases the Frontend instance
      *
-     * It is used by the client to release the frontend instance. HAL clear
-     * underneath resource. client mustn't access the instance any more.
+     * Associated resources are released.  close may be called more than once.
+     * Calls to any other method after this will return an error
      *
      * @return result Result status of the operation.
      *         SUCCESS if successful,
@@ -148,7 +150,7 @@
     setLnb(LnbId lnbId) generates (Result result);
 
     /**
-     * Enble or Disable Low Noise Amplifier (LNA).
+     * Enable or Disable Low Noise Amplifier (LNA).
      *
      * @param bEnable true if activate LNA module; false if deactivate LNA
      *
diff --git a/tv/tuner/1.0/TEST_MAPPING b/tv/tuner/1.0/TEST_MAPPING
new file mode 100644
index 0000000..1979887
--- /dev/null
+++ b/tv/tuner/1.0/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalTvTunerV1_0TargetTest"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd
new file mode 100644
index 0000000..45c01c1
--- /dev/null
+++ b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd
@@ -0,0 +1,111 @@
+<?xml version="1.0"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+         Licensed under the Apache License, Version 2.0 (the "License");
+         you may not use this file except in compliance with the License.
+         You may obtain a copy of the License at
+
+                    http://www.apache.org/licenses/LICENSE-2.0
+
+         Unless required by applicable law or agreed to in writing, software
+         distributed under the License is distributed on an "AS IS" BASIS,
+         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+         See the License for the specific language governing permissions and
+         limitations under the License.
+-->
+<xs:schema version="1.0"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <!-- List of the Tuner Resource Manager client use case priority hint. -->
+    <xs:simpleType name="version">
+        <xs:restriction base="xs:decimal">
+            <xs:enumeration value="1.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="config">
+        <xs:sequence>
+            <xs:element name="useCaseDefault" type="useCaseDefault" minOccurs="1" maxOccurs="1"/>
+            <xs:element name="useCasePreDefined" type="useCasePreDefined" minOccurs="0" maxOccurs="5"/>
+            <xs:element name="useCaseVendor" type="useCaseVendor" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="version" type="version"/>
+    </xs:complexType>
+
+    <xs:complexType name="useCaseDefault">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                useCaseDefault section:
+                Default value for predefined use cases priority hint.
+                    "fgPriority": priority when the use case is in foreground.
+                    "bgPriority": priority when the use case is in background.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="fgPriority" type="priority"/>
+        <xs:attribute name="bgPriority" type="priority"/>
+    </xs:complexType>
+
+    <xs:complexType name="useCasePreDefined">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                useCasePreDefined section:
+                A list of predefined use cases and their foreground/background priority hint.
+                Each use case has the following attributes:
+                    "type": type of the use case. Pre-defined use cases start with "USE_CASE_"
+                            and have been predefined in "predefinedUseCaseType".
+                    "fgPriority": priority when the use case is in foreground.
+                    "bgPriority": priority when the use case is in background.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="type" type="predefinedUseCaseType"/>
+        <xs:attribute name="fgPriority" type="priority"/>
+        <xs:attribute name="bgPriority" type="priority"/>
+    </xs:complexType>
+
+    <xs:complexType name="useCaseVendor">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                useCaseVendor section:
+                A list of vendor defined use cases and their foreground/background priority hint.
+                Each use case has the following attributes:
+                    "type": type of the use case. Vendor defined use cases start with "VENDOR_USE_CASE_".
+                    "fgPriority": priority when the use case is in foreground.
+                    "bgPriority": priority when the use case is in background.
+                    "id": Vendor defined use case must have an id greater than 1000 to be associated with.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="type" type="vendorUseCaseType"/>
+        <xs:attribute name="id" type="id"/>
+        <xs:attribute name="fgPriority" type="priority"/>
+        <xs:attribute name="bgPriority" type="priority"/>
+    </xs:complexType>
+
+    <xs:simpleType name="predefinedUseCaseType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="USE_CASE_RECORD"/>
+            <xs:enumeration value="USE_CASE_LIVE"/>
+            <xs:enumeration value="USE_CASE_PLAYBACK"/>
+            <xs:enumeration value="USE_CASE_SCAN"/>
+            <xs:enumeration value="USE_CASE_BACKGROUND"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="vendorUseCaseType">
+        <xs:restriction base="xs:string">
+            <xs:pattern value="VENDOR_USE_CASE_[_A-Z0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="priority">
+        <xs:restriction base="xs:integer">
+            <xs:minInclusive value="0"/>
+            <xs:maxInclusive value="1000"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="id">
+        <xs:restriction base="xs:integer">
+            <xs:minInclusive value="1001"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:element name="config" type="config"/>
+</xs:schema>
diff --git a/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml
new file mode 100644
index 0000000..938faeb
--- /dev/null
+++ b/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+         Licensed under the Apache License, Version 2.0 (the "License");
+         you may not use this file except in compliance with the License.
+         You may obtain a copy of the License at
+
+                    http://www.apache.org/licenses/LICENSE-2.0
+
+         Unless required by applicable law or agreed to in writing, software
+         distributed under the License is distributed on an "AS IS" BASIS,
+         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+         See the License for the specific language governing permissions and
+         limitations under the License.
+-->
+<!-- A sample Tuner Resource Manager use case priority configuration xml -->
+<config version="1.0" xmlns:xi="http://www.w3.org/2001/XMLSchema">
+    <!-- useCaseDefault section:
+        Default value for predefined use cases priority hint.
+            "fgPriority": priority when the use case is in foreground. Value range [0-1000].
+            "bgPriority": priority when the use case is in background. Value range [0-1000].
+    -->
+    <useCaseDefault fgPriority="150" bgPriority="50"/>
+    <!-- useCasePreDefined section:
+        A list of predefined use cases and their foreground/background priority hint.
+        Each use case has the following attributes:
+            "type": type of the use case. Pre-defined use cases start with "USE_CASE_"
+                    and could only use the types defined in "predefinedUseCaseType" in xsd.
+            "fgPriority": priority when the use case is in foreground. Value range [0-1000].
+            "bgPriority": priority when the use case is in background. Value range [0-1000].
+    -->
+    <useCasePreDefined type="USE_CASE_RECORD" fgPriority="600" bgPriority="500"/>
+    <useCasePreDefined type="USE_CASE_LIVE" fgPriority="490" bgPriority="400"/>
+    <useCasePreDefined type="USE_CASE_PLAYBACK" fgPriority="480" bgPriority="300"/>
+    <useCasePreDefined type="USE_CASE_SCAN" fgPriority="450" bgPriority="200"/>
+    <useCasePreDefined type="USE_CASE_BACKGROUND" fgPriority="180" bgPriority="100"/>
+    <!-- useCaseVendor section:
+        A list of vendor defined use cases and their foreground/background priority hint.
+        Each use case has the following attributes:
+            "type": type of the use case. Vendor defined use cases start with "VENDOR_USE_CASE_".
+            "fgPriority": priority when the use case is in foreground. Value range [0-1000].
+            "bgPriority": priority when the use case is in background. Value range [0-1000].
+            "id": Vendor defined use case must have an id greater than 1000 to be associated with.
+    -->
+    <useCaseVendor type="VENDOR_USE_CASE_SPECIAL_1" id="1001" fgPriority="300" bgPriority="80"/>
+    <useCaseVendor type="VENDOR_USE_CASE_SPECIAL_2" id="1002" fgPriority="200" bgPriority="40"/>
+</config>
diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp
index 989e25c..5711889 100644
--- a/tv/tuner/1.0/default/Android.bp
+++ b/tv/tuner/1.0/default/Android.bp
@@ -24,6 +24,7 @@
         "libfmq",
         "libhidlbase",
         "libhidlmemory",
+        "libion",
         "liblog",
         "libstagefright_foundation",
         "libutils",
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index 43c4e3a..67eff1b 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -48,11 +48,9 @@
         return Result::INVALID_STATE;
     }
 
-    mFrontendSourceFile = mFrontend->getSourceFile();
-
     mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
 
-    return startFrontendInputLoop();
+    return Result::SUCCESS;
 }
 
 Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
@@ -60,19 +58,10 @@
     ALOGV("%s", __FUNCTION__);
 
     uint32_t filterId;
-
-    if (!mUnusedFilterIds.empty()) {
-        filterId = *mUnusedFilterIds.begin();
-
-        mUnusedFilterIds.erase(filterId);
-    } else {
-        filterId = ++mLastUsedFilterId;
-    }
-
-    mUsedFilterIds.insert(filterId);
+    filterId = ++mLastUsedFilterId;
 
     if (cb == nullptr) {
-        ALOGW("callback can't be null");
+        ALOGW("[Demux] callback can't be null");
         _hidl_cb(Result::INVALID_ARGUMENT, new Filter());
         return Void();
     }
@@ -85,33 +74,79 @@
     }
 
     mFilters[filterId] = filter;
+    if (filter->isPcrFilter()) {
+        mPcrFilterIds.insert(filterId);
+    }
+    bool result = true;
+    if (!filter->isRecordFilter()) {
+        // Only save non-record filters for now. Record filters are saved when the
+        // IDvr.attacheFilter is called.
+        mPlaybackFilterIds.insert(filterId);
+        if (mDvrPlayback != nullptr) {
+            result = mDvrPlayback->addPlaybackFilter(filterId, filter);
+        }
+    }
 
-    _hidl_cb(Result::SUCCESS, filter);
+    _hidl_cb(result ? Result::SUCCESS : Result::INVALID_ARGUMENT, filter);
     return Void();
 }
 
 Return<void> Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    sp<TimeFilter> timeFilter = new TimeFilter(this);
+    mTimeFilter = new TimeFilter(this);
 
-    _hidl_cb(Result::SUCCESS, timeFilter);
+    _hidl_cb(Result::SUCCESS, mTimeFilter);
     return Void();
 }
 
-Return<void> Demux::getAvSyncHwId(const sp<IFilter>& /* filter */, getAvSyncHwId_cb _hidl_cb) {
+Return<void> Demux::getAvSyncHwId(const sp<IFilter>& filter, getAvSyncHwId_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    AvSyncHwId avSyncHwId = 0;
+    uint32_t avSyncHwId = -1;
+    int id;
+    Result status;
 
-    _hidl_cb(Result::SUCCESS, avSyncHwId);
+    filter->getId([&](Result result, uint32_t filterId) {
+        id = filterId;
+        status = result;
+    });
+
+    if (status != Result::SUCCESS) {
+        ALOGE("[Demux] Can't get filter Id.");
+        _hidl_cb(Result::INVALID_STATE, avSyncHwId);
+        return Void();
+    }
+
+    if (!mFilters[id]->isMediaFilter()) {
+        ALOGE("[Demux] Given filter is not a media filter.");
+        _hidl_cb(Result::INVALID_ARGUMENT, avSyncHwId);
+        return Void();
+    }
+
+    if (!mPcrFilterIds.empty()) {
+        // Return the lowest pcr filter id in the default implementation as the av sync id
+        _hidl_cb(Result::SUCCESS, *mPcrFilterIds.begin());
+        return Void();
+    }
+
+    ALOGE("[Demux] No PCR filter opened.");
+    _hidl_cb(Result::INVALID_STATE, avSyncHwId);
     return Void();
 }
 
-Return<void> Demux::getAvSyncTime(AvSyncHwId /* avSyncHwId */, getAvSyncTime_cb _hidl_cb) {
+Return<void> Demux::getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    uint64_t avSyncTime = 0;
+    uint64_t avSyncTime = -1;
+    if (mPcrFilterIds.empty()) {
+        _hidl_cb(Result::INVALID_STATE, avSyncTime);
+        return Void();
+    }
+    if (avSyncHwId != *mPcrFilterIds.begin()) {
+        _hidl_cb(Result::INVALID_ARGUMENT, avSyncTime);
+        return Void();
+    }
 
     _hidl_cb(Result::SUCCESS, avSyncTime);
     return Void();
@@ -120,8 +155,13 @@
 Return<Result> Demux::close() {
     ALOGV("%s", __FUNCTION__);
 
-    mUnusedFilterIds.clear();
-    mUsedFilterIds.clear();
+    set<uint32_t>::iterator it;
+    for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+        mDvrPlayback->removePlaybackFilter(*it);
+    }
+    mPlaybackFilterIds.clear();
+    mRecordFilterIds.clear();
+    mFilters.clear();
     mLastUsedFilterId = -1;
 
     return Result::SUCCESS;
@@ -132,20 +172,43 @@
     ALOGV("%s", __FUNCTION__);
 
     if (cb == nullptr) {
-        ALOGW("DVR callback can't be null");
+        ALOGW("[Demux] DVR callback can't be null");
         _hidl_cb(Result::INVALID_ARGUMENT, new Dvr());
         return Void();
     }
 
-    mDvr = new Dvr(type, bufferSize, cb, this);
+    set<uint32_t>::iterator it;
+    switch (type) {
+        case DvrType::PLAYBACK:
+            mDvrPlayback = new Dvr(type, bufferSize, cb, this);
+            if (!mDvrPlayback->createDvrMQ()) {
+                _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback);
+                return Void();
+            }
 
-    if (!mDvr->createDvrMQ()) {
-        _hidl_cb(Result::UNKNOWN_ERROR, mDvr);
-        return Void();
+            for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+                if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) {
+                    ALOGE("[Demux] Can't get filter info for DVR playback");
+                    _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback);
+                    return Void();
+                }
+            }
+
+            _hidl_cb(Result::SUCCESS, mDvrPlayback);
+            return Void();
+        case DvrType::RECORD:
+            mDvrRecord = new Dvr(type, bufferSize, cb, this);
+            if (!mDvrRecord->createDvrMQ()) {
+                _hidl_cb(Result::UNKNOWN_ERROR, mDvrRecord);
+                return Void();
+            }
+
+            _hidl_cb(Result::SUCCESS, mDvrRecord);
+            return Void();
+        default:
+            _hidl_cb(Result::INVALID_ARGUMENT, nullptr);
+            return Void();
     }
-
-    _hidl_cb(Result::SUCCESS, mDvr);
-    return Void();
 }
 
 Return<Result> Demux::connectCiCam(uint32_t ciCamId) {
@@ -165,10 +228,11 @@
 Result Demux::removeFilter(uint32_t filterId) {
     ALOGV("%s", __FUNCTION__);
 
-    // resetFilterRecords(filterId);
-    mUsedFilterIds.erase(filterId);
+    if (mDvrPlayback != nullptr) {
+        mDvrPlayback->removePlaybackFilter(filterId);
+    }
+    mPlaybackFilterIds.erase(filterId);
     mRecordFilterIds.erase(filterId);
-    mUnusedFilterIds.insert(filterId);
     mFilters.erase(filterId);
 
     return Result::SUCCESS;
@@ -176,11 +240,11 @@
 
 void Demux::startBroadcastTsFilter(vector<uint8_t> data) {
     set<uint32_t>::iterator it;
-    for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
-        uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
-        if (DEBUG_FILTER) {
-            ALOGW("start ts filter pid: %d", pid);
-        }
+    uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
+    if (DEBUG_DEMUX) {
+        ALOGW("[Demux] start ts filter pid: %d", pid);
+    }
+    for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
         if (pid == mFilters[*it]->getTpid()) {
             mFilters[*it]->updateFilterOutput(data);
         }
@@ -189,10 +253,10 @@
 
 void Demux::sendFrontendInputToRecord(vector<uint8_t> data) {
     set<uint32_t>::iterator it;
+    if (DEBUG_DEMUX) {
+        ALOGW("[Demux] update record filter output");
+    }
     for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
-        if (DEBUG_FILTER) {
-            ALOGW("update record filter output");
-        }
         mFilters[*it]->updateRecordOutput(data);
     }
 }
@@ -201,7 +265,7 @@
     set<uint32_t>::iterator it;
 
     // Handle the output data per filter type
-    for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
+    for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
         if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) {
             return false;
         }
@@ -234,11 +298,9 @@
     return mFilters[filterId]->getTpid();
 }
 
-Result Demux::startFrontendInputLoop() {
+void Demux::startFrontendInputLoop() {
     pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
     pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
-
-    return Result::SUCCESS;
 }
 
 void* Demux::__threadLoopFrontend(void* user) {
@@ -250,58 +312,27 @@
 void Demux::frontendInputThreadLoop() {
     std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
     mFrontendInputThreadRunning = true;
-    mKeepFetchingDataFromFrontend = true;
-
-    // open the stream and get its length
-    std::ifstream inputData(mFrontendSourceFile, std::ifstream::binary);
-    // TODO take the packet size from the frontend setting
-    int packetSize = 188;
-    int writePacketAmount = 6;
-    char* buffer = new char[packetSize];
-    ALOGW("[Demux] Frontend input thread loop start %s", mFrontendSourceFile.c_str());
-    if (!inputData.is_open()) {
-        mFrontendInputThreadRunning = false;
-        ALOGW("[Demux] Error %s", strerror(errno));
-    }
 
     while (mFrontendInputThreadRunning) {
-        // move the stream pointer for packet size * 6 every read until the end
-        while (mKeepFetchingDataFromFrontend) {
-            for (int i = 0; i < writePacketAmount; i++) {
-                inputData.read(buffer, packetSize);
-                if (!inputData) {
-                    mKeepFetchingDataFromFrontend = false;
-                    mFrontendInputThreadRunning = false;
-                    break;
-                }
-                // filter and dispatch filter output
-                vector<uint8_t> byteBuffer;
-                byteBuffer.resize(packetSize);
-                for (int index = 0; index < byteBuffer.size(); index++) {
-                    byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
-                }
-                if (mIsRecording) {
-                    // Feed the data into the Dvr recording input
-                    sendFrontendInputToRecord(byteBuffer);
-                } else {
-                    // Feed the data into the broadcast demux filter
-                    startBroadcastTsFilter(byteBuffer);
-                }
-            }
-            if (mIsRecording) {
-                // Dispatch the data into the broadcasting filters.
-                startRecordFilterDispatcher();
-            } else {
-                // Dispatch the data into the broadcasting filters.
-                startBroadcastFilterDispatcher();
-            }
-            usleep(100);
+        uint32_t efState = 0;
+        status_t status = mDvrPlayback->getDvrEventFlag()->wait(
+                static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+                true /* retry on spurious wake */);
+        if (status != OK) {
+            ALOGD("[Demux] wait for data ready on the playback FMQ");
+            continue;
+        }
+        // Our current implementation filter the data and write it into the filter FMQ immediately
+        // after the DATA_READY from the VTS/framework
+        if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
+            !mDvrPlayback->startFilterDispatcher(true /*isVirtualFrontend*/, mIsRecording)) {
+            ALOGE("[Demux] playback data failed to be filtered. Ending thread");
+            break;
         }
     }
 
+    mFrontendInputThreadRunning = false;
     ALOGW("[Demux] Frontend Input thread end.");
-    delete[] buffer;
-    inputData.close();
 }
 
 void Demux::stopFrontendInput() {
@@ -316,18 +347,19 @@
 }
 
 bool Demux::attachRecordFilter(int filterId) {
-    if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+    if (mFilters[filterId] == nullptr || mDvrRecord == nullptr ||
+        !mFilters[filterId]->isRecordFilter()) {
         return false;
     }
 
     mRecordFilterIds.insert(filterId);
-    mFilters[filterId]->attachFilterToRecord(mDvr);
+    mFilters[filterId]->attachFilterToRecord(mDvrRecord);
 
     return true;
 }
 
 bool Demux::detachRecordFilter(int filterId) {
-    if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+    if (mFilters[filterId] == nullptr || mDvrRecord == nullptr) {
         return false;
     }
 
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index 1405d0c..7f282b2 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -89,6 +89,18 @@
     void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
     uint16_t getFilterTpid(uint32_t filterId);
     void setIsRecording(bool isRecording);
+    void startFrontendInputLoop();
+
+    /**
+     * A dispatcher to read and dispatch input data to all the started filters.
+     * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     * Note that recording filters are not included.
+     */
+    bool startBroadcastFilterDispatcher();
+    void startBroadcastTsFilter(vector<uint8_t> data);
+
+    void sendFrontendInputToRecord(vector<uint8_t> data);
+    bool startRecordFilterDispatcher();
 
   private:
     // Tuner service
@@ -96,7 +108,6 @@
 
     // Frontend source
     sp<Frontend> mFrontend;
-    string mFrontendSourceFile;
 
     // A struct that passes the arguments to a newly created filter thread
     struct ThreadArgs {
@@ -104,7 +115,6 @@
         uint32_t filterId;
     };
 
-    Result startFrontendInputLoop();
     static void* __threadLoopFrontend(void* user);
     void frontendInputThreadLoop();
 
@@ -117,51 +127,41 @@
      */
     void deleteEventFlag();
     bool readDataFromMQ();
-    /**
-     * A dispatcher to read and dispatch input data to all the started filters.
-     * Each filter handler handles the data filtering/output writing/filterEvent updating.
-     * Note that recording filters are not included.
-     */
-    bool startBroadcastFilterDispatcher();
-    void startBroadcastTsFilter(vector<uint8_t> data);
-
-    void sendFrontendInputToRecord(vector<uint8_t> data);
-    bool startRecordFilterDispatcher();
 
     uint32_t mDemuxId;
     uint32_t mCiCamId;
+    set<uint32_t> mPcrFilterIds;
     /**
      * Record the last used filter id. Initial value is -1.
      * Filter Id starts with 0.
      */
     uint32_t mLastUsedFilterId = -1;
     /**
-     * Record all the used filter Ids.
+     * Record all the used playback filter Ids.
      * Any removed filter id should be removed from this set.
      */
-    set<uint32_t> mUsedFilterIds;
-    /**
-     * Record all the unused filter Ids within mLastUsedFilterId.
-     * Removed filter Id should be added into this set.
-     * When this set is not empty, ids here should be allocated first
-     * and added into usedFilterIds.
-     */
-    set<uint32_t> mUnusedFilterIds;
+    set<uint32_t> mPlaybackFilterIds;
     /**
      * Record all the attached record filter Ids.
      * Any removed filter id should be removed from this set.
      */
     set<uint32_t> mRecordFilterIds;
     /**
-     * A list of created FilterMQ ptrs.
+     * A list of created Filter sp.
      * The array number is the filter ID.
      */
     std::map<uint32_t, sp<Filter>> mFilters;
 
     /**
+     * Local reference to the opened Timer Filter instance.
+     */
+    sp<TimeFilter> mTimeFilter;
+
+    /**
      * Local reference to the opened DVR object.
      */
-    sp<Dvr> mDvr;
+    sp<Dvr> mDvrPlayback;
+    sp<Dvr> mDvrRecord;
 
     // Thread handlers
     pthread_t mFrontendInputThread;
@@ -188,7 +188,7 @@
     int mPesSizeLeft = 0;
     vector<uint8_t> mPesOutput;
 
-    const bool DEBUG_FILTER = false;
+    const bool DEBUG_DEMUX = false;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
index 3088a9d..68e175c 100644
--- a/tv/tuner/1.0/default/Dvr.cpp
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -70,14 +70,10 @@
         return status;
     }
 
-    // check if the attached filter is a record filter
-
-    mFilters[filterId] = filter;
-    mIsRecordFilterAttached = true;
+    // TODO check if the attached filter is a record filter
     if (!mDemux->attachRecordFilter(filterId)) {
         return Result::INVALID_ARGUMENT;
     }
-    mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
 
     return Result::SUCCESS;
 }
@@ -97,20 +93,8 @@
         return status;
     }
 
-    std::map<uint32_t, sp<IFilter>>::iterator it;
-
-    it = mFilters.find(filterId);
-    if (it != mFilters.end()) {
-        mFilters.erase(filterId);
-        if (!mDemux->detachRecordFilter(filterId)) {
-            return Result::INVALID_ARGUMENT;
-        }
-    }
-
-    // If all the filters are detached, record can't be started
-    if (mFilters.empty()) {
-        mIsRecordFilterAttached = false;
-        mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
+    if (!mDemux->detachRecordFilter(filterId)) {
+        return Result::INVALID_ARGUMENT;
     }
 
     return Result::SUCCESS;
@@ -132,8 +116,7 @@
         pthread_setname_np(mDvrThread, "playback_waiting_loop");
     } else if (mType == DvrType::RECORD) {
         mRecordStatus = RecordStatus::DATA_READY;
-        mIsRecordStarted = true;
-        mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
+        mDemux->setIsRecording(mType == DvrType::RECORD);
     }
 
     // TODO start another thread to send filter status callback to the framework
@@ -149,7 +132,7 @@
     std::lock_guard<std::mutex> lock(mDvrThreadLock);
 
     mIsRecordStarted = false;
-    mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
+    mDemux->setIsRecording(false);
 
     return Result::SUCCESS;
 }
@@ -175,7 +158,7 @@
     std::unique_ptr<DvrMQ> tmpDvrMQ =
             std::unique_ptr<DvrMQ>(new (std::nothrow) DvrMQ(mBufferSize, true));
     if (!tmpDvrMQ->isValid()) {
-        ALOGW("Failed to create FMQ of DVR");
+        ALOGW("[Dvr] Failed to create FMQ of DVR");
         return false;
     }
 
@@ -188,6 +171,10 @@
     return true;
 }
 
+EventFlag* Dvr::getDvrEventFlag() {
+    return mDvrEventFlag;
+}
+
 void* Dvr::__threadLoopPlayback(void* user) {
     Dvr* const self = static_cast<Dvr*>(user);
     self->playbackThreadLoop();
@@ -210,8 +197,9 @@
         }
         // Our current implementation filter the data and write it into the filter FMQ immediately
         // after the DATA_READY from the VTS/framework
-        if (!readPlaybackFMQ() || !startFilterDispatcher()) {
-            ALOGD("[Dvr] playback data failed to be filtered. Ending thread");
+        if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
+            !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) {
+            ALOGE("[Dvr] playback data failed to be filtered. Ending thread");
             break;
         }
 
@@ -250,19 +238,26 @@
     return mPlaybackStatus;
 }
 
-bool Dvr::readPlaybackFMQ() {
+bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
     // Read playback data from the input FMQ
     int size = mDvrMQ->availableToRead();
     int playbackPacketSize = mDvrSettings.playback().packetSize;
     vector<uint8_t> dataOutputBuffer;
     dataOutputBuffer.resize(playbackPacketSize);
-
     // Dispatch the packet to the PID matching filter output buffer
     for (int i = 0; i < size / playbackPacketSize; i++) {
         if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
             return false;
         }
-        startTpidFilter(dataOutputBuffer);
+        if (isVirtualFrontend) {
+            if (isRecording) {
+                mDemux->sendFrontendInputToRecord(dataOutputBuffer);
+            } else {
+                mDemux->startBroadcastTsFilter(dataOutputBuffer);
+            }
+        } else {
+            startTpidFilter(dataOutputBuffer);
+        }
     }
 
     return true;
@@ -281,9 +276,16 @@
     }
 }
 
-bool Dvr::startFilterDispatcher() {
-    std::map<uint32_t, sp<IFilter>>::iterator it;
+bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
+    if (isVirtualFrontend) {
+        if (isRecording) {
+            return mDemux->startRecordFilterDispatcher();
+        } else {
+            return mDemux->startBroadcastFilterDispatcher();
+        }
+    }
 
+    std::map<uint32_t, sp<IFilter>>::iterator it;
     // Handle the output data per filter type
     for (it = mFilters.begin(); it != mFilters.end(); it++) {
         if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
@@ -296,7 +298,10 @@
 
 bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
     std::lock_guard<std::mutex> lock(mWriteLock);
-    ALOGW("[Dvr] write record FMQ");
+    if (mRecordStatus == RecordStatus::OVERFLOW) {
+        ALOGW("[Dvr] stops writing and wait for the client side flushing.");
+        return true;
+    }
     if (mDvrMQ->write(data.data(), data.size())) {
         mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
         maySendRecordStatusCallback();
@@ -333,6 +338,15 @@
     return mRecordStatus;
 }
 
+bool Dvr::addPlaybackFilter(uint32_t filterId, sp<IFilter> filter) {
+    mFilters[filterId] = filter;
+    return true;
+}
+
+bool Dvr::removePlaybackFilter(uint32_t filterId) {
+    mFilters.erase(filterId);
+    return true;
+}
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
index f39d8db..a63a256 100644
--- a/tv/tuner/1.0/default/Dvr.h
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -81,6 +81,11 @@
     bool createDvrMQ();
     void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer);
     bool writeRecordFMQ(const std::vector<uint8_t>& data);
+    bool addPlaybackFilter(uint32_t filterId, sp<IFilter> filter);
+    bool removePlaybackFilter(uint32_t filterId);
+    bool readPlaybackFMQ(bool isVirtualFrontend, bool isRecording);
+    bool startFilterDispatcher(bool isVirtualFrontend, bool isRecording);
+    EventFlag* getDvrEventFlag();
 
   private:
     // Demux service
@@ -103,9 +108,7 @@
      * A dispatcher to read and dispatch input data to all the started filters.
      * Each filter handler handles the data filtering/output writing/filterEvent updating.
      */
-    bool readPlaybackFMQ();
     void startTpidFilter(vector<uint8_t> data);
-    bool startFilterDispatcher();
     static void* __threadLoopPlayback(void* user);
     static void* __threadLoopRecord(void* user);
     void playbackThreadLoop();
@@ -121,7 +124,6 @@
 
     // Thread handlers
     pthread_t mDvrThread;
-    pthread_t mBroadcastInputThread;
 
     // FMQ status local records
     PlaybackStatus mPlaybackStatus;
@@ -130,7 +132,6 @@
      * If a specific filter's writing loop is still running
      */
     bool mDvrThreadRunning;
-    bool mBroadcastInputThreadRunning;
     bool mKeepFetchingDataFromFrontend;
     /**
      * Lock to protect writes to the FMQs
@@ -141,7 +142,6 @@
      */
     std::mutex mPlaybackStatusLock;
     std::mutex mRecordStatusLock;
-    std::mutex mBroadcastInputThreadLock;
     std::mutex mDvrThreadLock;
 
     const bool DEBUG_DVR = false;
@@ -149,7 +149,6 @@
     // Booleans to check if recording is running.
     // Recording is ready when both of the following are set to true.
     bool mIsRecordStarted = false;
-    bool mIsRecordFilterAttached = false;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
index 54d0952..30b19c0 100644
--- a/tv/tuner/1.0/default/Filter.cpp
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -37,6 +37,38 @@
     mBufferSize = bufferSize;
     mCallback = cb;
     mDemux = demux;
+
+    switch (mType.mainType) {
+        case DemuxFilterMainType::TS:
+            if (mType.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
+                mType.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
+                mIsMediaFilter = true;
+            }
+            if (mType.subType.tsFilterType() == DemuxTsFilterType::PCR) {
+                mIsPcrFilter = true;
+            }
+            if (mType.subType.tsFilterType() == DemuxTsFilterType::RECORD) {
+                mIsRecordFilter = true;
+            }
+            break;
+        case DemuxFilterMainType::MMTP:
+            if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
+                mType.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
+                mIsMediaFilter = true;
+            }
+            if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::RECORD) {
+                mIsRecordFilter = true;
+            }
+            break;
+        case DemuxFilterMainType::IP:
+            break;
+        case DemuxFilterMainType::TLV:
+            break;
+        case DemuxFilterMainType::ALP:
+            break;
+        default:
+            break;
+    }
 }
 
 Filter::~Filter() {}
@@ -60,6 +92,8 @@
 Return<void> Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
+    mIsUsingFMQ = true;
+
     _hidl_cb(Result::SUCCESS, *mFilterMQ->getDesc());
     return Void();
 }
@@ -73,16 +107,12 @@
             mTpid = settings.ts().tpid;
             break;
         case DemuxFilterMainType::MMTP:
-            /*mmtpSettings*/
             break;
         case DemuxFilterMainType::IP:
-            /*ipSettings*/
             break;
         case DemuxFilterMainType::TLV:
-            /*tlvSettings*/
             break;
         case DemuxFilterMainType::ALP:
-            /*alpSettings*/
             break;
         default:
             break;
@@ -120,9 +150,13 @@
     return Result::SUCCESS;
 }
 
-Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t /*avDataId*/) {
+Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t avDataId) {
     ALOGV("%s", __FUNCTION__);
+    if (mDataId2Avfd.find(avDataId) == mDataId2Avfd.end()) {
+        return Result::INVALID_ARGUMENT;
+    }
 
+    ::close(mDataId2Avfd[avDataId]);
     return Result::SUCCESS;
 }
 
@@ -139,7 +173,7 @@
     std::unique_ptr<FilterMQ> tmpFilterMQ =
             std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(mBufferSize, true));
     if (!tmpFilterMQ->isValid()) {
-        ALOGW("Failed to create FMQ of filter with id: %d", mFilterId);
+        ALOGW("[Filter] Failed to create FMQ of filter with id: %d", mFilterId);
         return false;
     }
 
@@ -174,14 +208,21 @@
     // Event Callback without waiting for the DATA_CONSUMED to init the process.
     while (mFilterThreadRunning) {
         if (mFilterEvent.events.size() == 0) {
-            ALOGD("[Filter] wait for filter data output.");
+            if (DEBUG_FILTER) {
+                ALOGD("[Filter] wait for filter data output.");
+            }
             usleep(1000 * 1000);
             continue;
         }
         // After successfully write, send a callback and wait for the read to be done
         mCallback->onFilterEvent(mFilterEvent);
+        freeAvHandle();
         mFilterEvent.events.resize(0);
         mFilterStatus = DemuxFilterStatus::DATA_READY;
+        if (mCallback == nullptr) {
+            ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId);
+            break;
+        }
         mCallback->onFilterStatus(mFilterStatus);
         break;
     }
@@ -191,7 +232,7 @@
         // We do not wait for the last round of written data to be read to finish the thread
         // because the VTS can verify the reading itself.
         for (int i = 0; i < SECTION_WRITE_COUNT; i++) {
-            while (mFilterThreadRunning) {
+            while (mFilterThreadRunning && mIsUsingFMQ) {
                 status_t status = mFilterEventFlag->wait(
                         static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
                         WAIT_TIMEOUT, true /* retry on spurious wake */);
@@ -202,11 +243,6 @@
                 break;
             }
 
-            if (mCallback == nullptr) {
-                ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId);
-                break;
-            }
-
             maySendFilterStatusCallback();
 
             while (mFilterThreadRunning) {
@@ -232,7 +268,20 @@
     ALOGD("[Filter] filter thread ended.");
 }
 
+void Filter::freeAvHandle() {
+    if (!mIsMediaFilter) {
+        return;
+    }
+    for (int i = 0; i < mFilterEvent.events.size(); i++) {
+        ::close(mFilterEvent.events[i].media().avMemory.getNativeHandle()->data[0]);
+        native_handle_close(mFilterEvent.events[i].media().avMemory.getNativeHandle());
+    }
+}
+
 void Filter::maySendFilterStatusCallback() {
+    if (!mIsUsingFMQ) {
+        return;
+    }
     std::lock_guard<std::mutex> lock(mFilterStatusLock);
     int availableToRead = mFilterMQ->availableToRead();
     int availableToWrite = mFilterMQ->availableToWrite();
@@ -265,13 +314,11 @@
 
 void Filter::updateFilterOutput(vector<uint8_t> data) {
     std::lock_guard<std::mutex> lock(mFilterOutputLock);
-    ALOGD("[Filter] filter output updated");
     mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
 }
 
 void Filter::updateRecordOutput(vector<uint8_t> data) {
     std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
-    ALOGD("[Filter] record filter output updated");
     mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end());
 }
 
@@ -409,29 +456,91 @@
 }
 
 Result Filter::startMediaFilterHandler() {
-    DemuxFilterMediaEvent mediaEvent;
-    mediaEvent = {
-            // temp dump meta data
-            .pts = 0,
-            .dataLength = 530,
-            .avMemory = nullptr,
-            .isSecureMemory = false,
-    };
-    mFilterEvent.events.resize(1);
-    mFilterEvent.events[0].media(mediaEvent);
+    std::lock_guard<std::mutex> lock(mFilterEventLock);
+    if (mFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
+    for (int i = 0; i < mFilterOutput.size(); i += 188) {
+        if (mPesSizeLeft == 0) {
+            uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
+                              mFilterOutput[i + 6];
+            if (DEBUG_FILTER) {
+                ALOGD("[Filter] prefix %d", prefix);
+            }
+            if (prefix == 0x000001) {
+                // TODO handle mulptiple Pes filters
+                mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
+                mPesSizeLeft += 6;
+                if (DEBUG_FILTER) {
+                    ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+                }
+            } else {
+                continue;
+            }
+        }
+
+        int endPoint = min(184, mPesSizeLeft);
+        // append data and check size
+        vector<uint8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
+        vector<uint8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
+        mPesOutput.insert(mPesOutput.end(), first, last);
+        // size does not match then continue
+        mPesSizeLeft -= endPoint;
+        if (DEBUG_FILTER) {
+            ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+        }
+        if (mPesSizeLeft > 0 || mAvBufferCopyCount++ < 10) {
+            continue;
+        }
+
+        int av_fd = createAvIonFd(mPesOutput.size());
+        if (av_fd == -1) {
+            return Result::UNKNOWN_ERROR;
+        }
+        // copy the filtered data to the buffer
+        uint8_t* avBuffer = getIonBuffer(av_fd, mPesOutput.size());
+        if (avBuffer == NULL) {
+            return Result::UNKNOWN_ERROR;
+        }
+        memcpy(avBuffer, mPesOutput.data(), mPesOutput.size() * sizeof(uint8_t));
+
+        native_handle_t* nativeHandle = createNativeHandle(av_fd);
+        if (nativeHandle == NULL) {
+            return Result::UNKNOWN_ERROR;
+        }
+        hidl_handle handle;
+        handle.setTo(nativeHandle, /*shouldOwn=*/true);
+
+        // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
+        uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
+        mDataId2Avfd[dataId] = dup(av_fd);
+
+        // Create mediaEvent and send callback
+        DemuxFilterMediaEvent mediaEvent;
+        mediaEvent = {
+                .avMemory = std::move(handle),
+                .dataLength = static_cast<uint32_t>(mPesOutput.size()),
+                .avDataId = dataId,
+        };
+        int size = mFilterEvent.events.size();
+        mFilterEvent.events.resize(size + 1);
+        mFilterEvent.events[size].media(mediaEvent);
+
+        // Clear and log
+        mPesOutput.clear();
+        mAvBufferCopyCount = 0;
+        ::close(av_fd);
+        if (DEBUG_FILTER) {
+            ALOGD("[Filter] assembled av data length %d", mediaEvent.dataLength);
+        }
+    }
 
     mFilterOutput.clear();
-    // TODO handle write FQM for media stream
+
     return Result::SUCCESS;
 }
 
 Result Filter::startRecordFilterHandler() {
-    /*DemuxFilterTsRecordEvent tsRecordEvent;
-    tsRecordEvent.pid.tPid(0);
-    tsRecordEvent.indexMask.tsIndexMask(0x01);
-    mFilterEvent.events.resize(1);
-    mFilterEvent.events[0].tsRecord(tsRecordEvent);
-*/
     std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
     if (mRecordFilterOutput.empty()) {
         return Result::SUCCESS;
@@ -458,7 +567,7 @@
 
 bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) {
     // TODO check how many sections has been read
-    ALOGD("[Filter] section hander");
+    ALOGD("[Filter] section handler");
     std::lock_guard<std::mutex> lock(mFilterEventLock);
     if (!writeDataToFilterMQ(data)) {
         return false;
@@ -493,6 +602,42 @@
     mDvr = nullptr;
 }
 
+int Filter::createAvIonFd(int size) {
+    // Create an ion fd and allocate an av fd mapped to a buffer to it.
+    int ion_fd = ion_open();
+    if (ion_fd == -1) {
+        ALOGE("[Filter] Failed to open ion fd %d", errno);
+        return -1;
+    }
+    int av_fd = -1;
+    ion_alloc_fd(dup(ion_fd), size, 0 /*align*/, ION_HEAP_SYSTEM_MASK, 0 /*flags*/, &av_fd);
+    if (av_fd == -1) {
+        ALOGE("[Filter] Failed to create av fd %d", errno);
+        return -1;
+    }
+    return av_fd;
+}
+
+uint8_t* Filter::getIonBuffer(int fd, int size) {
+    uint8_t* avBuf = static_cast<uint8_t*>(
+            mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 /*offset*/));
+    if (avBuf == MAP_FAILED) {
+        ALOGE("[Filter] fail to allocate buffer %d", errno);
+        return NULL;
+    }
+    return avBuf;
+}
+
+native_handle_t* Filter::createNativeHandle(int fd) {
+    // Create a native handle to pass the av fd via the callback event.
+    native_handle_t* nativeHandle = native_handle_create(/*numFd*/ 1, 0);
+    if (nativeHandle == NULL) {
+        ALOGE("[Filter] Failed to create native_handle %d", errno);
+        return NULL;
+    }
+    nativeHandle->data[0] = dup(fd);
+    return nativeHandle;
+}
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
index 0dc992a..9386dca 100644
--- a/tv/tuner/1.0/default/Filter.h
+++ b/tv/tuner/1.0/default/Filter.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/tv/tuner/1.0/IFilter.h>
 #include <fmq/MessageQueue.h>
+#include <ion/ion.h>
 #include <math.h>
 #include <set>
 #include "Demux.h"
@@ -87,6 +88,10 @@
     Result startRecordFilterHandler();
     void attachFilterToRecord(const sp<Dvr> dvr);
     void detachFilterFromRecord();
+    void freeAvHandle();
+    bool isMediaFilter() { return mIsMediaFilter; };
+    bool isPcrFilter() { return mIsPcrFilter; };
+    bool isRecordFilter() { return mIsRecordFilter; };
 
   private:
     // Tuner service
@@ -101,6 +106,9 @@
     uint32_t mFilterId;
     uint32_t mBufferSize;
     DemuxFilterType mType;
+    bool mIsMediaFilter = false;
+    bool mIsPcrFilter = false;
+    bool mIsRecordFilter = false;
     DemuxFilterSettings mFilterSettings;
 
     uint16_t mTpid;
@@ -109,6 +117,7 @@
     vector<uint8_t> mFilterOutput;
     vector<uint8_t> mRecordFilterOutput;
     unique_ptr<FilterMQ> mFilterMQ;
+    bool mIsUsingFMQ = false;
     EventFlag* mFilterEventFlag;
     DemuxFilterEvent mFilterEvent;
 
@@ -160,6 +169,10 @@
     static void* __threadLoopFilter(void* user);
     void filterThreadLoop();
 
+    int createAvIonFd(int size);
+    uint8_t* getIonBuffer(int fd, int size);
+    native_handle_t* createNativeHandle(int fd);
+
     /**
      * Lock to protect writes to the FMQs
      */
@@ -181,6 +194,11 @@
     // TODO handle mulptiple Pes filters
     int mPesSizeLeft = 0;
     vector<uint8_t> mPesOutput;
+
+    // A map from data id to ion handle
+    std::map<uint64_t, int> mDataId2Avfd;
+    uint64_t mLastUsedDataId = 1;
+    int mAvBufferCopyCount = 0;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 1e07edd..8bf0ec5 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -41,6 +41,7 @@
     ALOGV("%s", __FUNCTION__);
     // Reset callback
     mCallback = nullptr;
+    mIsLocked = false;
 
     return Result::SUCCESS;
 }
@@ -63,10 +64,9 @@
         return Result::INVALID_STATE;
     }
 
-    // TODO dynamically allocate file to the source file
-    mSourceStreamFile = FRONTEND_STREAM_FILE;
-
+    mTunerService->frontendStartTune(mId);
     mCallback->onEvent(FrontendEventType::LOCKED);
+    mIsLocked = true;
     return Result::SUCCESS;
 }
 
@@ -74,27 +74,173 @@
     ALOGV("%s", __FUNCTION__);
 
     mTunerService->frontendStopTune(mId);
+    mIsLocked = false;
 
     return Result::SUCCESS;
 }
 
-Return<Result> Frontend::scan(const FrontendSettings& /* settings */, FrontendScanType /* type */) {
+Return<Result> Frontend::scan(const FrontendSettings& settings, FrontendScanType type) {
     ALOGV("%s", __FUNCTION__);
 
+    if (mType == FrontendType::ATSC) {
+        FrontendScanMessage msg;
+        msg.isLocked(true);
+        mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
+        mIsLocked = true;
+        return Result::SUCCESS;
+    }
+    if (mType != FrontendType::DVBT) {
+        return Result::UNAVAILABLE;
+    }
+
+    FrontendScanMessage msg;
+
+    if (mIsLocked) {
+        msg.isEnd(true);
+        mCallback->onScanMessage(FrontendScanMessageType::END, msg);
+        return Result::SUCCESS;
+    }
+
+    uint32_t frequency = settings.dvbt().frequency;
+    if (type == FrontendScanType::SCAN_BLIND) {
+        frequency += 100;
+    }
+    msg.frequencies({frequency});
+    mCallback->onScanMessage(FrontendScanMessageType::FREQUENCY, msg);
+    msg.isLocked(true);
+    mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
+    mIsLocked = true;
+
     return Result::SUCCESS;
 }
 
 Return<Result> Frontend::stopScan() {
     ALOGV("%s", __FUNCTION__);
 
+    mIsLocked = false;
     return Result::SUCCESS;
 }
 
-Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& /* statusTypes */,
+Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
                                  getStatus_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
     vector<FrontendStatus> statuses;
+    for (int i = 0; i < statusTypes.size(); i++) {
+        FrontendStatusType type = statusTypes[i];
+        FrontendStatus status;
+        // assign randomly selected values for testing.
+        switch (type) {
+            case FrontendStatusType::DEMOD_LOCK: {
+                status.isDemodLocked(true);
+                break;
+            }
+            case FrontendStatusType::SNR: {
+                status.snr(221);
+                break;
+            }
+            case FrontendStatusType::BER: {
+                status.ber(1);
+                break;
+            }
+            case FrontendStatusType::PER: {
+                status.per(2);
+                break;
+            }
+            case FrontendStatusType::PRE_BER: {
+                status.preBer(3);
+                break;
+            }
+            case FrontendStatusType::SIGNAL_QUALITY: {
+                status.signalQuality(4);
+                break;
+            }
+            case FrontendStatusType::SIGNAL_STRENGTH: {
+                status.signalStrength(5);
+                break;
+            }
+            case FrontendStatusType::SYMBOL_RATE: {
+                status.symbolRate(6);
+                break;
+            }
+            case FrontendStatusType::FEC: {
+                status.innerFec(FrontendInnerFec::FEC_2_9);  // value = 1 << 7
+                break;
+            }
+            case FrontendStatusType::MODULATION: {
+                FrontendModulationStatus modulationStatus;
+                modulationStatus.isdbt(FrontendIsdbtModulation::MOD_16QAM);  // value = 1 << 3
+                status.modulation(modulationStatus);
+                break;
+            }
+            case FrontendStatusType::SPECTRAL: {
+                status.inversion(FrontendDvbcSpectralInversion::NORMAL);
+                break;
+            }
+            case FrontendStatusType::LNB_VOLTAGE: {
+                status.lnbVoltage(LnbVoltage::VOLTAGE_5V);
+                break;
+            }
+            case FrontendStatusType::PLP_ID: {
+                status.plpId(101);  // type uint8_t
+                break;
+            }
+            case FrontendStatusType::EWBS: {
+                status.isEWBS(false);
+                break;
+            }
+            case FrontendStatusType::AGC: {
+                status.agc(7);
+                break;
+            }
+            case FrontendStatusType::LNA: {
+                status.isLnaOn(false);
+                break;
+            }
+            case FrontendStatusType::LAYER_ERROR: {
+                vector<bool> v = {false, true, true};
+                status.isLayerError(v);
+                break;
+            }
+            case FrontendStatusType::MER: {
+                status.mer(8);
+                break;
+            }
+            case FrontendStatusType::FREQ_OFFSET: {
+                status.freqOffset(9);
+                break;
+            }
+            case FrontendStatusType::HIERARCHY: {
+                status.hierarchy(FrontendDvbtHierarchy::HIERARCHY_1_NATIVE);
+                break;
+            }
+            case FrontendStatusType::RF_LOCK: {
+                status.isRfLocked(false);
+                break;
+            }
+            case FrontendStatusType::ATSC3_PLP_INFO: {
+                vector<FrontendStatusAtsc3PlpInfo> v;
+                FrontendStatusAtsc3PlpInfo info1{
+                        .plpId = 3,
+                        .isLocked = false,
+                        .uec = 313,
+                };
+                FrontendStatusAtsc3PlpInfo info2{
+                        .plpId = 5,
+                        .isLocked = true,
+                        .uec = 515,
+                };
+                v.push_back(info1);
+                v.push_back(info2);
+                status.plpInfo(v);
+                break;
+            }
+            default: {
+                continue;
+            }
+        }
+        statuses.push_back(status);
+    }
     _hidl_cb(Result::SUCCESS, statuses);
 
     return Void();
@@ -108,7 +254,9 @@
 
 Return<Result> Frontend::setLnb(uint32_t /* lnb */) {
     ALOGV("%s", __FUNCTION__);
-
+    if (!supportsSatellite()) {
+        return Result::INVALID_STATE;
+    }
     return Result::SUCCESS;
 }
 
@@ -120,10 +268,14 @@
     return mId;
 }
 
-string Frontend::getSourceFile() {
-    return mSourceStreamFile;
+bool Frontend::supportsSatellite() {
+    return mType == FrontendType::DVBS || mType == FrontendType::ISDBS ||
+           mType == FrontendType::ISDBS3;
 }
 
+bool Frontend::isLocked() {
+    return mIsLocked;
+}
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h
index eab43a3..a529b74 100644
--- a/tv/tuner/1.0/default/Frontend.h
+++ b/tv/tuner/1.0/default/Frontend.h
@@ -68,15 +68,17 @@
 
     string getSourceFile();
 
+    bool isLocked();
+
   private:
     virtual ~Frontend();
+    bool supportsSatellite();
     sp<IFrontendCallback> mCallback;
     sp<Tuner> mTunerService;
     FrontendType mType = FrontendType::UNDEFINED;
     FrontendId mId = 0;
+    bool mIsLocked = false;
 
-    const string FRONTEND_STREAM_FILE = "/vendor/etc/dumpTs3.ts";
-    string mSourceStreamFile;
     std::ifstream mFrontendData;
 };
 
diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp
index 51931d6..6025339 100644
--- a/tv/tuner/1.0/default/Lnb.cpp
+++ b/tv/tuner/1.0/default/Lnb.cpp
@@ -27,6 +27,9 @@
 namespace implementation {
 
 Lnb::Lnb() {}
+Lnb::Lnb(int id) {
+    mId = id;
+}
 
 Lnb::~Lnb() {}
 
@@ -66,9 +69,13 @@
     return Result::SUCCESS;
 }
 
+int Lnb::getId() {
+    return mId;
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
 }  // namespace tv
 }  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h
index f285cb9..1e97214 100644
--- a/tv/tuner/1.0/default/Lnb.h
+++ b/tv/tuner/1.0/default/Lnb.h
@@ -38,6 +38,7 @@
 class Lnb : public ILnb {
   public:
     Lnb();
+    Lnb(int id);
 
     virtual Return<Result> setCallback(const sp<ILnbCallback>& callback) override;
 
@@ -51,7 +52,10 @@
 
     virtual Return<Result> close() override;
 
+    int getId();
+
   private:
+    int mId;
     virtual ~Lnb();
 };
 
@@ -62,4 +66,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_
\ No newline at end of file
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_
diff --git a/tv/tuner/1.0/default/TimeFilter.cpp b/tv/tuner/1.0/default/TimeFilter.cpp
index 0b1fd1c..cec824f 100644
--- a/tv/tuner/1.0/default/TimeFilter.cpp
+++ b/tv/tuner/1.0/default/TimeFilter.cpp
@@ -34,24 +34,32 @@
 
 TimeFilter::~TimeFilter() {}
 
-Return<Result> TimeFilter::setTimeStamp(uint64_t /* timeStamp */) {
+Return<Result> TimeFilter::setTimeStamp(uint64_t timeStamp) {
     ALOGV("%s", __FUNCTION__);
+    if (timeStamp == INVALID_TIME_STAMP) {
+        return Result::INVALID_ARGUMENT;
+    }
+    mTimeStamp = timeStamp;
+    mBeginTime = time(NULL);
 
     return Result::SUCCESS;
 }
 
 Return<Result> TimeFilter::clearTimeStamp() {
     ALOGV("%s", __FUNCTION__);
+    mTimeStamp = INVALID_TIME_STAMP;
 
     return Result::SUCCESS;
 }
 
 Return<void> TimeFilter::getTimeStamp(getTimeStamp_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
+    if (mTimeStamp == INVALID_TIME_STAMP) {
+        _hidl_cb(Result::INVALID_STATE, mTimeStamp);
+    }
 
-    uint64_t timeStamp = 0;
-
-    _hidl_cb(Result::SUCCESS, timeStamp);
+    uint64_t currentTimeStamp = mTimeStamp + difftime(time(NULL), mBeginTime) * 900000;
+    _hidl_cb(Result::SUCCESS, currentTimeStamp);
     return Void();
 }
 
@@ -66,6 +74,7 @@
 
 Return<Result> TimeFilter::close() {
     ALOGV("%s", __FUNCTION__);
+    mTimeStamp = INVALID_TIME_STAMP;
 
     return Result::SUCCESS;
 }
diff --git a/tv/tuner/1.0/default/TimeFilter.h b/tv/tuner/1.0/default/TimeFilter.h
index 7131df8..cb3f29d 100644
--- a/tv/tuner/1.0/default/TimeFilter.h
+++ b/tv/tuner/1.0/default/TimeFilter.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/tv/tuner/1.0/ITimeFilter.h>
 #include "Demux.h"
+#include "time.h"
 
 using namespace std;
 
@@ -35,6 +36,8 @@
 
 using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
 
+#define INVALID_TIME_STAMP -1
+
 class Demux;
 
 class TimeFilter : public ITimeFilter {
@@ -57,6 +60,8 @@
 
   private:
     sp<Demux> mDemux;
+    uint64_t mTimeStamp = INVALID_TIME_STAMP;
+    time_t mBeginTime;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index c6017f0..48ce384 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -46,6 +46,52 @@
     mFrontends[5] = new Frontend(FrontendType::ISDBT, 5, this);
     mFrontends[6] = new Frontend(FrontendType::ANALOG, 6, this);
     mFrontends[7] = new Frontend(FrontendType::ATSC, 7, this);
+
+    FrontendInfo::FrontendCapabilities caps;
+    mFrontendCaps.resize(mFrontendSize);
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.dvbtCaps(FrontendDvbtCapabilities());
+    mFrontendCaps[0] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.atscCaps(FrontendAtscCapabilities());
+    mFrontendCaps[1] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.dvbcCaps(FrontendDvbcCapabilities());
+    mFrontendCaps[2] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.dvbsCaps(FrontendDvbsCapabilities());
+    mFrontendCaps[3] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.dvbtCaps(FrontendDvbtCapabilities());
+    mFrontendCaps[4] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    FrontendIsdbtCapabilities isdbtCaps{
+            .modeCap = FrontendIsdbtMode::MODE_1 | FrontendIsdbtMode::MODE_2,
+            .bandwidthCap = (unsigned int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ,
+            .modulationCap = (unsigned int)FrontendIsdbtModulation::MOD_16QAM,
+            // ISDBT shares coderate and guard interval with DVBT
+            .coderateCap = FrontendDvbtCoderate::CODERATE_4_5 | FrontendDvbtCoderate::CODERATE_6_7,
+            .guardIntervalCap = (unsigned int)FrontendDvbtGuardInterval::INTERVAL_1_128,
+    };
+    caps.isdbtCaps(isdbtCaps);
+    mFrontendCaps[5] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.analogCaps(FrontendAnalogCapabilities());
+    mFrontendCaps[6] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.atscCaps(FrontendAtscCapabilities());
+    mFrontendCaps[7] = caps;
+
+    mLnbs.resize(2);
+    mLnbs[0] = new Lnb(0);
+    mLnbs[1] = new Lnb(1);
 }
 
 Tuner::~Tuner() {}
@@ -93,6 +139,8 @@
 
     DemuxCapabilities caps;
 
+    // IP filter can be an MMTP filter's data source.
+    caps.linkCaps = {0x00, 0x00, 0x02, 0x00, 0x00};
     _hidl_cb(Result::SUCCESS, caps);
     return Void();
 }
@@ -106,10 +154,36 @@
     return Void();
 }
 
-Return<void> Tuner::getFrontendInfo(FrontendId /* frontendId */, getFrontendInfo_cb _hidl_cb) {
+Return<void> Tuner::getFrontendInfo(FrontendId frontendId, getFrontendInfo_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
     FrontendInfo info;
+    if (frontendId >= mFrontendSize) {
+        _hidl_cb(Result::INVALID_ARGUMENT, info);
+        return Void();
+    }
+
+    vector<FrontendStatusType> statusCaps = {
+            FrontendStatusType::DEMOD_LOCK,
+            FrontendStatusType::SNR,
+            FrontendStatusType::FEC,
+            FrontendStatusType::MODULATION,
+            FrontendStatusType::PLP_ID,
+            FrontendStatusType::LAYER_ERROR,
+            FrontendStatusType::ATSC3_PLP_INFO,
+    };
+    // assign randomly selected values for testing.
+    info = {
+            .type = mFrontends[frontendId]->getFrontendType(),
+            .minFrequency = 139,
+            .maxFrequency = 1139,
+            .minSymbolRate = 45,
+            .maxSymbolRate = 1145,
+            .acquireRange = 30,
+            .exclusiveGroupId = 57,
+            .statusCaps = statusCaps,
+            .frontendCaps = mFrontendCaps[frontendId],
+    };
 
     _hidl_cb(Result::SUCCESS, info);
     return Void();
@@ -119,17 +193,24 @@
     ALOGV("%s", __FUNCTION__);
 
     vector<LnbId> lnbIds;
+    lnbIds.resize(mLnbs.size());
+    for (int i = 0; i < lnbIds.size(); i++) {
+        lnbIds[i] = mLnbs[i]->getId();
+    }
 
     _hidl_cb(Result::SUCCESS, lnbIds);
     return Void();
 }
 
-Return<void> Tuner::openLnbById(LnbId /* lnbId */, openLnbById_cb _hidl_cb) {
+Return<void> Tuner::openLnbById(LnbId lnbId, openLnbById_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    sp<ILnb> lnb = new Lnb();
+    if (lnbId >= mLnbs.size()) {
+        _hidl_cb(Result::INVALID_ARGUMENT, nullptr);
+        return Void();
+    }
 
-    _hidl_cb(Result::SUCCESS, lnb);
+    _hidl_cb(Result::SUCCESS, mLnbs[lnbId]);
     return Void();
 }
 
@@ -150,6 +231,9 @@
 
 void Tuner::setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId) {
     mFrontendToDemux[frontendId] = demuxId;
+    if (mFrontends[frontendId] != nullptr && mFrontends[frontendId]->isLocked()) {
+        mDemuxes[demuxId]->startFrontendInputLoop();
+    }
 }
 
 void Tuner::frontendStopTune(uint32_t frontendId) {
@@ -161,6 +245,15 @@
     }
 }
 
+void Tuner::frontendStartTune(uint32_t frontendId) {
+    map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
+    uint32_t demuxId;
+    if (it != mFrontendToDemux.end()) {
+        demuxId = it->second;
+        mDemuxes[demuxId]->startFrontendInputLoop();
+    }
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
index 7a8a919..5de568f 100644
--- a/tv/tuner/1.0/default/Tuner.h
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -21,6 +21,7 @@
 #include <map>
 #include "Demux.h"
 #include "Frontend.h"
+#include "Lnb.h"
 
 using namespace std;
 
@@ -62,12 +63,14 @@
 
     void setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId);
 
+    void frontendStartTune(uint32_t frontendId);
     void frontendStopTune(uint32_t frontendId);
 
   private:
     virtual ~Tuner();
     // Static mFrontends array to maintain local frontends information
     vector<sp<Frontend>> mFrontends;
+    vector<FrontendInfo::FrontendCapabilities> mFrontendCaps;
     std::map<uint32_t, uint32_t> mFrontendToDemux;
     std::map<uint32_t, sp<Demux>> mDemuxes;
     // To maintain how many Frontends we have
@@ -75,6 +78,7 @@
     // The last used demux id. Initial value is -1.
     // First used id will be 0.
     int mLastUsedId = -1;
+    vector<sp<Lnb>> mLnbs;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/service.cpp b/tv/tuner/1.0/default/service.cpp
index 0858d8f..7bbc09e 100644
--- a/tv/tuner/1.0/default/service.cpp
+++ b/tv/tuner/1.0/default/service.cpp
@@ -45,8 +45,8 @@
     android::sp<ITuner> service = new Tuner();
     android::status_t status;
     if (kLazyService) {
-        auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
-        status = serviceRegistrar->registerService(service);
+        auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(service);
     } else {
         status = service->registerAsService();
     }
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 71db109..dd2b48f 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -63,7 +63,7 @@
     DVBS,
     /**
      * Digital Video Broadcasting - Terrestrial
-     * DVB Terresttrial Frontend Standard ETSI EN 300 468 V1.15.1 and
+     * DVB Terrestrial Frontend Standard ETSI EN 300 468 V1.15.1 and
      * ETSI EN 302 755 V1.4.1.
      */
     DVBT,
@@ -255,7 +255,7 @@
 };
 
 /**
- *  Signal Setting for ATSC Frontend.
+ *  Signal Settings for an ATSC Frontend.
  */
 struct FrontendAtscSettings {
     /**
@@ -881,7 +881,7 @@
 };
 
 /**
- *  Modulaltion Type for ISDBS.
+ *  Modulation Type for ISDBS.
  */
 @export
 enum FrontendIsdbsModulation : uint32_t {
@@ -1337,18 +1337,15 @@
 @export
 enum FrontendEventType : uint32_t {
     /**
-     * If frontend locked the signal which is specified by tune method, HAL sends
-     * Locked event.
+     * The frontend has locked to the signal specified by the tune method.
      */
     LOCKED,
     /**
-     * If frontend can't locked the signal which is specified by tune method,
-     * HAL sends NO_SIGNAL event.
+     * The frontend is unable to lock to the signal specified by the tune method.
      */
     NO_SIGNAL,
     /**
-     * If frontend detect that the locked signal get lost, HAL sends LOST_LOCK
-     * event.
+     * The frontend has lost the lock to the signal specified by the tune method.
      */
     LOST_LOCK,
 };
diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp
index 641e16a..1765915 100644
--- a/tv/tuner/1.0/vts/functional/Android.bp
+++ b/tv/tuner/1.0/vts/functional/Android.bp
@@ -17,8 +17,19 @@
 cc_test {
     name: "VtsHalTvTunerV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
-    srcs: ["VtsHalTvTunerV1_0TargetTest.cpp"],
+    srcs: [
+        "VtsHalTvTunerV1_0TargetTest.cpp",
+        "FrontendTests.cpp",
+        "DemuxTests.cpp",
+        "FilterTests.cpp",
+        "DvrTests.cpp",
+        "DescramblerTests.cpp",
+        "LnbTests.cpp",
+    ],
     static_libs: [
+        "android.hardware.cas@1.0",
+        "android.hardware.cas@1.1",
+        "android.hardware.cas@1.2",
         "android.hardware.tv.tuner@1.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
diff --git a/tv/tuner/1.0/vts/functional/DemuxTests.cpp b/tv/tuner/1.0/vts/functional/DemuxTests.cpp
new file mode 100644
index 0000000..37a47d7
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/DemuxTests.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "DemuxTests.h"
+
+AssertionResult DemuxTests::openDemux(sp<IDemux>& demux, uint32_t& demuxId) {
+    Result status;
+    mService->openDemux([&](Result result, uint32_t id, const sp<IDemux>& demuxSp) {
+        mDemux = demuxSp;
+        demux = demuxSp;
+        demuxId = id;
+        status = result;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DemuxTests::setDemuxFrontendDataSource(uint32_t frontendId) {
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    auto status = mDemux->setFrontendDataSource(frontendId);
+    return AssertionResult(status.isOk());
+}
+
+AssertionResult DemuxTests::getDemuxCaps(DemuxCapabilities& demuxCaps) {
+    if (!mDemux) {
+        ALOGW("[vts] Test with openDemux first.");
+        return failure();
+    }
+    Result status;
+    mService->getDemuxCaps([&](Result result, DemuxCapabilities caps) {
+        status = result;
+        demuxCaps = caps;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DemuxTests::closeDemux() {
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    auto status = mDemux->close();
+    mDemux = nullptr;
+    return AssertionResult(status.isOk());
+}
+
+AssertionResult DemuxTests::getAvSyncId(sp<IFilter> filter, uint32_t& avSyncHwId) {
+    EXPECT_TRUE(mDemux) << "Demux is not opened yet.";
+    Result status;
+    mDemux->getAvSyncHwId(filter, [&](Result result, uint32_t id) {
+        status = result;
+        avSyncHwId = id;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DemuxTests::getAvSyncTime(uint32_t avSyncId) {
+    EXPECT_TRUE(mDemux) << "Demux is not opened yet.";
+    Result status;
+    uint64_t syncTime;
+    mDemux->getAvSyncTime(avSyncId, [&](Result result, uint64_t time) {
+        status = result;
+        syncTime = time;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
\ No newline at end of file
diff --git a/tv/tuner/1.0/vts/functional/DemuxTests.h b/tv/tuner/1.0/vts/functional/DemuxTests.h
new file mode 100644
index 0000000..b249ea8
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/DemuxTests.h
@@ -0,0 +1,59 @@
+/*
+ * 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 <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IDemux.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <map>
+
+using android::sp;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::DemuxCapabilities;
+using android::hardware::tv::tuner::V1_0::IDemux;
+using android::hardware::tv::tuner::V1_0::IFilter;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::Result;
+
+using ::testing::AssertionResult;
+
+class DemuxTests {
+  public:
+    void setService(sp<ITuner> tuner) { mService = tuner; }
+
+    AssertionResult openDemux(sp<IDemux>& demux, uint32_t& demuxId);
+    AssertionResult setDemuxFrontendDataSource(uint32_t frontendId);
+    AssertionResult getAvSyncId(sp<IFilter> filter, uint32_t& avSyncHwId);
+    AssertionResult getAvSyncTime(uint32_t avSyncId);
+    AssertionResult getDemuxCaps(DemuxCapabilities& demuxCaps);
+    AssertionResult closeDemux();
+
+  protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+    sp<ITuner> mService;
+    sp<IDemux> mDemux;
+};
diff --git a/tv/tuner/1.0/vts/functional/DescramblerTests.cpp b/tv/tuner/1.0/vts/functional/DescramblerTests.cpp
new file mode 100644
index 0000000..2e27475
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/DescramblerTests.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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 "DescramblerTests.h"
+
+AssertionResult DescramblerTests::createCasPlugin(int32_t caSystemId) {
+    auto status = mMediaCasService->isSystemIdSupported(caSystemId);
+    if (!status.isOk() || !status) {
+        ALOGW("[vts] Failed to check isSystemIdSupported.");
+        return failure();
+    }
+
+    mCasListener = new MediaCasListener();
+    auto pluginStatus = mMediaCasService->createPluginExt(caSystemId, mCasListener);
+    if (!pluginStatus.isOk()) {
+        ALOGW("[vts] Failed to createPluginExt.");
+        return failure();
+    }
+    mCas = ICas::castFrom(pluginStatus);
+    if (mCas == nullptr) {
+        ALOGW("[vts] Failed to get ICas.");
+        return failure();
+    }
+    return success();
+}
+
+AssertionResult DescramblerTests::openCasSession(TunerKeyToken& sessionId,
+                                                 vector<uint8_t> hidlPvtData) {
+    Status sessionStatus;
+    SessionIntent intent = SessionIntent::LIVE;
+    ScramblingMode mode = ScramblingMode::RESERVED;
+    auto returnVoid =
+            mCas->openSession_1_2(intent, mode, [&](Status status, const hidl_vec<uint8_t>& id) {
+                sessionStatus = status;
+                sessionId = id;
+            });
+    if (!returnVoid.isOk() || (sessionStatus != Status::OK)) {
+        ALOGW("[vts] Failed to open cas session.");
+        mCas->closeSession(sessionId);
+        return failure();
+    }
+
+    auto status = mCas->setSessionPrivateData(sessionId, hidlPvtData);
+    if (status != android::hardware::cas::V1_0::Status::OK) {
+        ALOGW("[vts] Failed to set session private data");
+        mCas->closeSession(sessionId);
+        return failure();
+    }
+    return success();
+}
+
+AssertionResult DescramblerTests::getKeyToken(int32_t caSystemId, string provisonStr,
+                                              hidl_vec<uint8_t> hidlPvtData, TunerKeyToken& token) {
+    if (createCasPlugin(caSystemId) != success()) {
+        ALOGW("[vts] createCasPlugin failed.");
+        return failure();
+    }
+
+    if (provisonStr.size() > 0) {
+        auto returnStatus = mCas->provision(hidl_string(provisonStr));
+        if (returnStatus != android::hardware::cas::V1_0::Status::OK) {
+            ALOGW("[vts] provision failed.");
+            return failure();
+        }
+    }
+
+    return openCasSession(token, hidlPvtData);
+}
+
+AssertionResult DescramblerTests::openDescrambler(uint32_t demuxId) {
+    Result status;
+    mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
+        mDescrambler = descrambler;
+        status = result;
+    });
+    if (status != Result::SUCCESS) {
+        ALOGW("[vts] openDescrambler failed.");
+        return failure();
+    }
+
+    status = mDescrambler->setDemuxSource(demuxId);
+    if (status != Result::SUCCESS) {
+        ALOGW("[vts] setDemuxSource failed.");
+        return failure();
+    }
+
+    return success();
+}
+
+AssertionResult DescramblerTests::setKeyToken(TunerKeyToken token) {
+    Result status;
+    if (!mDescrambler) {
+        ALOGW("[vts] Descrambler is not opened yet.");
+        return failure();
+    }
+
+    status = mDescrambler->setKeyToken(token);
+    if (status != Result::SUCCESS) {
+        ALOGW("[vts] setKeyToken failed.");
+        return failure();
+    }
+
+    return success();
+}
+
+AssertionResult DescramblerTests::addPid(DemuxPid pid, sp<IFilter> optionalSourceFilter) {
+    Result status;
+    if (!mDescrambler) {
+        ALOGW("[vts] Descrambler is not opened yet.");
+        return failure();
+    }
+
+    status = mDescrambler->addPid(pid, optionalSourceFilter);
+    if (status != Result::SUCCESS) {
+        ALOGW("[vts] addPid failed.");
+        return failure();
+    }
+
+    return success();
+}
+
+AssertionResult DescramblerTests::removePid(DemuxPid pid, sp<IFilter> optionalSourceFilter) {
+    Result status;
+    if (!mDescrambler) {
+        ALOGW("[vts] Descrambler is not opened yet.");
+        return failure();
+    }
+
+    status = mDescrambler->removePid(pid, optionalSourceFilter);
+    if (status != Result::SUCCESS) {
+        ALOGW("[vts] removePid failed.");
+        return failure();
+    }
+
+    return success();
+}
+
+AssertionResult DescramblerTests::closeDescrambler() {
+    Result status;
+    if (!mDescrambler) {
+        ALOGW("[vts] Descrambler is not opened yet.");
+        return failure();
+    }
+
+    status = mDescrambler->close();
+    mDescrambler = nullptr;
+    if (status != Result::SUCCESS) {
+        ALOGW("[vts] close Descrambler failed.");
+        return failure();
+    }
+
+    return success();
+}
+
+AssertionResult DescramblerTests::getDemuxPidFromFilterSettings(DemuxFilterType type,
+                                                                DemuxFilterSettings settings,
+                                                                DemuxPid& pid) {
+    switch (type.mainType) {
+        case DemuxFilterMainType::TS:
+            if (type.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
+                type.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
+                pid.tPid(settings.ts().tpid);
+            } else {
+                ALOGW("[vts] Not a media ts filter!");
+                return failure();
+            }
+            break;
+        case DemuxFilterMainType::MMTP:
+            if (type.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
+                type.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
+                pid.mmtpPid(settings.mmtp().mmtpPid);
+            } else {
+                ALOGW("[vts] Not a media mmtp filter!");
+                return failure();
+            }
+            break;
+        default:
+            ALOGW("[vts] Not a media filter!");
+            return failure();
+    }
+    return success();
+}
diff --git a/tv/tuner/1.0/vts/functional/DescramblerTests.h b/tv/tuner/1.0/vts/functional/DescramblerTests.h
new file mode 100644
index 0000000..16d480d
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/DescramblerTests.h
@@ -0,0 +1,121 @@
+/*
+ * 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 <android-base/logging.h>
+#include <android/hardware/cas/1.0/types.h>
+#include <android/hardware/cas/1.2/ICas.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <android/hardware/cas/1.2/IMediaCasService.h>
+#include <android/hardware/cas/1.2/types.h>
+#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/Status.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <fstream>
+#include <iostream>
+#include <map>
+
+using android::Condition;
+using android::Mutex;
+using android::sp;
+using android::hardware::EventFlag;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MessageQueue;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::cas::V1_2::ICas;
+using android::hardware::cas::V1_2::ICasListener;
+using android::hardware::cas::V1_2::IMediaCasService;
+using android::hardware::cas::V1_2::ScramblingMode;
+using android::hardware::cas::V1_2::SessionIntent;
+using android::hardware::cas::V1_2::Status;
+using android::hardware::cas::V1_2::StatusEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxPid;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::IDescrambler;
+using android::hardware::tv::tuner::V1_0::IFilter;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::Result;
+using android::hardware::tv::tuner::V1_0::TunerKeyToken;
+
+using ::testing::AssertionResult;
+
+using namespace std;
+
+class MediaCasListener : public ICasListener {
+  public:
+    virtual Return<void> onEvent(int32_t /*event*/, int32_t /*arg*/,
+                                 const hidl_vec<uint8_t>& /*data*/) override {
+        return Void();
+    }
+
+    virtual Return<void> onSessionEvent(const hidl_vec<uint8_t>& /*sessionId*/, int32_t /*event*/,
+                                        int32_t /*arg*/,
+                                        const hidl_vec<uint8_t>& /*data*/) override {
+        return Void();
+    }
+
+    virtual Return<void> onStatusUpdate(StatusEvent /*event*/, int32_t /*arg*/) override {
+        return Void();
+    }
+};
+
+class DescramblerTests {
+  public:
+    void setService(sp<ITuner> tuner) { mService = tuner; }
+    void setCasService(sp<IMediaCasService> casService) { mMediaCasService = casService; }
+
+    AssertionResult setKeyToken(TunerKeyToken token);
+    AssertionResult openDescrambler(uint32_t demuxId);
+    AssertionResult addPid(DemuxPid pid, sp<IFilter> optionalSourceFilter);
+    AssertionResult removePid(DemuxPid pid, sp<IFilter> optionalSourceFilter);
+    AssertionResult closeDescrambler();
+    AssertionResult getKeyToken(int32_t caSystemId, string provisonStr,
+                                hidl_vec<uint8_t> hidlPvtData, TunerKeyToken& token);
+    AssertionResult getDemuxPidFromFilterSettings(DemuxFilterType type,
+                                                  DemuxFilterSettings settings, DemuxPid& pid);
+
+  protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+    sp<ITuner> mService;
+    sp<ICas> mCas;
+    sp<IMediaCasService> mMediaCasService;
+    sp<MediaCasListener> mCasListener;
+    sp<IDescrambler> mDescrambler;
+
+  private:
+    AssertionResult openCasSession(TunerKeyToken& sessionId, vector<uint8_t> hidlPvtData);
+    AssertionResult createCasPlugin(int32_t caSystemId);
+};
diff --git a/tv/tuner/1.0/vts/functional/DvrTests.cpp b/tv/tuner/1.0/vts/functional/DvrTests.cpp
new file mode 100644
index 0000000..0dfc032
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/DvrTests.cpp
@@ -0,0 +1,348 @@
+/*
+ * 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 "DvrTests.h"
+
+void DvrCallback::startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings,
+                                           MQDesc& playbackMQDescriptor) {
+    mInputDataFile = dataInputFile;
+    mPlaybackSettings = settings;
+    mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mPlaybackMQ);
+    pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, this);
+    pthread_setname_np(mPlaybackThread, "test_playback_input_loop");
+}
+
+void DvrCallback::stopPlaybackThread() {
+    mPlaybackThreadRunning = false;
+    mKeepWritingPlaybackFMQ = false;
+
+    android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+}
+
+void* DvrCallback::__threadLoopPlayback(void* user) {
+    DvrCallback* const self = static_cast<DvrCallback*>(user);
+    self->playbackThreadLoop();
+    return 0;
+}
+
+void DvrCallback::playbackThreadLoop() {
+    android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+    mPlaybackThreadRunning = true;
+
+    // Create the EventFlag that is used to signal the HAL impl that data have been
+    // written into the Playback FMQ
+    EventFlag* playbackMQEventFlag;
+    EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) ==
+                android::OK);
+
+    int fd = open(mInputDataFile.c_str(), O_RDONLY | O_LARGEFILE);
+    int readBytes;
+    uint32_t regionSize = 0;
+    uint8_t* buffer;
+    ALOGW("[vts] playback thread loop start %s", mInputDataFile.c_str());
+    if (fd < 0) {
+        mPlaybackThreadRunning = false;
+        ALOGW("[vts] Error %s", strerror(errno));
+    }
+
+    while (mPlaybackThreadRunning) {
+        while (mKeepWritingPlaybackFMQ) {
+            int totalWrite = mPlaybackMQ->availableToWrite();
+            if (totalWrite * 4 < mPlaybackMQ->getQuantumCount()) {
+                // Wait for the HAL implementation to read more data then write.
+                continue;
+            }
+            MessageQueue<uint8_t, kSynchronizedReadWrite>::MemTransaction memTx;
+            if (!mPlaybackMQ->beginWrite(totalWrite, &memTx)) {
+                ALOGW("[vts] Fail to write into Playback fmq.");
+                mPlaybackThreadRunning = false;
+                break;
+            }
+            auto first = memTx.getFirstRegion();
+            buffer = first.getAddress();
+            regionSize = first.getLength();
+
+            if (regionSize > 0) {
+                readBytes = read(fd, buffer, regionSize);
+                if (readBytes <= 0) {
+                    if (readBytes < 0) {
+                        ALOGW("[vts] Read from %s failed.", mInputDataFile.c_str());
+                    } else {
+                        ALOGW("[vts] playback input EOF.");
+                    }
+                    mPlaybackThreadRunning = false;
+                    break;
+                }
+            }
+            if (regionSize == 0 || (readBytes == regionSize && regionSize < totalWrite)) {
+                auto second = memTx.getSecondRegion();
+                buffer = second.getAddress();
+                regionSize = second.getLength();
+                int ret = read(fd, buffer, regionSize);
+                if (ret <= 0) {
+                    if (ret < 0) {
+                        ALOGW("[vts] Read from %s failed.", mInputDataFile.c_str());
+                    } else {
+                        ALOGW("[vts] playback input EOF.");
+                    }
+                    mPlaybackThreadRunning = false;
+                    break;
+                }
+                readBytes += ret;
+            }
+            if (!mPlaybackMQ->commitWrite(readBytes)) {
+                ALOGW("[vts] Failed to commit write playback fmq.");
+                mPlaybackThreadRunning = false;
+                break;
+            }
+            playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+        }
+    }
+
+    mPlaybackThreadRunning = false;
+    ALOGW("[vts] Playback thread end.");
+    close(fd);
+}
+
+void DvrCallback::testRecordOutput() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (mDataOutputBuffer.empty()) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
+            stopRecordThread();
+            return;
+        }
+    }
+    stopRecordThread();
+    ALOGW("[vts] record pass and stop");
+}
+
+void DvrCallback::startRecordOutputThread(RecordSettings recordSettings,
+                                          MQDesc& recordMQDescriptor) {
+    mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mRecordMQ);
+    struct RecordThreadArgs* threadArgs =
+            (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs));
+    threadArgs->user = this;
+    threadArgs->recordSettings = &recordSettings;
+    threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ;
+
+    pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs);
+    pthread_setname_np(mRecordThread, "test_record_input_loop");
+}
+
+void* DvrCallback::__threadLoopRecord(void* threadArgs) {
+    DvrCallback* const self =
+            static_cast<DvrCallback*>(((struct RecordThreadArgs*)threadArgs)->user);
+    self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSettings,
+                           ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ);
+    return 0;
+}
+
+void DvrCallback::recordThreadLoop(RecordSettings* /*recordSettings*/, bool* keepReadingRecordFMQ) {
+    ALOGD("[vts] DvrCallback record threadLoop start.");
+    android::Mutex::Autolock autoLock(mRecordThreadLock);
+    mRecordThreadRunning = true;
+    mKeepReadingRecordFMQ = true;
+
+    // Create the EventFlag that is used to signal the HAL impl that data have been
+    // read from the Record FMQ
+    EventFlag* recordMQEventFlag;
+    EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
+                android::OK);
+
+    while (mRecordThreadRunning) {
+        while (*keepReadingRecordFMQ) {
+            uint32_t efState = 0;
+            android::status_t status = recordMQEventFlag->wait(
+                    static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+                    true /* retry on spurious wake */);
+            if (status != android::OK) {
+                ALOGD("[vts] wait for data ready on the record FMQ");
+                continue;
+            }
+            // Our current implementation filter the data and write it into the filter FMQ
+            // immediately after the DATA_READY from the VTS/framework
+            if (!readRecordFMQ()) {
+                ALOGD("[vts] record data failed to be filtered. Ending thread");
+                mRecordThreadRunning = false;
+                break;
+            }
+        }
+    }
+
+    mRecordThreadRunning = false;
+    ALOGD("[vts] record thread ended.");
+}
+
+bool DvrCallback::readRecordFMQ() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    bool result = false;
+    mDataOutputBuffer.clear();
+    mDataOutputBuffer.resize(mRecordMQ->availableToRead());
+    result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
+    EXPECT_TRUE(result) << "can't read from Record MQ";
+    mMsgCondition.signal();
+    return result;
+}
+
+void DvrCallback::stopRecordThread() {
+    mKeepReadingRecordFMQ = false;
+    mRecordThreadRunning = false;
+}
+
+AssertionResult DvrTests::openDvrInDemux(DvrType type, uint32_t bufferSize) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+
+    // Create dvr callback
+    if (type == DvrType::PLAYBACK) {
+        mDvrPlaybackCallback = new DvrCallback();
+        mDemux->openDvr(type, bufferSize, mDvrPlaybackCallback,
+                        [&](Result result, const sp<IDvr>& dvr) {
+                            mDvrPlayback = dvr;
+                            status = result;
+                        });
+        if (status == Result::SUCCESS) {
+            mDvrPlaybackCallback->setDvr(mDvrPlayback);
+        }
+    }
+
+    if (type == DvrType::RECORD) {
+        mDvrRecordCallback = new DvrCallback();
+        mDemux->openDvr(type, bufferSize, mDvrRecordCallback,
+                        [&](Result result, const sp<IDvr>& dvr) {
+                            mDvrRecord = dvr;
+                            status = result;
+                        });
+        if (status == Result::SUCCESS) {
+            mDvrRecordCallback->setDvr(mDvrRecord);
+        }
+    }
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::configDvrPlayback(DvrSettings setting) {
+    Result status = mDvrPlayback->configure(setting);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::configDvrRecord(DvrSettings setting) {
+    Result status = mDvrRecord->configure(setting);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::getDvrPlaybackMQDescriptor() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+    mDvrPlayback->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+        mDvrPlaybackMQDescriptor = dvrMQDesc;
+        status = result;
+    });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::getDvrRecordMQDescriptor() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    mDvrRecord->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+        mDvrRecordMQDescriptor = dvrMQDesc;
+        status = result;
+    });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::attachFilterToDvr(sp<IFilter> filter) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->attachFilter(filter);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::detachFilterToDvr(sp<IFilter> filter) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->detachFilter(filter);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::startDvrPlayback() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+    status = mDvrPlayback->start();
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::stopDvrPlayback() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+    status = mDvrPlayback->stop();
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+void DvrTests::closeDvrPlayback() {
+    ASSERT_TRUE(mDemux);
+    ASSERT_TRUE(mDvrPlayback);
+    ASSERT_TRUE(mDvrPlayback->close() == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::startDvrRecord() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->start();
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::stopDvrRecord() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->stop();
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+void DvrTests::closeDvrRecord() {
+    ASSERT_TRUE(mDemux);
+    ASSERT_TRUE(mDvrRecord);
+    ASSERT_TRUE(mDvrRecord->close() == Result::SUCCESS);
+}
diff --git a/tv/tuner/1.0/vts/functional/DvrTests.h b/tv/tuner/1.0/vts/functional/DvrTests.h
new file mode 100644
index 0000000..3997839
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/DvrTests.h
@@ -0,0 +1,194 @@
+/*
+ * 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 <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <fcntl.h>
+#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/Status.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <fstream>
+#include <iostream>
+#include <map>
+
+#include "FilterTests.h"
+
+using android::Condition;
+using android::Mutex;
+using android::sp;
+using android::hardware::EventFlag;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MessageQueue;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DvrSettings;
+using android::hardware::tv::tuner::V1_0::DvrType;
+using android::hardware::tv::tuner::V1_0::IDvr;
+using android::hardware::tv::tuner::V1_0::IDvrCallback;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
+using android::hardware::tv::tuner::V1_0::RecordStatus;
+using android::hardware::tv::tuner::V1_0::Result;
+
+using namespace std;
+
+#define WAIT_TIMEOUT 3000000000
+
+class DvrCallback : public IDvrCallback {
+  public:
+    virtual Return<void> onRecordStatus(DemuxFilterStatus status) override {
+        ALOGD("[vts] record status %hhu", status);
+        switch (status) {
+            case DemuxFilterStatus::DATA_READY:
+                break;
+            case DemuxFilterStatus::LOW_WATER:
+                break;
+            case DemuxFilterStatus::HIGH_WATER:
+            case DemuxFilterStatus::OVERFLOW:
+                ALOGD("[vts] record overflow. Flushing.");
+                EXPECT_TRUE(mDvr) << "Dvr callback is not set with an IDvr";
+                if (mDvr) {
+                    Result result = mDvr->flush();
+                    ALOGD("[vts] Flushing result %d.", result);
+                }
+                break;
+        }
+        return Void();
+    }
+
+    virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
+        // android::Mutex::Autolock autoLock(mMsgLock);
+        ALOGD("[vts] playback status %d", status);
+        switch (status) {
+            case PlaybackStatus::SPACE_EMPTY:
+            case PlaybackStatus::SPACE_ALMOST_EMPTY:
+                ALOGD("[vts] keep playback inputing %d", status);
+                mKeepWritingPlaybackFMQ = true;
+                break;
+            case PlaybackStatus::SPACE_ALMOST_FULL:
+            case PlaybackStatus::SPACE_FULL:
+                ALOGD("[vts] stop playback inputing %d", status);
+                mKeepWritingPlaybackFMQ = false;
+                break;
+        }
+        return Void();
+    }
+
+    void stopPlaybackThread();
+    void testRecordOutput();
+    void stopRecordThread();
+
+    void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings,
+                                  MQDesc& playbackMQDescriptor);
+    void startRecordOutputThread(RecordSettings recordSettings, MQDesc& recordMQDescriptor);
+    static void* __threadLoopPlayback(void* user);
+    static void* __threadLoopRecord(void* threadArgs);
+    void playbackThreadLoop();
+    void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ);
+
+    bool readRecordFMQ();
+
+    void setDvr(sp<IDvr> dvr) { mDvr = dvr; }
+
+  private:
+    struct RecordThreadArgs {
+        DvrCallback* user;
+        RecordSettings* recordSettings;
+        bool* keepReadingRecordFMQ;
+    };
+    // uint16_t mDataLength = 0;
+    std::vector<uint8_t> mDataOutputBuffer;
+
+    std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterMQ;
+    std::unique_ptr<FilterMQ> mPlaybackMQ;
+    std::unique_ptr<FilterMQ> mRecordMQ;
+    std::map<uint32_t, EventFlag*> mFilterMQEventFlag;
+
+    android::Mutex mMsgLock;
+    android::Mutex mPlaybackThreadLock;
+    android::Mutex mRecordThreadLock;
+    android::Condition mMsgCondition;
+
+    bool mKeepWritingPlaybackFMQ = true;
+    bool mKeepReadingRecordFMQ = true;
+    bool mPlaybackThreadRunning;
+    bool mRecordThreadRunning;
+    pthread_t mPlaybackThread;
+    pthread_t mRecordThread;
+    string mInputDataFile;
+    PlaybackSettings mPlaybackSettings;
+
+    sp<IDvr> mDvr = nullptr;
+
+    // int mPidFilterOutputCount = 0;
+};
+
+class DvrTests {
+  public:
+    void setService(sp<ITuner> tuner) { mService = tuner; }
+    void setDemux(sp<IDemux> demux) { mDemux = demux; }
+
+    void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings) {
+        mDvrPlaybackCallback->startPlaybackInputThread(dataInputFile, settings,
+                                                       mDvrPlaybackMQDescriptor);
+    };
+
+    void startRecordOutputThread(RecordSettings settings) {
+        mDvrRecordCallback->startRecordOutputThread(settings, mDvrRecordMQDescriptor);
+    };
+
+    void stopPlaybackThread() { mDvrPlaybackCallback->stopPlaybackThread(); }
+    void testRecordOutput() { mDvrRecordCallback->testRecordOutput(); }
+    void stopRecordThread() { mDvrRecordCallback->stopRecordThread(); }
+
+    AssertionResult openDvrInDemux(DvrType type, uint32_t bufferSize);
+    AssertionResult configDvrPlayback(DvrSettings setting);
+    AssertionResult configDvrRecord(DvrSettings setting);
+    AssertionResult getDvrPlaybackMQDescriptor();
+    AssertionResult getDvrRecordMQDescriptor();
+    AssertionResult attachFilterToDvr(sp<IFilter> filter);
+    AssertionResult detachFilterToDvr(sp<IFilter> filter);
+    AssertionResult stopDvrPlayback();
+    AssertionResult startDvrPlayback();
+    AssertionResult stopDvrRecord();
+    AssertionResult startDvrRecord();
+    void closeDvrPlayback();
+    void closeDvrRecord();
+
+  protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+    sp<ITuner> mService;
+    sp<IDvr> mDvrPlayback;
+    sp<IDvr> mDvrRecord;
+    sp<IDemux> mDemux;
+    sp<DvrCallback> mDvrPlaybackCallback;
+    sp<DvrCallback> mDvrRecordCallback;
+    MQDesc mDvrPlaybackMQDescriptor;
+    MQDesc mDvrRecordMQDescriptor;
+};
diff --git a/tv/tuner/1.0/vts/functional/FilterTests.cpp b/tv/tuner/1.0/vts/functional/FilterTests.cpp
new file mode 100644
index 0000000..0ecdf73
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/FilterTests.cpp
@@ -0,0 +1,302 @@
+/*
+ * 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 "FilterTests.h"
+
+void FilterCallback::startFilterEventThread(DemuxFilterEvent event) {
+    struct FilterThreadArgs* threadArgs =
+            (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs));
+    threadArgs->user = this;
+    threadArgs->event = event;
+
+    pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs);
+    pthread_setname_np(mFilterThread, "test_playback_input_loop");
+}
+
+void FilterCallback::testFilterDataOutput() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (mPidFilterOutputCount < 1) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
+            return;
+        }
+    }
+    mPidFilterOutputCount = 0;
+    ALOGW("[vts] pass and stop");
+}
+
+void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) {
+    mFilterMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mFilterMQ);
+    EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) ==
+                android::OK);
+}
+
+void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) {
+    mFilterIdToGoldenOutput = goldenOutputFile;
+}
+
+void* FilterCallback::__threadLoopFilter(void* threadArgs) {
+    FilterCallback* const self =
+            static_cast<FilterCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
+    self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event);
+    return 0;
+}
+
+void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
+    android::Mutex::Autolock autoLock(mFilterOutputLock);
+    // Read from mFilterMQ[event.filterId] per event and filter type
+
+    // Assemble to filterOutput[filterId]
+
+    // check if filterOutput[filterId] matches goldenOutput[filterId]
+
+    // If match, remove filterId entry from MQ map
+
+    // end thread
+}
+
+bool FilterCallback::readFilterEventData() {
+    bool result = false;
+    DemuxFilterEvent filterEvent = mFilterEvent;
+    ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId);
+    // todo separate filter handlers
+    for (int i = 0; i < filterEvent.events.size(); i++) {
+        switch (mFilterEventType) {
+            case FilterEventType::SECTION:
+                mDataLength = filterEvent.events[i].section().dataLength;
+                break;
+            case FilterEventType::PES:
+                mDataLength = filterEvent.events[i].pes().dataLength;
+                break;
+            case FilterEventType::MEDIA:
+                return dumpAvData(filterEvent.events[i].media());
+            case FilterEventType::RECORD:
+                break;
+            case FilterEventType::MMTPRECORD:
+                break;
+            case FilterEventType::DOWNLOAD:
+                break;
+            default:
+                break;
+        }
+        // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not
+        // match";
+
+        mDataOutputBuffer.resize(mDataLength);
+        result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength);
+        EXPECT_TRUE(result) << "can't read from Filter MQ";
+
+        /*for (int i = 0; i < mDataLength; i++) {
+            EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
+        }*/
+    }
+    mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+    return result;
+}
+
+bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) {
+    uint32_t length = event.dataLength;
+    uint64_t dataId = event.avDataId;
+    // read data from buffer pointed by a handle
+    hidl_handle handle = event.avMemory;
+
+    int av_fd = handle.getNativeHandle()->data[0];
+    uint8_t* buffer = static_cast<uint8_t*>(
+            mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0 /*offset*/));
+    if (buffer == MAP_FAILED) {
+        ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
+        return false;
+    }
+    uint8_t output[length + 1];
+    memcpy(output, buffer, length);
+    // print buffer and check with golden output.
+    EXPECT_TRUE(mFilter->releaseAvHandle(handle, dataId) == Result::SUCCESS);
+    return true;
+}
+
+AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+
+    // Create demux callback
+    mFilterCallback = new FilterCallback();
+
+    // Add filter to the local demux
+    mDemux->openFilter(type, bufferSize, mFilterCallback,
+                       [&](Result result, const sp<IFilter>& filter) {
+                           mFilter = filter;
+                           status = result;
+                       });
+
+    if (status == Result::SUCCESS) {
+        mFilterCallback->setFilterEventType(getFilterEventType(type));
+    }
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::openTimeFilterInDemux() {
+    if (!mDemux) {
+        ALOGW("[vts] Test with openDemux first.");
+        return failure();
+    }
+
+    // Add time filter to the local demux
+    Result status;
+    mDemux->openTimeFilter([&](Result result, const sp<ITimeFilter>& filter) {
+        mTimeFilter = filter;
+        status = result;
+    });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::setTimeStamp(uint64_t timeStamp) {
+    if (!mTimeFilter) {
+        ALOGW("[vts] Test with openTimeFilterInDemux first.");
+        return failure();
+    }
+
+    mBeginTimeStamp = timeStamp;
+    return AssertionResult(mTimeFilter->setTimeStamp(timeStamp) == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::getTimeStamp() {
+    if (!mTimeFilter) {
+        ALOGW("[vts] Test with openTimeFilterInDemux first.");
+        return failure();
+    }
+
+    Result status;
+    mTimeFilter->getTimeStamp([&](Result result, uint64_t /*timeStamp*/) { status = result; });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::getNewlyOpenedFilterId(uint32_t& filterId) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first.";
+    EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first.";
+
+    mFilter->getId([&](Result result, uint32_t filterId) {
+        mFilterId = filterId;
+        status = result;
+    });
+
+    if (status == Result::SUCCESS) {
+        mFilterCallback->setFilterId(mFilterId);
+        mFilterCallback->setFilterInterface(mFilter);
+        mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId);
+        mFilters[mFilterId] = mFilter;
+        mFilterCallbacks[mFilterId] = mFilterCallback;
+        filterId = mFilterId;
+    }
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint32_t filterId) {
+    Result status;
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    status = mFilters[filterId]->configure(setting);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::getFilterMQDescriptor(uint32_t filterId) {
+    Result status;
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
+
+    mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) {
+        mFilterMQDescriptor = filterMQDesc;
+        status = result;
+    });
+
+    if (status == Result::SUCCESS) {
+        mFilterCallbacks[filterId]->updateFilterMQ(mFilterMQDescriptor);
+    }
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::setFilterDataSource(uint32_t sourceFilterId, uint32_t sinkFilterId) {
+    if (!mFilters[sourceFilterId] || !mFilters[sinkFilterId]) {
+        ALOGE("[vts] setFilterDataSource filter not opened.");
+        return failure();
+    }
+
+    auto status = mFilters[sinkFilterId]->setDataSource(mFilters[sourceFilterId]);
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::setFilterDataSourceToDemux(uint32_t filterId) {
+    if (!mFilters[filterId]) {
+        ALOGE("[vts] setFilterDataSourceToDemux filter not opened.");
+        return failure();
+    }
+
+    auto status = mFilters[filterId]->setDataSource(NULL);
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::startFilter(uint32_t filterId) {
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    Result status = mFilters[filterId]->start();
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::stopFilter(uint32_t filterId) {
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    Result status = mFilters[filterId]->stop();
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::clearTimeStamp() {
+    if (!mTimeFilter) {
+        ALOGW("[vts] Test with openTimeFilterInDemux first.");
+        return failure();
+    }
+
+    return AssertionResult(mTimeFilter->clearTimeStamp() == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::closeFilter(uint32_t filterId) {
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    Result status = mFilters[filterId]->close();
+    if (status == Result::SUCCESS) {
+        for (int i = 0; i < mUsedFilterIds.size(); i++) {
+            if (mUsedFilterIds[i] == filterId) {
+                mUsedFilterIds.erase(mUsedFilterIds.begin() + i);
+                break;
+            }
+        }
+        mFilterCallbacks.erase(filterId);
+        mFilters.erase(filterId);
+    }
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::closeTimeFilter() {
+    if (!mTimeFilter) {
+        ALOGW("[vts] Test with openTimeFilterInDemux first.");
+        return failure();
+    }
+
+    return AssertionResult(mTimeFilter->close() == Result::SUCCESS);
+}
diff --git a/tv/tuner/1.0/vts/functional/FilterTests.h b/tv/tuner/1.0/vts/functional/FilterTests.h
new file mode 100644
index 0000000..a76a6b9
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/FilterTests.h
@@ -0,0 +1,234 @@
+/*
+ * 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 <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IFilter.h>
+#include <android/hardware/tv/tuner/1.0/IFilterCallback.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <map>
+
+using android::Condition;
+using android::Mutex;
+using android::sp;
+using android::hardware::EventFlag;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MessageQueue;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::IDemux;
+using android::hardware::tv::tuner::V1_0::IFilter;
+using android::hardware::tv::tuner::V1_0::IFilterCallback;
+using android::hardware::tv::tuner::V1_0::ITimeFilter;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::Result;
+
+using ::testing::AssertionResult;
+
+using namespace std;
+
+enum FilterEventType : uint8_t {
+    UNDEFINED,
+    SECTION,
+    MEDIA,
+    PES,
+    RECORD,
+    MMTPRECORD,
+    DOWNLOAD,
+    TEMI,
+};
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using MQDesc = MQDescriptorSync<uint8_t>;
+
+#define WAIT_TIMEOUT 3000000000
+
+class FilterCallback : public IFilterCallback {
+  public:
+    virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        // Temprarily we treat the first coming back filter data on the matching pid a success
+        // once all of the MQ are cleared, means we got all the expected output
+        mFilterEvent = filterEvent;
+        readFilterEventData();
+        mPidFilterOutputCount++;
+        // mFilterIdToMQ.erase(filterEvent.filterId);
+
+        // startFilterEventThread(filterEvent);
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    virtual Return<void> onFilterStatus(const DemuxFilterStatus /*status*/) override {
+        return Void();
+    }
+
+    void setFilterId(uint32_t filterId) { mFilterId = filterId; }
+    void setFilterInterface(sp<IFilter> filter) { mFilter = filter; }
+    void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
+
+    void testFilterDataOutput();
+
+    void startFilterEventThread(DemuxFilterEvent event);
+    static void* __threadLoopFilter(void* threadArgs);
+    void filterThreadLoop(DemuxFilterEvent& event);
+
+    void updateFilterMQ(MQDesc& filterMQDescriptor);
+    void updateGoldenOutputMap(string goldenOutputFile);
+    bool readFilterEventData();
+    bool dumpAvData(DemuxFilterMediaEvent event);
+
+  private:
+    struct FilterThreadArgs {
+        FilterCallback* user;
+        DemuxFilterEvent event;
+    };
+    uint16_t mDataLength = 0;
+    std::vector<uint8_t> mDataOutputBuffer;
+
+    string mFilterIdToGoldenOutput;
+
+    uint32_t mFilterId;
+    sp<IFilter> mFilter;
+    FilterEventType mFilterEventType;
+    std::unique_ptr<FilterMQ> mFilterMQ;
+    EventFlag* mFilterMQEventFlag;
+    DemuxFilterEvent mFilterEvent;
+
+    android::Mutex mMsgLock;
+    android::Mutex mFilterOutputLock;
+    android::Condition mMsgCondition;
+    android::Condition mFilterOutputCondition;
+
+    pthread_t mFilterThread;
+
+    int mPidFilterOutputCount = 0;
+};
+
+class FilterTests {
+  public:
+    void setService(sp<ITuner> tuner) { mService = tuner; }
+    void setDemux(sp<IDemux> demux) { mDemux = demux; }
+    sp<IFilter> getFilterById(uint32_t filterId) { return mFilters[filterId]; }
+
+    std::map<uint32_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
+
+    AssertionResult openFilterInDemux(DemuxFilterType type, uint32_t bufferSize);
+    AssertionResult openTimeFilterInDemux();
+    AssertionResult setTimeStamp(uint64_t timeStamp);
+    AssertionResult getTimeStamp();
+    AssertionResult getNewlyOpenedFilterId(uint32_t& filterId);
+    AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId);
+    AssertionResult getFilterMQDescriptor(uint32_t filterId);
+    AssertionResult setFilterDataSource(uint32_t sourceFilterId, uint32_t sinkFilterId);
+    AssertionResult setFilterDataSourceToDemux(uint32_t filterId);
+    AssertionResult startFilter(uint32_t filterId);
+    AssertionResult clearTimeStamp();
+    AssertionResult stopFilter(uint32_t filterId);
+    AssertionResult closeFilter(uint32_t filterId);
+    AssertionResult closeTimeFilter();
+
+    FilterEventType getFilterEventType(DemuxFilterType type) {
+        FilterEventType eventType = FilterEventType::UNDEFINED;
+        switch (type.mainType) {
+            case DemuxFilterMainType::TS:
+                switch (type.subType.tsFilterType()) {
+                    case DemuxTsFilterType::UNDEFINED:
+                        break;
+                    case DemuxTsFilterType::SECTION:
+                        eventType = FilterEventType::SECTION;
+                        break;
+                    case DemuxTsFilterType::PES:
+                        eventType = FilterEventType::PES;
+                        break;
+                    case DemuxTsFilterType::TS:
+                        break;
+                    case DemuxTsFilterType::AUDIO:
+                    case DemuxTsFilterType::VIDEO:
+                        eventType = FilterEventType::MEDIA;
+                        break;
+                    case DemuxTsFilterType::PCR:
+                        break;
+                    case DemuxTsFilterType::RECORD:
+                        eventType = FilterEventType::RECORD;
+                        break;
+                    case DemuxTsFilterType::TEMI:
+                        eventType = FilterEventType::TEMI;
+                        break;
+                }
+                break;
+            case DemuxFilterMainType::MMTP:
+                /*mmtpSettings*/
+                break;
+            case DemuxFilterMainType::IP:
+                /*ipSettings*/
+                break;
+            case DemuxFilterMainType::TLV:
+                /*tlvSettings*/
+                break;
+            case DemuxFilterMainType::ALP:
+                /*alpSettings*/
+                break;
+            default:
+                break;
+        }
+        return eventType;
+    }
+
+  protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+    sp<ITuner> mService;
+    sp<IFilter> mFilter;
+    sp<ITimeFilter> mTimeFilter;
+    sp<IDemux> mDemux;
+    std::map<uint32_t, sp<IFilter>> mFilters;
+    std::map<uint32_t, sp<FilterCallback>> mFilterCallbacks;
+
+    sp<FilterCallback> mFilterCallback;
+    MQDesc mFilterMQDescriptor;
+    vector<uint32_t> mUsedFilterIds;
+
+    uint32_t mFilterId = -1;
+    uint64_t mBeginTimeStamp;
+};
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.cpp b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
new file mode 100644
index 0000000..45951d2
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
@@ -0,0 +1,452 @@
+/*
+ * 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 "FrontendTests.h"
+
+Return<void> FrontendCallback::onEvent(FrontendEventType frontendEventType) {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    ALOGD("[vts] frontend event received. Type: %d", frontendEventType);
+    mEventReceived = true;
+    mMsgCondition.signal();
+    switch (frontendEventType) {
+        case FrontendEventType::LOCKED:
+            mLockMsgReceived = true;
+            mLockMsgCondition.signal();
+            return Void();
+        default:
+            // do nothing
+            return Void();
+    }
+}
+
+Return<void> FrontendCallback::onScanMessage(FrontendScanMessageType type,
+                                             const FrontendScanMessage& message) {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mScanMsgProcessed) {
+        mMsgCondition.wait(mMsgLock);
+    }
+    ALOGD("[vts] frontend scan message. Type: %d", type);
+    mScanMessageReceived = true;
+    mScanMsgProcessed = false;
+    mScanMessageType = type;
+    mScanMessage = message;
+    mMsgCondition.signal();
+    return Void();
+}
+
+void FrontendCallback::tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings) {
+    Result result = frontend->tune(settings);
+    EXPECT_TRUE(result == Result::SUCCESS);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "Event not received within timeout";
+            mLockMsgReceived = false;
+            return;
+        }
+    }
+    mEventReceived = false;
+}
+
+void FrontendCallback::tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings) {
+    Result result = frontend->tune(settings);
+    EXPECT_TRUE(result == Result::SUCCESS);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mLockMsgReceived) {
+        if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "Event LOCKED not received within timeout";
+            mLockMsgReceived = false;
+            return;
+        }
+    }
+    mLockMsgReceived = false;
+}
+
+void FrontendCallback::scanTest(sp<IFrontend>& frontend, FrontendConfig config,
+                                FrontendScanType type) {
+    uint32_t targetFrequency = getTargetFrequency(config.settings, config.type);
+    if (type == FrontendScanType::SCAN_BLIND) {
+        // reset the frequency in the scan configuration to test blind scan. The settings param of
+        // passed in means the real input config on the transponder connected to the DUT.
+        // We want the blind the test to start from lower frequency than this to check the blind
+        // scan implementation.
+        resetBlindScanStartingFrequency(config, targetFrequency - 100);
+    }
+
+    Result result = frontend->scan(config.settings, type);
+    EXPECT_TRUE(result == Result::SUCCESS);
+
+    bool scanMsgLockedReceived = false;
+    bool targetFrequencyReceived = false;
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+wait:
+    while (!mScanMessageReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "Scan message not received within timeout";
+            mScanMessageReceived = false;
+            mScanMsgProcessed = true;
+            return;
+        }
+    }
+
+    if (mScanMessageType != FrontendScanMessageType::END) {
+        if (mScanMessageType == FrontendScanMessageType::LOCKED) {
+            scanMsgLockedReceived = true;
+            Result result = frontend->scan(config.settings, type);
+            EXPECT_TRUE(result == Result::SUCCESS);
+        }
+
+        if (mScanMessageType == FrontendScanMessageType::FREQUENCY) {
+            targetFrequencyReceived = mScanMessage.frequencies().size() > 0 &&
+                                      mScanMessage.frequencies()[0] == targetFrequency;
+        }
+
+        if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) {
+            ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent());
+        }
+
+        mScanMessageReceived = false;
+        mScanMsgProcessed = true;
+        mMsgCondition.signal();
+        goto wait;
+    }
+
+    EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END";
+    EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan";
+    mScanMessageReceived = false;
+    mScanMsgProcessed = true;
+}
+
+uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) {
+    switch (type) {
+        case FrontendType::ANALOG:
+            return settings.analog().frequency;
+        case FrontendType::ATSC:
+            return settings.atsc().frequency;
+        case FrontendType::ATSC3:
+            return settings.atsc3().frequency;
+        case FrontendType::DVBC:
+            return settings.dvbc().frequency;
+        case FrontendType::DVBS:
+            return settings.dvbs().frequency;
+        case FrontendType::DVBT:
+            return settings.dvbt().frequency;
+        case FrontendType::ISDBS:
+            return settings.isdbs().frequency;
+        case FrontendType::ISDBS3:
+            return settings.isdbs3().frequency;
+        case FrontendType::ISDBT:
+            return settings.isdbt().frequency;
+        default:
+            return 0;
+    }
+}
+
+void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config,
+                                                       uint32_t resetingFreq) {
+    switch (config.type) {
+        case FrontendType::ANALOG:
+            config.settings.analog().frequency = resetingFreq;
+            break;
+        case FrontendType::ATSC:
+            config.settings.atsc().frequency = resetingFreq;
+            break;
+        case FrontendType::ATSC3:
+            config.settings.atsc3().frequency = resetingFreq;
+            break;
+        case FrontendType::DVBC:
+            config.settings.dvbc().frequency = resetingFreq;
+            break;
+        case FrontendType::DVBS:
+            config.settings.dvbs().frequency = resetingFreq;
+            break;
+        case FrontendType::DVBT:
+            config.settings.dvbt().frequency = resetingFreq;
+            break;
+        case FrontendType::ISDBS:
+            config.settings.isdbs().frequency = resetingFreq;
+            break;
+        case FrontendType::ISDBS3:
+            config.settings.isdbs3().frequency = resetingFreq;
+            break;
+        case FrontendType::ISDBT:
+            config.settings.isdbt().frequency = resetingFreq;
+            break;
+        default:
+            // do nothing
+            return;
+    }
+}
+
+AssertionResult FrontendTests::getFrontendIds() {
+    Result status;
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        mFeIds = frontendIds;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::getFrontendInfo(uint32_t frontendId) {
+    Result status;
+    mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) {
+        mFrontendInfo = frontendInfo;
+        status = result;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::openFrontendById(uint32_t frontendId) {
+    Result status;
+    mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) {
+        mFrontend = frontend;
+        status = result;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::setFrontendCallback() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+    mFrontendCallback = new FrontendCallback();
+    auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
+    return AssertionResult(callbackStatus.isOk());
+}
+
+AssertionResult FrontendTests::scanFrontend(FrontendConfig config, FrontendScanType type) {
+    EXPECT_TRUE(mFrontendCallback)
+            << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
+
+    EXPECT_TRUE(mFrontendInfo.type == config.type)
+            << "FrontendConfig does not match the frontend info of the given id.";
+
+    mFrontendCallback->scanTest(mFrontend, config, type);
+    return AssertionResult(true);
+}
+
+AssertionResult FrontendTests::stopScanFrontend() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+    Result status;
+    status = mFrontend->stopScan();
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+void FrontendTests::verifyFrontendStatus(vector<FrontendStatusType> statusTypes,
+                                         vector<FrontendStatus> expectStatuses) {
+    ASSERT_TRUE(mFrontend) << "Frontend is not opened yet.";
+    Result status;
+    vector<FrontendStatus> realStatuses;
+
+    mFrontend->getStatus(statusTypes, [&](Result result, const hidl_vec<FrontendStatus>& statuses) {
+        status = result;
+        realStatuses = statuses;
+    });
+
+    ASSERT_TRUE(realStatuses.size() == statusTypes.size());
+    for (int i = 0; i < statusTypes.size(); i++) {
+        FrontendStatusType type = statusTypes[i];
+        switch (type) {
+            case FrontendStatusType::DEMOD_LOCK: {
+                ASSERT_TRUE(realStatuses[i].isDemodLocked() == expectStatuses[i].isDemodLocked());
+                break;
+            }
+            case FrontendStatusType::SNR: {
+                ASSERT_TRUE(realStatuses[i].snr() == expectStatuses[i].snr());
+                break;
+            }
+            case FrontendStatusType::BER: {
+                ASSERT_TRUE(realStatuses[i].ber() == expectStatuses[i].ber());
+                break;
+            }
+            case FrontendStatusType::PER: {
+                ASSERT_TRUE(realStatuses[i].per() == expectStatuses[i].per());
+                break;
+            }
+            case FrontendStatusType::PRE_BER: {
+                ASSERT_TRUE(realStatuses[i].preBer() == expectStatuses[i].preBer());
+                break;
+            }
+            case FrontendStatusType::SIGNAL_QUALITY: {
+                ASSERT_TRUE(realStatuses[i].signalQuality() == expectStatuses[i].signalQuality());
+                break;
+            }
+            case FrontendStatusType::SIGNAL_STRENGTH: {
+                ASSERT_TRUE(realStatuses[i].signalStrength() == expectStatuses[i].signalStrength());
+                break;
+            }
+            case FrontendStatusType::SYMBOL_RATE: {
+                ASSERT_TRUE(realStatuses[i].symbolRate() == expectStatuses[i].symbolRate());
+                break;
+            }
+            case FrontendStatusType::FEC: {
+                ASSERT_TRUE(realStatuses[i].innerFec() == expectStatuses[i].innerFec());
+                break;
+            }
+            case FrontendStatusType::MODULATION: {
+                // TODO: check modulation status
+                break;
+            }
+            case FrontendStatusType::SPECTRAL: {
+                ASSERT_TRUE(realStatuses[i].inversion() == expectStatuses[i].inversion());
+                break;
+            }
+            case FrontendStatusType::LNB_VOLTAGE: {
+                ASSERT_TRUE(realStatuses[i].lnbVoltage() == expectStatuses[i].lnbVoltage());
+                break;
+            }
+            case FrontendStatusType::PLP_ID: {
+                ASSERT_TRUE(realStatuses[i].plpId() == expectStatuses[i].plpId());
+                break;
+            }
+            case FrontendStatusType::EWBS: {
+                ASSERT_TRUE(realStatuses[i].isEWBS() == expectStatuses[i].isEWBS());
+                break;
+            }
+            case FrontendStatusType::AGC: {
+                ASSERT_TRUE(realStatuses[i].agc() == expectStatuses[i].agc());
+                break;
+            }
+            case FrontendStatusType::LNA: {
+                ASSERT_TRUE(realStatuses[i].isLnaOn() == expectStatuses[i].isLnaOn());
+                break;
+            }
+            case FrontendStatusType::LAYER_ERROR: {
+                vector<bool> realLayberError = realStatuses[i].isLayerError();
+                vector<bool> expectLayerError = expectStatuses[i].isLayerError();
+                ASSERT_TRUE(realLayberError.size() == expectLayerError.size());
+                for (int i = 0; i < realLayberError.size(); i++) {
+                    ASSERT_TRUE(realLayberError[i] == expectLayerError[i]);
+                }
+                break;
+            }
+            case FrontendStatusType::MER: {
+                ASSERT_TRUE(realStatuses[i].mer() == expectStatuses[i].mer());
+                break;
+            }
+            case FrontendStatusType::FREQ_OFFSET: {
+                ASSERT_TRUE(realStatuses[i].freqOffset() == expectStatuses[i].freqOffset());
+                break;
+            }
+            case FrontendStatusType::HIERARCHY: {
+                ASSERT_TRUE(realStatuses[i].hierarchy() == expectStatuses[i].hierarchy());
+                break;
+            }
+            case FrontendStatusType::RF_LOCK: {
+                ASSERT_TRUE(realStatuses[i].isRfLocked() == expectStatuses[i].isRfLocked());
+                break;
+            }
+            case FrontendStatusType::ATSC3_PLP_INFO:
+                // TODO: verify plpinfo
+                break;
+            default:
+                continue;
+        }
+    }
+    ASSERT_TRUE(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWithDemux) {
+    EXPECT_TRUE(mFrontendCallback)
+            << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
+
+    EXPECT_TRUE(mFrontendInfo.type == config.type)
+            << "FrontendConfig does not match the frontend info of the given id.";
+
+    mIsSoftwareFe = config.isSoftwareFe;
+    bool result = true;
+    if (mIsSoftwareFe && testWithDemux) {
+        DvrConfig dvrConfig;
+        getSoftwareFrontendPlaybackConfig(dvrConfig);
+        result &= mDvrTests.openDvrInDemux(dvrConfig.type, dvrConfig.bufferSize) == success();
+        result &= mDvrTests.configDvrPlayback(dvrConfig.settings) == success();
+        result &= mDvrTests.getDvrPlaybackMQDescriptor() == success();
+        mDvrTests.startPlaybackInputThread(dvrConfig.playbackInputFile,
+                                           dvrConfig.settings.playback());
+        if (!result) {
+            ALOGW("[vts] Software frontend dvr configure failed.");
+            return failure();
+        }
+    }
+    mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
+    return AssertionResult(true);
+}
+
+AssertionResult FrontendTests::setLnb(uint32_t lnbId) {
+    if (!mFrontendCallback) {
+        ALOGW("[vts] open and set frontend callback first.");
+        return failure();
+    }
+    return AssertionResult(mFrontend->setLnb(lnbId) == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+    Result status;
+    status = mFrontend->stopTune();
+    if (mIsSoftwareFe && testWithDemux) {
+        mDvrTests.stopPlaybackThread();
+        mDvrTests.closeDvrPlayback();
+    }
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::closeFrontend() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+    Result status;
+    status = mFrontend->close();
+    mFrontend = nullptr;
+    mFrontendCallback = nullptr;
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) {
+    ASSERT_TRUE(getFrontendIds());
+    ASSERT_TRUE(mFeIds.size() > 0);
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+        if (mFrontendInfo.type != feType) {
+            continue;
+        }
+        feId = mFeIds[i];
+        return;
+    }
+    feId = INVALID_ID;
+}
+
+void FrontendTests::tuneTest(FrontendConfig frontendConf) {
+    uint32_t feId;
+    getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(openFrontendById(feId));
+    ASSERT_TRUE(setFrontendCallback());
+    ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
+    verifyFrontendStatus(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
+    ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
+    ASSERT_TRUE(closeFrontend());
+}
+
+void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
+    uint32_t feId;
+    getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(openFrontendById(feId));
+    ASSERT_TRUE(setFrontendCallback());
+    ASSERT_TRUE(scanFrontend(frontendConf, scanType));
+    ASSERT_TRUE(stopScanFrontend());
+    ASSERT_TRUE(closeFrontend());
+}
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.h b/tv/tuner/1.0/vts/functional/FrontendTests.h
new file mode 100644
index 0000000..c536325
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.h
@@ -0,0 +1,154 @@
+/*
+ * 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 <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IFrontend.h>
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <map>
+
+#include "DvrTests.h"
+#include "VtsHalTvTunerV1_0TestConfigurations.h"
+
+#define WAIT_TIMEOUT 3000000000
+#define INVALID_ID -1
+
+using android::Condition;
+using android::IMemory;
+using android::IMemoryHeap;
+using android::MemoryDealer;
+using android::Mutex;
+using android::sp;
+using android::hardware::fromHeap;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::FrontendAtscModulation;
+using android::hardware::tv::tuner::V1_0::FrontendAtscSettings;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
+using android::hardware::tv::tuner::V1_0::FrontendEventType;
+using android::hardware::tv::tuner::V1_0::FrontendId;
+using android::hardware::tv::tuner::V1_0::FrontendInfo;
+using android::hardware::tv::tuner::V1_0::FrontendInnerFec;
+using android::hardware::tv::tuner::V1_0::FrontendScanMessage;
+using android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
+using android::hardware::tv::tuner::V1_0::FrontendScanType;
+using android::hardware::tv::tuner::V1_0::FrontendSettings;
+using android::hardware::tv::tuner::V1_0::IFrontend;
+using android::hardware::tv::tuner::V1_0::IFrontendCallback;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::Result;
+
+using ::testing::AssertionResult;
+
+using namespace std;
+
+#define INVALID_ID -1
+#define WAIT_TIMEOUT 3000000000
+
+class FrontendCallback : public IFrontendCallback {
+  public:
+    virtual Return<void> onEvent(FrontendEventType frontendEventType) override;
+    virtual Return<void> onScanMessage(FrontendScanMessageType type,
+                                       const FrontendScanMessage& message) override;
+
+    void tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings);
+    void tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings);
+    void scanTest(sp<IFrontend>& frontend, FrontendConfig config, FrontendScanType type);
+
+    // Helper methods
+    uint32_t getTargetFrequency(FrontendSettings settings, FrontendType type);
+    void resetBlindScanStartingFrequency(FrontendConfig& config, uint32_t resetingFreq);
+
+  private:
+    bool mEventReceived = false;
+    bool mScanMessageReceived = false;
+    bool mLockMsgReceived = false;
+    bool mScanMsgProcessed = true;
+    FrontendScanMessageType mScanMessageType;
+    FrontendScanMessage mScanMessage;
+    hidl_vec<uint8_t> mEventMessage;
+    android::Mutex mMsgLock;
+    android::Condition mMsgCondition;
+    android::Condition mLockMsgCondition;
+};
+
+class FrontendTests {
+  public:
+    sp<ITuner> mService;
+
+    void setService(sp<ITuner> tuner) {
+        mService = tuner;
+        mDvrTests.setService(tuner);
+    }
+
+    AssertionResult getFrontendIds();
+    AssertionResult getFrontendInfo(uint32_t frontendId);
+    AssertionResult openFrontendById(uint32_t frontendId);
+    AssertionResult setFrontendCallback();
+    AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type);
+    AssertionResult stopScanFrontend();
+    AssertionResult tuneFrontend(FrontendConfig config, bool testWithDemux);
+    AssertionResult setLnb(uint32_t lnbId);
+    void verifyFrontendStatus(vector<FrontendStatusType> statusTypes,
+                              vector<FrontendStatus> expectStatuses);
+    AssertionResult stopTuneFrontend(bool testWithDemux);
+    AssertionResult closeFrontend();
+
+    void getFrontendIdByType(FrontendType feType, uint32_t& feId);
+    void tuneTest(FrontendConfig frontendConf);
+    void scanTest(FrontendConfig frontend, FrontendScanType type);
+
+    void setDvrTests(DvrTests dvrTests) { mDvrTests = dvrTests; }
+    void setDemux(sp<IDemux> demux) { mDvrTests.setDemux(demux); }
+
+  protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+    void getSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
+        PlaybackSettings playbackSettings{
+                .statusMask = 0xf,
+                .lowThreshold = 0x1000,
+                .highThreshold = 0x07fff,
+                .dataFormat = DataFormat::TS,
+                .packetSize = 188,
+        };
+        dvrConfig.type = DvrType::PLAYBACK;
+        dvrConfig.playbackInputFile = "/data/local/tmp/segment000000.ts";
+        dvrConfig.bufferSize = FMQ_SIZE_4M;
+        dvrConfig.settings.playback(playbackSettings);
+    }
+
+    sp<IFrontend> mFrontend;
+    FrontendInfo mFrontendInfo;
+    sp<FrontendCallback> mFrontendCallback;
+    hidl_vec<FrontendId> mFeIds;
+
+    DvrTests mDvrTests;
+    bool mIsSoftwareFe = false;
+};
diff --git a/tv/tuner/1.0/vts/functional/LnbTests.cpp b/tv/tuner/1.0/vts/functional/LnbTests.cpp
new file mode 100644
index 0000000..9080f59
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/LnbTests.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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 "LnbTests.h"
+
+Return<void> LnbCallback::onEvent(LnbEventType lnbEventType) {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    ALOGD("[vts] lnb event received. Type: %d", lnbEventType);
+    mEventReceived = true;
+    mMsgCondition.signal();
+    return Void();
+}
+
+Return<void> LnbCallback::onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) {
+    string msg(diseqcMessage.begin(), diseqcMessage.end());
+    ALOGD("[vts] onDiseqcMessage %s", msg.c_str());
+    return Void();
+}
+
+AssertionResult LnbTests::getLnbIds(vector<uint32_t>& ids) {
+    Result status;
+    mService->getLnbIds([&](Result result, const hidl_vec<uint32_t>& lnbIds) {
+        status = result;
+        ids = lnbIds;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult LnbTests::openLnbById(uint32_t lnbId) {
+    Result status;
+    mService->openLnbById(lnbId, [&](Result result, const sp<ILnb>& lnb) {
+        mLnb = lnb;
+        status = result;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult LnbTests::openLnbByName(string lnbName) {
+    Result status;
+    mService->openLnbByName(lnbName, [&](Result result, uint32_t /*lnbId*/, const sp<ILnb>& lnb) {
+        mLnb = lnb;
+        status = result;
+    });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult LnbTests::setLnbCallback() {
+    if (!mLnb) {
+        ALOGW("[vts] Open Lnb first");
+        return failure();
+    }
+    mLnbCallback = new LnbCallback();
+    auto callbackStatus = mLnb->setCallback(mLnbCallback);
+    return AssertionResult(callbackStatus.isOk());
+}
+
+AssertionResult LnbTests::setVoltage(LnbVoltage voltage) {
+    if (!mLnb) {
+        ALOGW("[vts] Open Lnb first");
+        return failure();
+    }
+    Result status = mLnb->setVoltage(voltage);
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult LnbTests::setTone(LnbTone tone) {
+    if (!mLnb) {
+        ALOGW("[vts] Open Lnb first");
+        return failure();
+    }
+    Result status = mLnb->setTone(tone);
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult LnbTests::setSatellitePosition(LnbPosition position) {
+    if (!mLnb) {
+        ALOGW("[vts] Open Lnb first");
+        return failure();
+    }
+    Result status = mLnb->setSatellitePosition(position);
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult LnbTests::sendDiseqcMessage(vector<uint8_t> diseqcMsg) {
+    if (!mLnb) {
+        ALOGW("[vts] Open Lnb first");
+        return failure();
+    }
+    Result status = mLnb->sendDiseqcMessage(diseqcMsg);
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult LnbTests::closeLnb() {
+    if (!mLnb) {
+        ALOGW("[vts] Open Lnb first");
+        return failure();
+    }
+    Result status = mLnb->close();
+    mLnb = nullptr;
+    mLnbCallback = nullptr;
+    return AssertionResult(status == Result::SUCCESS);
+}
diff --git a/tv/tuner/1.0/vts/functional/LnbTests.h b/tv/tuner/1.0/vts/functional/LnbTests.h
new file mode 100644
index 0000000..2fdbe2c
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/LnbTests.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/ILnb.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <map>
+
+using android::Condition;
+using android::Mutex;
+using android::sp;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::ILnb;
+using android::hardware::tv::tuner::V1_0::ILnbCallback;
+using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::LnbEventType;
+using android::hardware::tv::tuner::V1_0::LnbPosition;
+using android::hardware::tv::tuner::V1_0::LnbTone;
+using android::hardware::tv::tuner::V1_0::LnbVoltage;
+using android::hardware::tv::tuner::V1_0::Result;
+
+using ::testing::AssertionResult;
+
+using namespace std;
+
+class LnbCallback : public ILnbCallback {
+  public:
+    virtual Return<void> onEvent(LnbEventType lnbEventType) override;
+    virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override;
+
+  private:
+    bool mEventReceived = false;
+    android::Mutex mMsgLock;
+    android::Condition mMsgCondition;
+};
+
+class LnbTests {
+  public:
+    void setService(sp<ITuner> tuner) { mService = tuner; }
+
+    AssertionResult getLnbIds(vector<uint32_t>& ids);
+    AssertionResult openLnbById(uint32_t lnbId);
+    AssertionResult openLnbByName(string lnbName);
+    AssertionResult setLnbCallback();
+    AssertionResult setVoltage(LnbVoltage voltage);
+    AssertionResult setTone(LnbTone tone);
+    AssertionResult setSatellitePosition(LnbPosition position);
+    AssertionResult sendDiseqcMessage(vector<uint8_t> diseqcMsg);
+    AssertionResult closeLnb();
+
+  protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+    sp<ITuner> mService;
+    sp<ILnb> mLnb;
+    sp<LnbCallback> mLnbCallback;
+    hidl_vec<uint32_t> mLnbIds;
+};
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 820c58c..4f6c19e 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -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,1470 +14,572 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "Tuner_hidl_hal_test"
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <android-base/logging.h>
-#include <android/hardware/tv/tuner/1.0/IDemux.h>
-#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
-#include <android/hardware/tv/tuner/1.0/IDvr.h>
-#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
-#include <android/hardware/tv/tuner/1.0/IFilter.h>
-#include <android/hardware/tv/tuner/1.0/IFilterCallback.h>
-#include <android/hardware/tv/tuner/1.0/IFrontend.h>
-#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
-#include <android/hardware/tv/tuner/1.0/ITuner.h>
-#include <android/hardware/tv/tuner/1.0/types.h>
-#include <binder/MemoryDealer.h>
-#include <fmq/MessageQueue.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/HidlTransportSupport.h>
-#include <hidl/ServiceManagement.h>
-#include <hidl/Status.h>
-#include <hidlmemory/FrameworkUtils.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-#include <fstream>
-#include <iostream>
-#include <map>
-
-#define WAIT_TIMEOUT 3000000000
-#define WAIT_TIMEOUT_data_ready 3000000000 * 4
-
-using android::Condition;
-using android::IMemory;
-using android::IMemoryHeap;
-using android::MemoryDealer;
-using android::Mutex;
-using android::sp;
-using android::hardware::EventFlag;
-using android::hardware::fromHeap;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
-using android::hardware::HidlMemory;
-using android::hardware::kSynchronizedReadWrite;
-using android::hardware::MessageQueue;
-using android::hardware::MQDescriptorSync;
-using android::hardware::Return;
-using android::hardware::Void;
-using android::hardware::tv::tuner::V1_0::DataFormat;
-using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
-using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
-using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
-using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
-using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
-using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
-using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
-using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
-using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
-using android::hardware::tv::tuner::V1_0::DemuxFilterType;
-using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
-using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
-using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
-using android::hardware::tv::tuner::V1_0::DvrSettings;
-using android::hardware::tv::tuner::V1_0::DvrType;
-using android::hardware::tv::tuner::V1_0::FrontendAtscModulation;
-using android::hardware::tv::tuner::V1_0::FrontendAtscSettings;
-using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
-using android::hardware::tv::tuner::V1_0::FrontendEventType;
-using android::hardware::tv::tuner::V1_0::FrontendId;
-using android::hardware::tv::tuner::V1_0::FrontendInnerFec;
-using android::hardware::tv::tuner::V1_0::FrontendScanMessage;
-using android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
-using android::hardware::tv::tuner::V1_0::FrontendSettings;
-using android::hardware::tv::tuner::V1_0::IDemux;
-using android::hardware::tv::tuner::V1_0::IDescrambler;
-using android::hardware::tv::tuner::V1_0::IDvr;
-using android::hardware::tv::tuner::V1_0::IDvrCallback;
-using android::hardware::tv::tuner::V1_0::IFilter;
-using android::hardware::tv::tuner::V1_0::IFilterCallback;
-using android::hardware::tv::tuner::V1_0::IFrontend;
-using android::hardware::tv::tuner::V1_0::IFrontendCallback;
-using android::hardware::tv::tuner::V1_0::ITuner;
-using android::hardware::tv::tuner::V1_0::PlaybackSettings;
-using android::hardware::tv::tuner::V1_0::PlaybackStatus;
-using android::hardware::tv::tuner::V1_0::RecordSettings;
-using android::hardware::tv::tuner::V1_0::RecordStatus;
-using android::hardware::tv::tuner::V1_0::Result;
+#include "VtsHalTvTunerV1_0TargetTest.h"
 
 namespace {
 
-using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-using MQDesc = MQDescriptorSync<uint8_t>;
-
-const std::vector<uint8_t> goldenDataOutputBuffer{
-        0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
-        0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
-        0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
-        0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
-        0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
-        0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
-        0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
-        0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
-        0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
-        0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
-        0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
-        0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
-        0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
-        0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
-        0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
-        0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
-        0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
-        0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
-        0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
-        0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
-        0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
-        0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
-        0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
-        0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
-        0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
-        0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
-        0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
-        0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
-        0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
-        0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
-        0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
-        0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
-        0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
-        0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
-        0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
-        0x73, 0x63, 0x65, 0x6e, 0x65,
-};
-
-// const uint16_t FMQ_SIZE_4K = 0x1000;
-const uint32_t FMQ_SIZE_1M = 0x100000;
-const uint32_t FMQ_SIZE_16M = 0x1000000;
-
-struct FilterConf {
-    DemuxFilterType type;
-    DemuxFilterSettings setting;
-};
-
-enum FilterEventType : uint8_t {
-    UNDEFINED,
-    SECTION,
-    MEDIA,
-    PES,
-    RECORD,
-    MMTPRECORD,
-    DOWNLOAD,
-    TEMI,
-};
-
-struct PlaybackConf {
-    string inputDataFile;
-    PlaybackSettings setting;
-};
-
-class FrontendCallback : public IFrontendCallback {
-  public:
-    virtual Return<void> onEvent(FrontendEventType frontendEventType) override {
-        android::Mutex::Autolock autoLock(mMsgLock);
-        mEventReceived = true;
-        mEventType = frontendEventType;
-        mMsgCondition.signal();
-        return Void();
-    }
-
-    virtual Return<void> onScanMessage(FrontendScanMessageType /* type */,
-                                       const FrontendScanMessage& /* message */) override {
-        android::Mutex::Autolock autoLock(mMsgLock);
-        mScanMessageReceived = true;
-        mMsgCondition.signal();
-        return Void();
-    };
-
-    void testOnEvent(sp<IFrontend>& frontend, FrontendSettings settings);
-    void testOnDiseqcMessage(sp<IFrontend>& frontend, FrontendSettings settings);
-
-  private:
-    bool mEventReceived = false;
-    bool mDiseqcMessageReceived = false;
-    bool mScanMessageReceived = false;
-    FrontendEventType mEventType;
-    hidl_vec<uint8_t> mEventMessage;
-    android::Mutex mMsgLock;
-    android::Condition mMsgCondition;
-};
-
-void FrontendCallback::testOnEvent(sp<IFrontend>& frontend, FrontendSettings settings) {
-    Result result = frontend->tune(settings);
-
-    EXPECT_TRUE(result == Result::SUCCESS);
-
-    android::Mutex::Autolock autoLock(mMsgLock);
-    while (!mEventReceived) {
-        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
-            EXPECT_TRUE(false) << "event not received within timeout";
-            return;
-        }
-    }
+AssertionResult TunerBroadcastHidlTest::filterDataOutputTest(vector<string> /*goldenOutputFiles*/) {
+    return filterDataOutputTestBase(mFilterTests);
 }
 
-void FrontendCallback::testOnDiseqcMessage(sp<IFrontend>& frontend, FrontendSettings settings) {
-    Result result = frontend->tune(settings);
-
-    EXPECT_TRUE(result == Result::SUCCESS);
-
-    android::Mutex::Autolock autoLock(mMsgLock);
-    while (!mDiseqcMessageReceived) {
-        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
-            EXPECT_TRUE(false) << "diseqc message not received within timeout";
-            return;
-        }
-    }
+AssertionResult TunerPlaybackHidlTest::filterDataOutputTest(vector<string> /*goldenOutputFiles*/) {
+    return filterDataOutputTestBase(mFilterTests);
 }
 
-class FilterCallback : public IFilterCallback {
-  public:
-    virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent) override {
-        android::Mutex::Autolock autoLock(mMsgLock);
-        // Temprarily we treat the first coming back filter data on the matching pid a success
-        // once all of the MQ are cleared, means we got all the expected output
-        mFilterIdToEvent = filterEvent;
-        readFilterEventData();
-        mPidFilterOutputCount++;
-        // mFilterIdToMQ.erase(filterEvent.filterId);
-
-        // startFilterEventThread(filterEvent);
-        mMsgCondition.signal();
-        return Void();
-    }
-
-    virtual Return<void> onFilterStatus(const DemuxFilterStatus /*status*/) override {
-        return Void();
-    }
-
-    void setFilterId(uint32_t filterId) { mFilterId = filterId; }
-    void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
-
-    void testFilterDataOutput();
-
-    void startFilterEventThread(DemuxFilterEvent event);
-    static void* __threadLoopFilter(void* threadArgs);
-    void filterThreadLoop(DemuxFilterEvent& event);
-
-    void updateFilterMQ(MQDesc& filterMQDescriptor);
-    void updateGoldenOutputMap(string goldenOutputFile);
-    bool readFilterEventData();
-
-  private:
-    struct FilterThreadArgs {
-        FilterCallback* user;
-        DemuxFilterEvent event;
-    };
-    uint16_t mDataLength = 0;
-    std::vector<uint8_t> mDataOutputBuffer;
-
-    string mFilterIdToGoldenOutput;
-
-    uint32_t mFilterId;
-    FilterEventType mFilterEventType;
-    std::unique_ptr<FilterMQ> mFilterIdToMQ;
-    EventFlag* mFilterIdToMQEventFlag;
-    DemuxFilterEvent mFilterIdToEvent;
-
-    android::Mutex mMsgLock;
-    android::Mutex mFilterOutputLock;
-    android::Condition mMsgCondition;
-    android::Condition mFilterOutputCondition;
-
-    pthread_t mFilterThread;
-
-    int mPidFilterOutputCount = 0;
-};
-
-void FilterCallback::startFilterEventThread(DemuxFilterEvent event) {
-    struct FilterThreadArgs* threadArgs =
-            (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs));
-    threadArgs->user = this;
-    threadArgs->event = event;
-
-    pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs);
-    pthread_setname_np(mFilterThread, "test_playback_input_loop");
-}
-
-void FilterCallback::testFilterDataOutput() {
-    android::Mutex::Autolock autoLock(mMsgLock);
-    while (mPidFilterOutputCount < 1) {
-        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
-            EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
-            return;
-        }
-    }
-    mPidFilterOutputCount = 0;
-    ALOGW("[vts] pass and stop");
-}
-
-void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) {
-    mFilterIdToMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
-    EXPECT_TRUE(mFilterIdToMQ);
-    EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ->getEventFlagWord(),
-                                           &mFilterIdToMQEventFlag) == android::OK);
-}
-
-void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) {
-    mFilterIdToGoldenOutput = goldenOutputFile;
-}
-
-void* FilterCallback::__threadLoopFilter(void* threadArgs) {
-    FilterCallback* const self =
-            static_cast<FilterCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
-    self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event);
-    return 0;
-}
-
-void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
-    android::Mutex::Autolock autoLock(mFilterOutputLock);
-    // Read from mFilterIdToMQ[event.filterId] per event and filter type
-
-    // Assemble to filterOutput[filterId]
-
-    // check if filterOutput[filterId] matches goldenOutput[filterId]
-
-    // If match, remove filterId entry from MQ map
-
-    // end thread
-}
-
-bool FilterCallback::readFilterEventData() {
-    bool result = false;
-    DemuxFilterEvent filterEvent = mFilterIdToEvent;
-    ALOGW("[vts] reading from filter FMQ %d", mFilterId);
-    // todo separate filter handlers
-    for (int i = 0; i < filterEvent.events.size(); i++) {
-        switch (mFilterEventType) {
-            case FilterEventType::SECTION:
-                mDataLength = filterEvent.events[i].section().dataLength;
-                break;
-            case FilterEventType::PES:
-                mDataLength = filterEvent.events[i].pes().dataLength;
-                break;
-            case FilterEventType::MEDIA:
-                break;
-            case FilterEventType::RECORD:
-                break;
-            case FilterEventType::MMTPRECORD:
-                break;
-            case FilterEventType::DOWNLOAD:
-                break;
-            default:
-                break;
-        }
-        // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not
-        // match";
-
-        mDataOutputBuffer.resize(mDataLength);
-        result = mFilterIdToMQ->read(mDataOutputBuffer.data(), mDataLength);
-        EXPECT_TRUE(result) << "can't read from Filter MQ";
-
-        /*for (int i = 0; i < mDataLength; i++) {
-            EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
-        }*/
-    }
-    mFilterIdToMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
-    return result;
-}
-
-class DvrCallback : public IDvrCallback {
-  public:
-    virtual Return<void> onRecordStatus(DemuxFilterStatus status) override {
-        ALOGW("[vts] record status %hhu", status);
-        switch (status) {
-            case DemuxFilterStatus::DATA_READY:
-                break;
-            case DemuxFilterStatus::LOW_WATER:
-                break;
-            case DemuxFilterStatus::HIGH_WATER:
-            case DemuxFilterStatus::OVERFLOW:
-                ALOGW("[vts] record overflow. Flushing");
-                break;
-        }
-        return Void();
-    }
-
-    virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
-        // android::Mutex::Autolock autoLock(mMsgLock);
-        ALOGW("[vts] playback status %d", status);
-        switch (status) {
-            case PlaybackStatus::SPACE_EMPTY:
-            case PlaybackStatus::SPACE_ALMOST_EMPTY:
-                ALOGW("[vts] keep playback inputing %d", status);
-                mKeepWritingPlaybackFMQ = true;
-                break;
-            case PlaybackStatus::SPACE_ALMOST_FULL:
-            case PlaybackStatus::SPACE_FULL:
-                ALOGW("[vts] stop playback inputing %d", status);
-                mKeepWritingPlaybackFMQ = false;
-                break;
-        }
-        return Void();
-    }
-
-    void testFilterDataOutput();
-    void stopPlaybackThread();
-    void testRecordOutput();
-    void stopRecordThread();
-
-    void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor);
-    void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor);
-    static void* __threadLoopPlayback(void* threadArgs);
-    static void* __threadLoopRecord(void* threadArgs);
-    void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ);
-    void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ);
-
-    bool readRecordFMQ();
-
-  private:
-    struct PlaybackThreadArgs {
-        DvrCallback* user;
-        PlaybackConf* playbackConf;
-        bool* keepWritingPlaybackFMQ;
-    };
-    struct RecordThreadArgs {
-        DvrCallback* user;
-        RecordSettings* recordSetting;
-        bool* keepReadingRecordFMQ;
-    };
-    uint16_t mDataLength = 0;
-    std::vector<uint8_t> mDataOutputBuffer;
-
-    std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
-    std::unique_ptr<FilterMQ> mPlaybackMQ;
-    std::unique_ptr<FilterMQ> mRecordMQ;
-    std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
-    std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
-
-    android::Mutex mMsgLock;
-    android::Mutex mPlaybackThreadLock;
-    android::Mutex mRecordThreadLock;
-    android::Condition mMsgCondition;
-
-    bool mKeepWritingPlaybackFMQ = true;
-    bool mKeepReadingRecordFMQ = true;
-    bool mPlaybackThreadRunning;
-    bool mRecordThreadRunning;
-    pthread_t mPlaybackThread;
-    pthread_t mRecordThread;
-
-    int mPidFilterOutputCount = 0;
-};
-
-void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf,
-                                           MQDesc& playbackMQDescriptor) {
-    mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */);
-    EXPECT_TRUE(mPlaybackMQ);
-    struct PlaybackThreadArgs* threadArgs =
-            (struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs));
-    threadArgs->user = this;
-    threadArgs->playbackConf = &playbackConf;
-    threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ;
-
-    pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs);
-    pthread_setname_np(mPlaybackThread, "test_playback_input_loop");
-}
-
-void DvrCallback::stopPlaybackThread() {
-    mPlaybackThreadRunning = false;
-    mKeepWritingPlaybackFMQ = false;
-
-    android::Mutex::Autolock autoLock(mPlaybackThreadLock);
-}
-
-void* DvrCallback::__threadLoopPlayback(void* threadArgs) {
-    DvrCallback* const self =
-            static_cast<DvrCallback*>(((struct PlaybackThreadArgs*)threadArgs)->user);
-    self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf,
-                             ((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ);
-    return 0;
-}
-
-void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) {
-    android::Mutex::Autolock autoLock(mPlaybackThreadLock);
-    mPlaybackThreadRunning = true;
-
-    // Create the EventFlag that is used to signal the HAL impl that data have been
-    // written into the Playback FMQ
-    EventFlag* playbackMQEventFlag;
-    EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) ==
-                android::OK);
-
-    // open the stream and get its length
-    std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary);
-    int writeSize = playbackConf->setting.packetSize * 6;
-    char* buffer = new char[writeSize];
-    ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str());
-    if (!inputData.is_open()) {
-        mPlaybackThreadRunning = false;
-        ALOGW("[vts] Error %s", strerror(errno));
-    }
-
-    while (mPlaybackThreadRunning) {
-        // move the stream pointer for packet size * 6 every read until the end
-        while (*keepWritingPlaybackFMQ) {
-            inputData.read(buffer, writeSize);
-            if (!inputData) {
-                int leftSize = inputData.gcount();
-                if (leftSize == 0) {
-                    mPlaybackThreadRunning = false;
-                    break;
-                }
-                inputData.clear();
-                inputData.read(buffer, leftSize);
-                // Write the left over of the input data and quit the thread
-                if (leftSize > 0) {
-                    EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize));
-                    playbackMQEventFlag->wake(
-                            static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
-                }
-                mPlaybackThreadRunning = false;
-                break;
-            }
-            // Write input FMQ and notify the Tuner Implementation
-            EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize));
-            playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
-            inputData.seekg(writeSize, inputData.cur);
-            sleep(1);
-        }
-    }
-
-    ALOGW("[vts] Playback thread end.");
-
-    delete[] buffer;
-    inputData.close();
-}
-
-void DvrCallback::testRecordOutput() {
-    android::Mutex::Autolock autoLock(mMsgLock);
-    while (mDataOutputBuffer.empty()) {
-        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
-            EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
-            return;
-        }
-    }
-    stopRecordThread();
-    ALOGW("[vts] record pass and stop");
-}
-
-void DvrCallback::startRecordOutputThread(RecordSettings recordSetting,
-                                          MQDesc& recordMQDescriptor) {
-    mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
-    EXPECT_TRUE(mRecordMQ);
-    struct RecordThreadArgs* threadArgs =
-            (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs));
-    threadArgs->user = this;
-    threadArgs->recordSetting = &recordSetting;
-    threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ;
-
-    pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs);
-    pthread_setname_np(mRecordThread, "test_record_input_loop");
-}
-
-void* DvrCallback::__threadLoopRecord(void* threadArgs) {
-    DvrCallback* const self =
-            static_cast<DvrCallback*>(((struct RecordThreadArgs*)threadArgs)->user);
-    self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSetting,
-                           ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ);
-    return 0;
-}
-
-void DvrCallback::recordThreadLoop(RecordSettings* /*recordSetting*/, bool* keepReadingRecordFMQ) {
-    ALOGD("[vts] DvrCallback record threadLoop start.");
-    android::Mutex::Autolock autoLock(mRecordThreadLock);
-    mRecordThreadRunning = true;
-
-    // Create the EventFlag that is used to signal the HAL impl that data have been
-    // read from the Record FMQ
-    EventFlag* recordMQEventFlag;
-    EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
-                android::OK);
-
-    while (mRecordThreadRunning) {
-        while (*keepReadingRecordFMQ) {
-            uint32_t efState = 0;
-            android::status_t status = recordMQEventFlag->wait(
-                    static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
-                    true /* retry on spurious wake */);
-            if (status != android::OK) {
-                ALOGD("[vts] wait for data ready on the record FMQ");
-                continue;
-            }
-            // Our current implementation filter the data and write it into the filter FMQ
-            // immediately after the DATA_READY from the VTS/framework
-            if (!readRecordFMQ()) {
-                ALOGD("[vts] record data failed to be filtered. Ending thread");
-                mRecordThreadRunning = false;
-                break;
-            }
-        }
-    }
-
-    mRecordThreadRunning = false;
-    ALOGD("[vts] record thread ended.");
-}
-
-bool DvrCallback::readRecordFMQ() {
-    android::Mutex::Autolock autoLock(mMsgLock);
-    bool result = false;
-    mDataOutputBuffer.clear();
-    mDataOutputBuffer.resize(mRecordMQ->availableToRead());
-    result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
-    EXPECT_TRUE(result) << "can't read from Record MQ";
-    mMsgCondition.signal();
-    return result;
-}
-
-void DvrCallback::stopRecordThread() {
-    mKeepReadingRecordFMQ = false;
-    mRecordThreadRunning = false;
-    android::Mutex::Autolock autoLock(mRecordThreadLock);
-}
-
-class TunerHidlTest : public testing::TestWithParam<std::string> {
-  public:
-    virtual void SetUp() override {
-        mService = ITuner::getService(GetParam());
-        ASSERT_NE(mService, nullptr);
-    }
-
-    sp<ITuner> mService;
-
-  protected:
-    static void description(const std::string& description) {
-        RecordProperty("description", description);
-    }
-
-    sp<IFrontend> mFrontend;
-    sp<FrontendCallback> mFrontendCallback;
-    sp<IDescrambler> mDescrambler;
-    sp<IDemux> mDemux;
-    sp<IDvr> mDvr;
-    sp<IFilter> mFilter;
-    std::map<uint32_t, sp<IFilter>> mFilters;
-    std::map<uint32_t, sp<FilterCallback>> mFilterCallbacks;
-    sp<FilterCallback> mFilterCallback;
-    sp<DvrCallback> mDvrCallback;
-    MQDesc mFilterMQDescriptor;
-    MQDesc mPlaybackMQDescriptor;
-    MQDesc mRecordMQDescriptor;
-    vector<uint32_t> mUsedFilterIds;
-
-    uint32_t mDemuxId;
-    uint32_t mFilterId;
-
-    pthread_t mPlaybackshread;
-    bool mPlaybackThreadRunning;
-
-    ::testing::AssertionResult createFrontend(int32_t frontendId);
-    ::testing::AssertionResult tuneFrontend(int32_t frontendId);
-    ::testing::AssertionResult stopTuneFrontend(int32_t frontendId);
-    ::testing::AssertionResult closeFrontend(int32_t frontendId);
-    ::testing::AssertionResult createDemux();
-    ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId,
-                                                       FrontendSettings settings);
-    ::testing::AssertionResult getPlaybackMQDescriptor();
-    ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting);
-    ::testing::AssertionResult getRecordMQDescriptor();
-    ::testing::AssertionResult addRecordToDemux(RecordSettings setting);
-    ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting);
-    ::testing::AssertionResult getFilterMQDescriptor();
-    ::testing::AssertionResult closeDemux();
-    ::testing::AssertionResult createDescrambler();
-    ::testing::AssertionResult closeDescrambler();
-
-    ::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
-                                                    PlaybackConf playbackConf,
-                                                    vector<string> goldenOutputFiles);
-    ::testing::AssertionResult recordDataFlowTest(vector<FilterConf> filterConf,
-                                                  RecordSettings recordSetting,
-                                                  vector<string> goldenOutputFiles);
-    ::testing::AssertionResult broadcastDataFlowTest(vector<FilterConf> filterConf,
-                                                     vector<string> goldenOutputFiles);
-};
-
-::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) {
-    Result status;
-
-    mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) {
-        mFrontend = frontend;
-        status = result;
-    });
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-
-    mFrontendCallback = new FrontendCallback();
-    auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
-
-    return ::testing::AssertionResult(callbackStatus.isOk());
-}
-
-::testing::AssertionResult TunerHidlTest::tuneFrontend(int32_t frontendId) {
-    if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Frontend Settings for testing
-    FrontendSettings frontendSettings;
-    FrontendAtscSettings frontendAtscSettings{
-            .frequency = 0,
-            .modulation = FrontendAtscModulation::UNDEFINED,
-    };
-    frontendSettings.atsc(frontendAtscSettings);
-    mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
-
-    FrontendDvbtSettings frontendDvbtSettings{
-            .frequency = 0,
-    };
-    frontendSettings.dvbt(frontendDvbtSettings);
-    mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
-
-    return ::testing::AssertionResult(true);
-}
-
-::testing::AssertionResult TunerHidlTest::stopTuneFrontend(int32_t frontendId) {
-    Result status;
-    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    status = mFrontend->stopTune();
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::closeFrontend(int32_t frontendId) {
-    Result status;
-    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    status = mFrontend->close();
-    mFrontend = nullptr;
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::createDemux() {
-    Result status;
-
-    mService->openDemux([&](Result result, uint32_t demuxId, const sp<IDemux>& demux) {
-        mDemux = demux;
-        mDemuxId = demuxId;
-        status = result;
-    });
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId,
-                                                                  FrontendSettings settings) {
-    Result status;
-
-    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    mFrontendCallback->testOnEvent(mFrontend, settings);
-
-    status = mDemux->setFrontendDataSource(frontendId);
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::closeDemux() {
-    Result status;
-    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    status = mDemux->close();
-    mDemux = nullptr;
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::createDescrambler() {
-    Result status;
-
-    mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
-        mDescrambler = descrambler;
-        status = result;
-    });
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-
-    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    status = mDescrambler->setDemuxSource(mDemuxId);
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Test if demux source can be set more than once.
-    status = mDescrambler->setDemuxSource(mDemuxId);
-    return ::testing::AssertionResult(status == Result::INVALID_STATE);
-}
-
-::testing::AssertionResult TunerHidlTest::closeDescrambler() {
-    Result status;
-    if (!mDescrambler && createDescrambler() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    status = mDescrambler->close();
-    mDescrambler = nullptr;
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::addPlaybackToDemux(PlaybackSettings setting) {
-    Result status;
-
-    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Create dvr callback
-    mDvrCallback = new DvrCallback();
-
-    // Add playback input to the local demux
-    mDemux->openDvr(DvrType::PLAYBACK, FMQ_SIZE_1M, mDvrCallback,
-                    [&](Result result, const sp<IDvr>& dvr) {
-                        mDvr = dvr;
-                        status = result;
-                    });
-
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-
-    DvrSettings dvrSetting;
-    dvrSetting.playback(setting);
-    status = mDvr->configure(dvrSetting);
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::getPlaybackMQDescriptor() {
-    Result status;
-
-    if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) {
-        return ::testing::AssertionFailure();
-    }
-
-    mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
-        mPlaybackMQDescriptor = dvrMQDesc;
-        status = result;
-    });
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::addRecordToDemux(RecordSettings setting) {
-    Result status;
-
-    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Create dvr callback
-    mDvrCallback = new DvrCallback();
-
-    // Add playback input to the local demux
-    mDemux->openDvr(DvrType::RECORD, FMQ_SIZE_1M, mDvrCallback,
-                    [&](Result result, const sp<IDvr>& dvr) {
-                        mDvr = dvr;
-                        status = result;
-                    });
-
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-
-    DvrSettings dvrSetting;
-    dvrSetting.record(setting);
-    status = mDvr->configure(dvrSetting);
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::getRecordMQDescriptor() {
-    Result status;
-
-    if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) {
-        return ::testing::AssertionFailure();
-    }
-
-    mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
-        mRecordMQDescriptor = dvrMQDesc;
-        status = result;
-    });
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type,
-                                                           DemuxFilterSettings setting) {
-    Result status;
-
-    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Create demux callback
-    mFilterCallback = new FilterCallback();
-
-    // Add filter to the local demux
-    mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback,
-                       [&](Result result, const sp<IFilter>& filter) {
-                           mFilter = filter;
-                           status = result;
-                       });
-
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-
-    mFilter->getId([&](Result result, uint32_t filterId) {
-        mFilterId = filterId;
-        status = result;
-    });
-
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-
-    mFilterCallback->setFilterId(mFilterId);
-
-    FilterEventType eventType = FilterEventType::UNDEFINED;
-    switch (type.mainType) {
-        case DemuxFilterMainType::TS:
-            switch (type.subType.tsFilterType()) {
-                case DemuxTsFilterType::UNDEFINED:
-                    break;
-                case DemuxTsFilterType::SECTION:
-                    eventType = FilterEventType::SECTION;
-                    break;
-                case DemuxTsFilterType::PES:
-                    eventType = FilterEventType::PES;
-                    break;
-                case DemuxTsFilterType::TS:
-                    break;
-                case DemuxTsFilterType::AUDIO:
-                case DemuxTsFilterType::VIDEO:
-                    eventType = FilterEventType::MEDIA;
-                    break;
-                case DemuxTsFilterType::PCR:
-                    break;
-                case DemuxTsFilterType::RECORD:
-                    eventType = FilterEventType::RECORD;
-                    break;
-                case DemuxTsFilterType::TEMI:
-                    eventType = FilterEventType::TEMI;
-                    break;
-            }
-            break;
-        case DemuxFilterMainType::MMTP:
-            /*mmtpSettings*/
-            break;
-        case DemuxFilterMainType::IP:
-            /*ipSettings*/
-            break;
-        case DemuxFilterMainType::TLV:
-            /*tlvSettings*/
-            break;
-        case DemuxFilterMainType::ALP:
-            /*alpSettings*/
-            break;
-        default:
-            break;
-    }
-    mFilterCallback->setFilterEventType(eventType);
-
-    // Configure the filter
-    status = mFilter->configure(setting);
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor() {
-    Result status;
-
-    if (!mDemux || !mFilter) {
-        return ::testing::AssertionFailure();
-    }
-
-    mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) {
-        mFilterMQDescriptor = filterMQDesc;
-        status = result;
-    });
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(
-        vector<FilterConf> filterConf, PlaybackConf playbackConf,
+AssertionResult TunerDescramblerHidlTest::filterDataOutputTest(
         vector<string> /*goldenOutputFiles*/) {
-    Result status;
-    int filterIdsSize;
-    // Filter Configuration Module
-    for (int i = 0; i < filterConf.size(); i++) {
-        if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
-                    ::testing::AssertionFailure() ||
-            // TODO use a map to save the FMQs/EvenFlags and pass to callback
-            getFilterMQDescriptor() == ::testing::AssertionFailure()) {
-            return ::testing::AssertionFailure();
-        }
-        filterIdsSize = mUsedFilterIds.size();
-        mUsedFilterIds.resize(filterIdsSize + 1);
-        mUsedFilterIds[filterIdsSize] = mFilterId;
-        mFilters[mFilterId] = mFilter;
-        mFilterCallbacks[mFilterId] = mFilterCallback;
-        mFilterCallback->updateFilterMQ(mFilterMQDescriptor);
-        // mDemuxCallback->updateGoldenOutputMap(goldenOutputFiles[i]);
-        status = mFilter->start();
-        if (status != Result::SUCCESS) {
-            return ::testing::AssertionFailure();
-        }
-    }
-
-    // Playback Input Module
-    PlaybackSettings playbackSetting = playbackConf.setting;
-    if (addPlaybackToDemux(playbackSetting) == ::testing::AssertionFailure() ||
-        getPlaybackMQDescriptor() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-    for (int i = 0; i <= filterIdsSize; i++) {
-        if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
-            return ::testing::AssertionFailure();
-        }
-    }
-    mDvrCallback->startPlaybackInputThread(playbackConf, mPlaybackMQDescriptor);
-    status = mDvr->start();
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Data Verify Module
-    std::map<uint32_t, sp<FilterCallback>>::iterator it;
-    for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) {
-        it->second->testFilterDataOutput();
-    }
-    mDvrCallback->stopPlaybackThread();
-
-    // Clean Up Module
-    for (int i = 0; i <= filterIdsSize; i++) {
-        if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
-            return ::testing::AssertionFailure();
-        }
-    }
-    if (mDvr->stop() != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-    mUsedFilterIds.clear();
-    mFilterCallbacks.clear();
-    mFilters.clear();
-    return closeDemux();
+    return filterDataOutputTestBase(mFilterTests);
 }
 
-::testing::AssertionResult TunerHidlTest::broadcastDataFlowTest(
-        vector<FilterConf> filterConf, vector<string> /*goldenOutputFiles*/) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
+void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf,
+                                                        FrontendConfig frontendConf) {
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint32_t filterId;
 
-    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
-        status = result;
-        feIds = frontendIds;
-    });
-
-    if (feIds.size() == 0) {
-        ALOGW("[   WARN   ] Frontend isn't available");
-        return ::testing::AssertionFailure();
-    }
-
-    FrontendDvbtSettings dvbt{
-            .frequency = 1000,
-    };
-    FrontendSettings settings;
-    settings.dvbt(dvbt);
-
-    if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) {
-        return ::testing::AssertionFailure();
-    }
-
-    int filterIdsSize;
-    // Filter Configuration Module
-    for (int i = 0; i < filterConf.size(); i++) {
-        if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
-                    ::testing::AssertionFailure() ||
-            // TODO use a map to save the FMQs/EvenFlags and pass to callback
-            getFilterMQDescriptor() == ::testing::AssertionFailure()) {
-            return ::testing::AssertionFailure();
-        }
-        filterIdsSize = mUsedFilterIds.size();
-        mUsedFilterIds.resize(filterIdsSize + 1);
-        mUsedFilterIds[filterIdsSize] = mFilterId;
-        mFilters[mFilterId] = mFilter;
-        mFilterCallbacks[mFilterId] = mFilterCallback;
-        mFilterCallback->updateFilterMQ(mFilterMQDescriptor);
-        status = mFilter->start();
-        if (status != Result::SUCCESS) {
-            return ::testing::AssertionFailure();
-        }
-    }
-
-    // Data Verify Module
-    std::map<uint32_t, sp<FilterCallback>>::iterator it;
-    for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) {
-        it->second->testFilterDataOutput();
-    }
-
-    // Clean Up Module
-    for (int i = 0; i <= filterIdsSize; i++) {
-        if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
-            return ::testing::AssertionFailure();
-        }
-    }
-    if (mFrontend->stopTune() != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-    mUsedFilterIds.clear();
-    mFilterCallbacks.clear();
-    mFilters.clear();
-    return closeDemux();
+    mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFilterTests.setDemux(demux);
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
 }
 
-::testing::AssertionResult TunerHidlTest::recordDataFlowTest(vector<FilterConf> filterConf,
-                                                             RecordSettings recordSetting,
-                                                             vector<string> /*goldenOutputFiles*/) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
-
-    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
-        status = result;
-        feIds = frontendIds;
-    });
-
-    if (feIds.size() == 0) {
-        ALOGW("[   WARN   ] Frontend isn't available");
-        return ::testing::AssertionFailure();
-    }
-
-    FrontendDvbtSettings dvbt{
-            .frequency = 1000,
-    };
-    FrontendSettings settings;
-    settings.dvbt(dvbt);
-
-    int filterIdsSize;
-    // Filter Configuration Module
-    for (int i = 0; i < filterConf.size(); i++) {
-        if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
-                    ::testing::AssertionFailure() ||
-            // TODO use a map to save the FMQs/EvenFlags and pass to callback
-            getFilterMQDescriptor() == ::testing::AssertionFailure()) {
-            return ::testing::AssertionFailure();
-        }
-        filterIdsSize = mUsedFilterIds.size();
-        mUsedFilterIds.resize(filterIdsSize + 1);
-        mUsedFilterIds[filterIdsSize] = mFilterId;
-        mFilters[mFilterId] = mFilter;
-    }
-
-    // Record Config Module
-    if (addRecordToDemux(recordSetting) == ::testing::AssertionFailure() ||
-        getRecordMQDescriptor() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-    for (int i = 0; i <= filterIdsSize; i++) {
-        if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
-            return ::testing::AssertionFailure();
-        }
-    }
-
-    mDvrCallback->startRecordOutputThread(recordSetting, mRecordMQDescriptor);
-    status = mDvr->start();
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-
-    if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Data Verify Module
-    mDvrCallback->testRecordOutput();
-
-    // Clean Up Module
-    for (int i = 0; i <= filterIdsSize; i++) {
-        if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
-            return ::testing::AssertionFailure();
-        }
-    }
-    if (mFrontend->stopTune() != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
-    mUsedFilterIds.clear();
-    mFilterCallbacks.clear();
-    mFilters.clear();
-    return closeDemux();
-}
-
-/*
- * API STATUS TESTS
- */
-TEST_P(TunerHidlTest, CreateFrontend) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
-
-    description("Create Frontends");
-    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
-        status = result;
-        feIds = frontendIds;
-    });
-
-    if (feIds.size() == 0) {
-        ALOGW("[   WARN   ] Frontend isn't available");
+void TunerFilterHidlTest::testTimeFilter(TimeFilterConfig filterConf) {
+    if (!filterConf.supportTimeFilter) {
         return;
     }
+    uint32_t demuxId;
+    sp<IDemux> demux;
 
-    for (size_t i = 0; i < feIds.size(); i++) {
-        ASSERT_TRUE(createFrontend(feIds[i]));
-    }
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    mFilterTests.setDemux(demux);
+    ASSERT_TRUE(mFilterTests.openTimeFilterInDemux());
+    ASSERT_TRUE(mFilterTests.setTimeStamp(filterConf.timeStamp));
+    ASSERT_TRUE(mFilterTests.getTimeStamp());
+    ASSERT_TRUE(mFilterTests.clearTimeStamp());
+    ASSERT_TRUE(mFilterTests.closeTimeFilter());
+    ASSERT_TRUE(mDemuxTests.closeDemux());
 }
 
-TEST_P(TunerHidlTest, TuneFrontend) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
+void TunerBroadcastHidlTest::broadcastSingleFilterTest(FilterConfig filterConf,
+                                                       FrontendConfig frontendConf) {
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint32_t filterId;
 
-    description("Tune Frontends and check callback onEvent");
-    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
-        status = result;
-        feIds = frontendIds;
-    });
-
-    if (feIds.size() == 0) {
-        ALOGW("[   WARN   ] Frontend isn't available");
+    mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+    if (feId == INVALID_ID) {
+        // TODO broadcast test on Cuttlefish needs licensed ts input,
+        // these tests are runnable on vendor device with real frontend module
+        // or with manual ts installing and use DVBT frontend.
         return;
     }
-
-    for (size_t i = 0; i < feIds.size(); i++) {
-        ASSERT_TRUE(tuneFrontend(feIds[i]));
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    if (mLnbId) {
+        ASSERT_TRUE(mFrontendTests.setLnb(*mLnbId));
     }
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFrontendTests.setDemux(demux);
+    mFilterTests.setDemux(demux);
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    // tune test
+    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+    ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
+    ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
 }
 
-TEST_P(TunerHidlTest, StopTuneFrontend) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
-
-    description("stopTune Frontends");
-    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
-        status = result;
-        feIds = frontendIds;
-    });
-
-    if (feIds.size() == 0) {
-        ALOGW("[   WARN   ] Frontend isn't available");
+void TunerBroadcastHidlTest::broadcastSingleFilterTestWithLnb(FilterConfig filterConf,
+                                                              FrontendConfig frontendConf,
+                                                              LnbConfig lnbConf) {
+    vector<uint32_t> ids;
+    ASSERT_TRUE(mLnbTests.getLnbIds(ids));
+    if (!lnbConf.usingLnb) {
         return;
     }
-
-    for (size_t i = 0; i < feIds.size(); i++) {
-        ASSERT_TRUE(stopTuneFrontend(feIds[i]));
-    }
+    ASSERT_TRUE(ids.size() > 0);
+    ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
+    *mLnbId = ids[0];
+    ASSERT_TRUE(mLnbTests.setLnbCallback());
+    ASSERT_TRUE(mLnbTests.setVoltage(lnbConf.voltage));
+    ASSERT_TRUE(mLnbTests.setTone(lnbConf.tone));
+    ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbConf.position));
+    broadcastSingleFilterTest(filterConf, frontendConf);
+    ASSERT_TRUE(mLnbTests.closeLnb());
+    mLnbId = nullptr;
 }
 
-TEST_P(TunerHidlTest, CloseFrontend) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
+void TunerPlaybackHidlTest::playbackSingleFilterTest(FilterConfig filterConf, DvrConfig dvrConf) {
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint32_t filterId;
 
-    description("Close Frontends");
-    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
-        status = result;
-        feIds = frontendIds;
-    });
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    mFilterTests.setDemux(demux);
+    mDvrTests.setDemux(demux);
+    ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize));
+    ASSERT_TRUE(mDvrTests.configDvrPlayback(dvrConf.settings));
+    ASSERT_TRUE(mDvrTests.getDvrPlaybackMQDescriptor());
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+    mDvrTests.startPlaybackInputThread(dvrConf.playbackInputFile, dvrConf.settings.playback());
+    ASSERT_TRUE(mDvrTests.startDvrPlayback());
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
+    mDvrTests.stopPlaybackThread();
+    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    ASSERT_TRUE(mDvrTests.stopDvrPlayback());
+    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+    mDvrTests.closeDvrPlayback();
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+}
 
-    if (feIds.size() == 0) {
-        ALOGW("[   WARN   ] Frontend isn't available");
+void TunerRecordHidlTest::recordSingleFilterTest(FilterConfig filterConf,
+                                                 FrontendConfig frontendConf, DvrConfig dvrConf) {
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint32_t filterId;
+    sp<IFilter> filter;
+
+    mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    if (mLnbId) {
+        ASSERT_TRUE(mFrontendTests.setLnb(*mLnbId));
+    }
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFilterTests.setDemux(demux);
+    mDvrTests.setDemux(demux);
+    mFrontendTests.setDvrTests(mDvrTests);
+    ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize));
+    ASSERT_TRUE(mDvrTests.configDvrRecord(dvrConf.settings));
+    ASSERT_TRUE(mDvrTests.getDvrRecordMQDescriptor());
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+    filter = mFilterTests.getFilterById(filterId);
+    ASSERT_TRUE(filter != nullptr);
+    mDvrTests.startRecordOutputThread(dvrConf.settings.record());
+    ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter));
+    ASSERT_TRUE(mDvrTests.startDvrRecord());
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+    mDvrTests.testRecordOutput();
+    mDvrTests.stopRecordThread();
+    ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    ASSERT_TRUE(mDvrTests.stopDvrRecord());
+    ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter));
+    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+    mDvrTests.closeDvrRecord();
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
+void TunerRecordHidlTest::recordSingleFilterTestWithLnb(FilterConfig filterConf,
+                                                        FrontendConfig frontendConf,
+                                                        DvrConfig dvrConf, LnbConfig lnbConf) {
+    vector<uint32_t> ids;
+    ASSERT_TRUE(mLnbTests.getLnbIds(ids));
+    if (!lnbConf.usingLnb) {
         return;
     }
-
-    for (size_t i = 0; i < feIds.size(); i++) {
-        ASSERT_TRUE(closeFrontend(feIds[i]));
-    }
+    ASSERT_TRUE(ids.size() > 0);
+    ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
+    *mLnbId = ids[0];
+    ASSERT_TRUE(mLnbTests.setLnbCallback());
+    ASSERT_TRUE(mLnbTests.setVoltage(lnbConf.voltage));
+    ASSERT_TRUE(mLnbTests.setTone(lnbConf.tone));
+    ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbConf.position));
+    recordSingleFilterTest(filterConf, frontendConf, dvrConf);
+    ASSERT_TRUE(mLnbTests.closeLnb());
+    mLnbId = nullptr;
 }
 
-TEST_P(TunerHidlTest, CreateDemuxWithFrontend) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
+void TunerRecordHidlTest::attachSingleFilterToRecordDvrTest(FilterConfig filterConf,
+                                                            FrontendConfig frontendConf,
+                                                            DvrConfig dvrConf) {
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint32_t filterId;
+    sp<IFilter> filter;
 
-    description("Create Demux with Frontend");
-    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
-        status = result;
-        feIds = frontendIds;
-    });
+    mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFilterTests.setDemux(demux);
+    mDvrTests.setDemux(demux);
+    ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize));
+    ASSERT_TRUE(mDvrTests.configDvrRecord(dvrConf.settings));
+    ASSERT_TRUE(mDvrTests.getDvrRecordMQDescriptor());
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+    filter = mFilterTests.getFilterById(filterId);
+    ASSERT_TRUE(filter != nullptr);
+    ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter));
+    ASSERT_TRUE(mDvrTests.startDvrRecord());
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    ASSERT_TRUE(mDvrTests.stopDvrRecord());
+    ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter));
+    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+    mDvrTests.closeDvrRecord();
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
 
-    if (feIds.size() == 0) {
-        ALOGW("[   WARN   ] Frontend isn't available");
+void TunerDescramblerHidlTest::scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
+                                                      FrontendConfig frontendConf,
+                                                      DescramblerConfig descConfig) {
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    set<uint32_t> filterIds;
+    uint32_t filterId;
+    set<struct FilterConfig>::iterator config;
+    set<uint32_t>::iterator id;
+
+    mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+    if (feId == INVALID_ID) {
+        // TODO broadcast test on Cuttlefish needs licensed ts input,
+        // these tests are runnable on vendor device with real frontend module
+        // or with manual ts installing and use DVBT frontend.
         return;
     }
-
-    FrontendDvbtSettings dvbt{
-        .frequency = 1000,
-    };
-    FrontendSettings settings;
-    settings.dvbt(dvbt);
-
-    for (size_t i = 0; i < feIds.size(); i++) {
-        ASSERT_TRUE(createDemuxWithFrontend(feIds[i], settings));
-        mFrontend->stopTune();
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFilterTests.setDemux(demux);
+    mFrontendTests.setDemux(demux);
+    for (config = mediaFilterConfs.begin(); config != mediaFilterConfs.end(); config++) {
+        ASSERT_TRUE(mFilterTests.openFilterInDemux((*config).type, (*config).bufferSize));
+        ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+        ASSERT_TRUE(mFilterTests.configFilter((*config).settings, filterId));
+        filterIds.insert(filterId);
     }
+    ASSERT_TRUE(mDescramblerTests.openDescrambler(demuxId));
+    TunerKeyToken token;
+    ASSERT_TRUE(mDescramblerTests.getKeyToken(descConfig.casSystemId, descConfig.provisionStr,
+                                              descConfig.hidlPvtData, token));
+    ASSERT_TRUE(mDescramblerTests.setKeyToken(token));
+    vector<DemuxPid> pids;
+    DemuxPid pid;
+    for (config = mediaFilterConfs.begin(); config != mediaFilterConfs.end(); config++) {
+        ASSERT_TRUE(mDescramblerTests.getDemuxPidFromFilterSettings((*config).type,
+                                                                    (*config).settings, pid));
+        pids.push_back(pid);
+        ASSERT_TRUE(mDescramblerTests.addPid(pid, nullptr));
+    }
+    for (id = filterIds.begin(); id != filterIds.end(); id++) {
+        ASSERT_TRUE(mFilterTests.startFilter(*id));
+    }
+    // tune test
+    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+    ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
+    ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+    for (id = filterIds.begin(); id != filterIds.end(); id++) {
+        ASSERT_TRUE(mFilterTests.stopFilter(*id));
+    }
+    for (auto pid : pids) {
+        ASSERT_TRUE(mDescramblerTests.removePid(pid, nullptr));
+    }
+    ASSERT_TRUE(mDescramblerTests.closeDescrambler());
+    for (id = filterIds.begin(); id != filterIds.end(); id++) {
+        ASSERT_TRUE(mFilterTests.closeFilter(*id));
+    }
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
 }
 
-TEST_P(TunerHidlTest, CreateDemux) {
-    description("Create Demux");
-    ASSERT_TRUE(createDemux());
+TEST_P(TunerFrontendHidlTest, TuneFrontend) {
+    description("Tune one Frontend with specific setting and check Lock event");
+    mFrontendTests.tuneTest(frontendArray[DVBT]);
 }
 
-TEST_P(TunerHidlTest, CloseDemux) {
-    description("Close Demux");
-    ASSERT_TRUE(closeDemux());
+TEST_P(TunerFrontendHidlTest, AutoScanFrontend) {
+    description("Run an auto frontend scan with specific setting and check lock scanMessage");
+    mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_AUTO);
 }
 
-TEST_P(TunerHidlTest, CreateDescrambler) {
-    description("Create Descrambler");
-    ASSERT_TRUE(createDescrambler());
+TEST_P(TunerFrontendHidlTest, BlindScanFrontend) {
+    description("Run an blind frontend scan with specific setting and check lock scanMessage");
+    mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND);
 }
 
-TEST_P(TunerHidlTest, CloseDescrambler) {
-    description("Close Descrambler");
-    ASSERT_TRUE(closeDescrambler());
+TEST_P(TunerLnbHidlTest, OpenLnbByName) {
+    description("Open and configure an Lnb with name then send a diseqc msg to it.");
+    ASSERT_TRUE(mLnbTests.openLnbByName(lnbArray[LNB_EXTERNAL].name));
+    ASSERT_TRUE(mLnbTests.setLnbCallback());
+    ASSERT_TRUE(mLnbTests.setVoltage(lnbArray[LNB_EXTERNAL].voltage));
+    ASSERT_TRUE(mLnbTests.setTone(lnbArray[LNB_EXTERNAL].tone));
+    ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbArray[LNB_EXTERNAL].position));
+    ASSERT_TRUE(mLnbTests.sendDiseqcMessage(diseqcMsgArray[DISEQC_POWER_ON]));
+    ASSERT_TRUE(mLnbTests.closeLnb());
 }
 
-/*
- * DATA FLOW TESTS
- *
- * TODO: re-enable the tests after finalizing the testing stream.
- */
-/*TEST_P(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) {
-    description("Feed ts data from playback and configure pes filter to get output");
-
-    // todo modulize the filter conf parser
-    vector<FilterConf> filterConf;
-    filterConf.resize(1);
-
-    DemuxFilterSettings filterSetting;
-    DemuxTsFilterSettings tsFilterSetting{
-            .tpid = 18,
-    };
-    DemuxFilterSectionSettings sectionFilterSetting;
-    tsFilterSetting.filterSettings.section(sectionFilterSetting);
-    filterSetting.ts(tsFilterSetting);
-
-    DemuxFilterType type{
-            .mainType = DemuxFilterMainType::TS,
-    };
-    type.subType.tsFilterType(DemuxTsFilterType::SECTION);
-    FilterConf sectionFilterConf{
-            .type = type,
-            .setting = filterSetting,
-    };
-    filterConf[0] = sectionFilterConf;
-
-    PlaybackSettings playbackSetting{
-            .statusMask = 0xf,
-            .lowThreshold = 0x1000,
-            .highThreshold = 0x07fff,
-            .dataFormat = DataFormat::TS,
-            .packetSize = 188,
-    };
-
-    PlaybackConf playbackConf{
-            .inputDataFile = "/vendor/etc/test1.ts",
-            .setting = playbackSetting,
-    };
-
-    vector<string> goldenOutputFiles;
-
-    ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles));
+TEST_P(TunerLnbHidlTest, SendDiseqcMessageToLnb) {
+    description("Open and configure an Lnb with specific settings then send a diseqc msg to it.");
+    vector<uint32_t> ids;
+    ASSERT_TRUE(mLnbTests.getLnbIds(ids));
+    if (!lnbArray[LNB0].usingLnb) {
+        return;
+    }
+    ASSERT_TRUE(ids.size() > 0);
+    ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
+    ASSERT_TRUE(mLnbTests.setLnbCallback());
+    ASSERT_TRUE(mLnbTests.setVoltage(lnbArray[LNB0].voltage));
+    ASSERT_TRUE(mLnbTests.setTone(lnbArray[LNB0].tone));
+    ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbArray[LNB0].position));
+    ASSERT_TRUE(mLnbTests.sendDiseqcMessage(diseqcMsgArray[DISEQC_POWER_ON]));
+    ASSERT_TRUE(mLnbTests.closeLnb());
 }
 
-TEST_P(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) {
-    description("Feed ts data from frontend and test with PES filter");
-
-    // todo modulize the filter conf parser
-    vector<FilterConf> filterConf;
-    filterConf.resize(1);
-
-    DemuxFilterSettings filterSetting;
-    DemuxTsFilterSettings tsFilterSetting{
-            .tpid = 119,
-    };
-    DemuxFilterPesDataSettings pesFilterSetting;
-    tsFilterSetting.filterSettings.pesData(pesFilterSetting);
-    filterSetting.ts(tsFilterSetting);
-
-    DemuxFilterType type{
-            .mainType = DemuxFilterMainType::TS,
-    };
-    type.subType.tsFilterType(DemuxTsFilterType::PES);
-    FilterConf pesFilterConf{
-            .type = type,
-            .setting = filterSetting,
-    };
-    filterConf[0] = pesFilterConf;
-
-    vector<string> goldenOutputFiles;
-
-    ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles));
+TEST_P(TunerDemuxHidlTest, openDemux) {
+    description("Open and close a Demux.");
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
 }
 
-TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
+TEST_P(TunerDemuxHidlTest, getAvSyncTime) {
+    description("Get the A/V sync time from a PCR filter.");
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint32_t mediaFilterId;
+    uint32_t pcrFilterId;
+    uint32_t avSyncHwId;
+    sp<IFilter> mediaFilter;
+
+    mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFilterTests.setDemux(demux);
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO1].type,
+                                               filterArray[TS_VIDEO1].bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(mediaFilterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO1].settings, mediaFilterId));
+    mediaFilter = mFilterTests.getFilterById(mediaFilterId);
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_PCR0].type,
+                                               filterArray[TS_PCR0].bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(pcrFilterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_PCR0].settings, pcrFilterId));
+    ASSERT_TRUE(mDemuxTests.getAvSyncId(mediaFilter, avSyncHwId));
+    ASSERT_TRUE(pcrFilterId == avSyncHwId);
+    ASSERT_TRUE(mDemuxTests.getAvSyncTime(pcrFilterId));
+    ASSERT_TRUE(mFilterTests.closeFilter(pcrFilterId));
+    ASSERT_TRUE(mFilterTests.closeFilter(mediaFilterId));
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
+TEST_P(TunerFilterHidlTest, StartFilterInDemux) {
+    description("Open and start a filter in Demux.");
+    // TODO use paramterized tests
+    configSingleFilterInDemuxTest(filterArray[TS_VIDEO0], frontendArray[DVBT]);
+}
+
+TEST_P(TunerFilterHidlTest, SetFilterLinkage) {
+    description("Pick up all the possible linkages from the demux caps and set them up.");
+    DemuxCapabilities caps;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.getDemuxCaps(caps));
+    mFilterTests.setDemux(demux);
+    for (int i = 0; i < caps.linkCaps.size(); i++) {
+        uint32_t bitMask = 1;
+        for (int j = 0; j < FILTER_MAIN_TYPE_BIT_COUNT; j++) {
+            if (caps.linkCaps[i] & (bitMask << j)) {
+                uint32_t sourceFilterId;
+                uint32_t sinkFilterId;
+                ASSERT_TRUE(mFilterTests.openFilterInDemux(filterLinkageTypes[SOURCE][i],
+                                                           FMQ_SIZE_16M));
+                ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(sourceFilterId));
+                ASSERT_TRUE(
+                        mFilterTests.openFilterInDemux(filterLinkageTypes[SINK][j], FMQ_SIZE_16M));
+                ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(sinkFilterId));
+                ASSERT_TRUE(mFilterTests.setFilterDataSource(sourceFilterId, sinkFilterId));
+                ASSERT_TRUE(mFilterTests.setFilterDataSourceToDemux(sinkFilterId));
+                ASSERT_TRUE(mFilterTests.closeFilter(sinkFilterId));
+                ASSERT_TRUE(mFilterTests.closeFilter(sourceFilterId));
+            }
+        }
+    }
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+}
+
+TEST_P(TunerFilterHidlTest, testTimeFilter) {
+    description("Open a timer filter in Demux and set time stamp.");
+    // TODO use paramterized tests
+    testTimeFilter(timeFilterArray[TIMER0]);
+}
+
+TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowVideoFilterTest) {
+    description("Test Video Filter functionality in Broadcast use case.");
+    broadcastSingleFilterTest(filterArray[TS_VIDEO1], frontendArray[DVBT]);
+}
+
+TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowAudioFilterTest) {
+    description("Test Audio Filter functionality in Broadcast use case.");
+    broadcastSingleFilterTest(filterArray[TS_AUDIO0], frontendArray[DVBT]);
+}
+
+TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowSectionFilterTest) {
+    description("Test Section Filter functionality in Broadcast use case.");
+    broadcastSingleFilterTest(filterArray[TS_SECTION0], frontendArray[DVBT]);
+}
+
+TEST_P(TunerBroadcastHidlTest, IonBufferTest) {
+    description("Test the av filter data bufferring.");
+    broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[DVBT]);
+}
+
+TEST_P(TunerBroadcastHidlTest, LnbBroadcastDataFlowVideoFilterTest) {
+    description("Test Video Filter functionality in Broadcast with Lnb use case.");
+    broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[DVBS]);
+}
+
+TEST_P(TunerPlaybackHidlTest, PlaybackDataFlowWithTsSectionFilterTest) {
+    description("Feed ts data from playback and configure Ts section filter to get output");
+    playbackSingleFilterTest(filterArray[TS_SECTION0], dvrArray[DVR_PLAYBACK0]);
+}
+
+TEST_P(TunerRecordHidlTest, AttachFiltersToRecordTest) {
+    description("Attach a single filter to the record dvr test.");
+    // TODO use paramterized tests
+    attachSingleFilterToRecordDvrTest(filterArray[TS_RECORD0], frontendArray[DVBT],
+                                      dvrArray[DVR_RECORD0]);
+}
+
+TEST_P(TunerRecordHidlTest, RecordDataFlowWithTsRecordFilterTest) {
     description("Feed ts data from frontend to recording and test with ts record filter");
+    recordSingleFilterTest(filterArray[TS_RECORD0], frontendArray[DVBT], dvrArray[DVR_RECORD0]);
+}
 
-    // todo modulize the filter conf parser
-    vector<FilterConf> filterConf;
-    filterConf.resize(1);
+TEST_P(TunerRecordHidlTest, LnbRecordDataFlowWithTsRecordFilterTest) {
+    description("Feed ts data from Fe with Lnb to recording and test with ts record filter");
+    recordSingleFilterTest(filterArray[TS_RECORD0], frontendArray[DVBS], dvrArray[DVR_RECORD0]);
+}
 
-    DemuxFilterSettings filterSetting;
-    DemuxTsFilterSettings tsFilterSetting{
-            .tpid = 119,
-    };
-    DemuxFilterRecordSettings recordFilterSetting;
-    tsFilterSetting.filterSettings.record(recordFilterSetting);
-    filterSetting.ts(tsFilterSetting);
+TEST_P(TunerDescramblerHidlTest, CreateDescrambler) {
+    description("Create Descrambler");
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    ASSERT_TRUE(mDescramblerTests.openDescrambler(demuxId));
+    ASSERT_TRUE(mDescramblerTests.closeDescrambler());
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
 
-    DemuxFilterType type{
-            .mainType = DemuxFilterMainType::TS,
-    };
-    type.subType.tsFilterType(DemuxTsFilterType::RECORD);
-    FilterConf recordFilterConf{
-            .type = type,
-            .setting = filterSetting,
-    };
-    filterConf[0] = recordFilterConf;
-
-    RecordSettings recordSetting{
-            .statusMask = 0xf,
-            .lowThreshold = 0x1000,
-            .highThreshold = 0x07fff,
-            .dataFormat = DataFormat::TS,
-            .packetSize = 188,
-    };
-
-    vector<string> goldenOutputFiles;
-
-    ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles));
-}*/
-
-}  // namespace
+TEST_P(TunerDescramblerHidlTest, ScrambledBroadcastDataFlowMediaFiltersTest) {
+    description("Test ts audio filter in scrambled broadcast use case");
+    set<FilterConfig> filterConfs;
+    filterConfs.insert(filterArray[TS_AUDIO0]);
+    filterConfs.insert(filterArray[TS_VIDEO1]);
+    scrambledBroadcastTest(filterConfs, frontendArray[DVBT], descramblerArray[DESC_0]);
+}
 
 INSTANTIATE_TEST_SUITE_P(
-        PerInstance, TunerHidlTest,
+        PerInstance, TunerFrontendHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
         android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerLnbHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerDemuxHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerFilterHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerBroadcastHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerPlaybackHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerRecordHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerDescramblerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFrontendHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerLnbHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerDemuxHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFilterHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerBroadcastHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerPlaybackHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerRecordHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerDescramblerHidlTest);
+}  // namespace
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
new file mode 100644
index 0000000..6804f3c
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
@@ -0,0 +1,273 @@
+/*
+ * 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 "DemuxTests.h"
+#include "DescramblerTests.h"
+#include "FrontendTests.h"
+#include "LnbTests.h"
+
+using android::hardware::tv::tuner::V1_0::DataFormat;
+using android::hardware::tv::tuner::V1_0::IDescrambler;
+
+static AssertionResult success() {
+    return ::testing::AssertionSuccess();
+}
+
+namespace {
+
+void initConfiguration() {
+    initFrontendConfig();
+    initFrontendScanConfig();
+    initLnbConfig();
+    initFilterConfig();
+    initTimeFilterConfig();
+    initDvrConfig();
+    initDescramblerConfig();
+}
+
+AssertionResult filterDataOutputTestBase(FilterTests tests) {
+    // Data Verify Module
+    std::map<uint32_t, sp<FilterCallback>>::iterator it;
+    std::map<uint32_t, sp<FilterCallback>> filterCallbacks = tests.getFilterCallbacks();
+    for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
+        it->second->testFilterDataOutput();
+    }
+    return success();
+}
+
+class TunerFrontendHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<ITuner> mService;
+    FrontendTests mFrontendTests;
+};
+
+class TunerLnbHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mLnbTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<ITuner> mService;
+    LnbTests mLnbTests;
+};
+
+class TunerDemuxHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+        mDemuxTests.setService(mService);
+        mFilterTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<ITuner> mService;
+    FrontendTests mFrontendTests;
+    DemuxTests mDemuxTests;
+    FilterTests mFilterTests;
+};
+
+class TunerFilterHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+        mDemuxTests.setService(mService);
+        mFilterTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    void configSingleFilterInDemuxTest(FilterConfig filterConf, FrontendConfig frontendConf);
+    void testTimeFilter(TimeFilterConfig filterConf);
+
+    sp<ITuner> mService;
+    FrontendTests mFrontendTests;
+    DemuxTests mDemuxTests;
+    FilterTests mFilterTests;
+};
+
+class TunerBroadcastHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+        mDemuxTests.setService(mService);
+        mFilterTests.setService(mService);
+        mLnbTests.setService(mService);
+        mDvrTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<ITuner> mService;
+    FrontendTests mFrontendTests;
+    DemuxTests mDemuxTests;
+    FilterTests mFilterTests;
+    LnbTests mLnbTests;
+    DvrTests mDvrTests;
+
+    AssertionResult filterDataOutputTest(vector<string> goldenOutputFiles);
+
+    void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf);
+    void broadcastSingleFilterTestWithLnb(FilterConfig filterConf, FrontendConfig frontendConf,
+                                          LnbConfig lnbConf);
+
+  private:
+    uint32_t* mLnbId = nullptr;
+};
+
+class TunerPlaybackHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+        mDemuxTests.setService(mService);
+        mFilterTests.setService(mService);
+        mDvrTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<ITuner> mService;
+    FrontendTests mFrontendTests;
+    DemuxTests mDemuxTests;
+    FilterTests mFilterTests;
+    DvrTests mDvrTests;
+
+    AssertionResult filterDataOutputTest(vector<string> goldenOutputFiles);
+
+    void playbackSingleFilterTest(FilterConfig filterConf, DvrConfig dvrConf);
+};
+
+class TunerRecordHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+        mDemuxTests.setService(mService);
+        mFilterTests.setService(mService);
+        mDvrTests.setService(mService);
+        mLnbTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    void attachSingleFilterToRecordDvrTest(FilterConfig filterConf, FrontendConfig frontendConf,
+                                           DvrConfig dvrConf);
+    void recordSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf,
+                                DvrConfig dvrConf);
+    void recordSingleFilterTestWithLnb(FilterConfig filterConf, FrontendConfig frontendConf,
+                                       DvrConfig dvrConf, LnbConfig lnbConf);
+
+    sp<ITuner> mService;
+    FrontendTests mFrontendTests;
+    DemuxTests mDemuxTests;
+    FilterTests mFilterTests;
+    DvrTests mDvrTests;
+    LnbTests mLnbTests;
+
+  private:
+    uint32_t* mLnbId = nullptr;
+};
+
+class TunerDescramblerHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        mCasService = IMediaCasService::getService();
+        ASSERT_NE(mService, nullptr);
+        ASSERT_NE(mCasService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+        mDemuxTests.setService(mService);
+        mDvrTests.setService(mService);
+        mDescramblerTests.setService(mService);
+        mDescramblerTests.setCasService(mCasService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    void scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
+                                FrontendConfig frontendConf, DescramblerConfig descConfig);
+    AssertionResult filterDataOutputTest(vector<string> /*goldenOutputFiles*/);
+
+    sp<ITuner> mService;
+    sp<IMediaCasService> mCasService;
+    FrontendTests mFrontendTests;
+    DemuxTests mDemuxTests;
+    FilterTests mFilterTests;
+    DescramblerTests mDescramblerTests;
+    DvrTests mDvrTests;
+};
+}  // namespace
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
new file mode 100644
index 0000000..6c68e35
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
@@ -0,0 +1,383 @@
+/*
+ * 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 <android/hardware/tv/tuner/1.0/types.h>
+#include <binder/MemoryDealer.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+
+using android::hardware::tv::tuner::V1_0::DataFormat;
+using android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxRecordScIndexType;
+using android::hardware::tv::tuner::V1_0::DemuxTlvFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxTpid;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::DvrSettings;
+using android::hardware::tv::tuner::V1_0::DvrType;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtGuardInterval;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtHierarchy;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtStandard;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode;
+using android::hardware::tv::tuner::V1_0::FrontendSettings;
+using android::hardware::tv::tuner::V1_0::FrontendStatus;
+using android::hardware::tv::tuner::V1_0::FrontendStatusType;
+using android::hardware::tv::tuner::V1_0::FrontendType;
+using android::hardware::tv::tuner::V1_0::LnbPosition;
+using android::hardware::tv::tuner::V1_0::LnbTone;
+using android::hardware::tv::tuner::V1_0::LnbVoltage;
+using android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
+
+using namespace std;
+
+const uint32_t FMQ_SIZE_1M = 0x100000;
+const uint32_t FMQ_SIZE_4M = 0x400000;
+const uint32_t FMQ_SIZE_16M = 0x1000000;
+
+#define CLEAR_KEY_SYSTEM_ID 0xF6D8
+#define FILTER_MAIN_TYPE_BIT_COUNT 32
+#define PROVISION_STR                                      \
+    "{                                                   " \
+    "  \"id\": 21140844,                                 " \
+    "  \"name\": \"Test Title\",                         " \
+    "  \"lowercase_organization_name\": \"Android\",     " \
+    "  \"asset_key\": {                                  " \
+    "  \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\"  " \
+    "  },                                                " \
+    "  \"cas_type\": 1,                                  " \
+    "  \"track_types\": [ ]                              " \
+    "}                                                   "
+
+typedef enum {
+    TS_VIDEO0,
+    TS_VIDEO1,
+    TS_AUDIO0,
+    TS_PES0,
+    TS_PCR0,
+    TS_SECTION0,
+    TS_TS0,
+    TS_RECORD0,
+    FILTER_MAX,
+} Filter;
+
+typedef enum {
+    TIMER0,
+    TIMER_MAX,
+} TimeFilter;
+
+typedef enum {
+    SOURCE,
+    SINK,
+    LINKAGE_DIR,
+} Linkage;
+
+typedef enum {
+    DVBT,
+    DVBS,
+    FRONTEND_MAX,
+} Frontend;
+
+typedef enum {
+    LNB0,
+    LNB_EXTERNAL,
+    LNB_MAX,
+} Lnb;
+
+typedef enum {
+    DISEQC_POWER_ON,
+    DISEQC_MAX,
+} Diseqc;
+
+typedef enum {
+    SCAN_DVBT,
+    SCAN_MAX,
+} FrontendScan;
+
+typedef enum {
+    DVR_RECORD0,
+    DVR_PLAYBACK0,
+    DVR_SOFTWARE_FE,
+    DVR_MAX,
+} Dvr;
+
+typedef enum {
+    DESC_0,
+    DESC_MAX,
+} Descrambler;
+
+struct FilterConfig {
+    uint32_t bufferSize;
+    DemuxFilterType type;
+    DemuxFilterSettings settings;
+
+    bool operator<(const FilterConfig& /*c*/) const { return false; }
+};
+
+struct TimeFilterConfig {
+    bool supportTimeFilter;
+    uint64_t timeStamp;
+};
+
+struct FrontendConfig {
+    bool isSoftwareFe;
+    FrontendType type;
+    FrontendSettings settings;
+    vector<FrontendStatusType> tuneStatusTypes;
+    vector<FrontendStatus> expectTuneStatuses;
+};
+
+struct LnbConfig {
+    bool usingLnb;
+    string name;
+    LnbVoltage voltage;
+    LnbTone tone;
+    LnbPosition position;
+};
+
+struct ChannelConfig {
+    int32_t frontendId;
+    int32_t channelId;
+    std::string channelName;
+    DemuxTpid videoPid;
+    DemuxTpid audioPid;
+};
+
+struct DvrConfig {
+    DvrType type;
+    uint32_t bufferSize;
+    DvrSettings settings;
+    string playbackInputFile;
+};
+
+struct DescramblerConfig {
+    uint32_t casSystemId;
+    string provisionStr;
+    vector<uint8_t> hidlPvtData;
+};
+
+static FrontendConfig frontendArray[FILTER_MAX];
+static FrontendConfig frontendScanArray[SCAN_MAX];
+static LnbConfig lnbArray[LNB_MAX];
+static vector<uint8_t> diseqcMsgArray[DISEQC_MAX];
+static ChannelConfig channelArray[FRONTEND_MAX];
+static FilterConfig filterArray[FILTER_MAX];
+static TimeFilterConfig timeFilterArray[TIMER_MAX];
+static DemuxFilterType filterLinkageTypes[LINKAGE_DIR][FILTER_MAIN_TYPE_BIT_COUNT];
+static DvrConfig dvrArray[DVR_MAX];
+static DescramblerConfig descramblerArray[DESC_MAX];
+static vector<string> goldenOutputFiles;
+
+/** Configuration array for the frontend tune test */
+inline void initFrontendConfig() {
+    FrontendDvbtSettings dvbtSettings{
+            .frequency = 578000,
+            .transmissionMode = FrontendDvbtTransmissionMode::AUTO,
+            .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
+            .constellation = FrontendDvbtConstellation::AUTO,
+            .hierarchy = FrontendDvbtHierarchy::AUTO,
+            .hpCoderate = FrontendDvbtCoderate::AUTO,
+            .lpCoderate = FrontendDvbtCoderate::AUTO,
+            .guardInterval = FrontendDvbtGuardInterval::AUTO,
+            .isHighPriority = true,
+            .standard = FrontendDvbtStandard::T,
+    };
+    frontendArray[DVBT].type = FrontendType::DVBT, frontendArray[DVBT].settings.dvbt(dvbtSettings);
+    vector<FrontendStatusType> types;
+    types.push_back(FrontendStatusType::DEMOD_LOCK);
+    FrontendStatus status;
+    status.isDemodLocked(true);
+    vector<FrontendStatus> statuses;
+    statuses.push_back(status);
+    frontendArray[DVBT].tuneStatusTypes = types;
+    frontendArray[DVBT].expectTuneStatuses = statuses;
+    frontendArray[DVBT].isSoftwareFe = true;
+    frontendArray[DVBS].type = FrontendType::DVBS;
+    frontendArray[DVBS].isSoftwareFe = true;
+};
+
+/** Configuration array for the frontend scan test */
+inline void initFrontendScanConfig() {
+    frontendScanArray[SCAN_DVBT].type = FrontendType::DVBT;
+    frontendScanArray[SCAN_DVBT].settings.dvbt({
+            .frequency = 578000,
+            .transmissionMode = FrontendDvbtTransmissionMode::MODE_8K,
+            .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
+            .constellation = FrontendDvbtConstellation::AUTO,
+            .hierarchy = FrontendDvbtHierarchy::AUTO,
+            .hpCoderate = FrontendDvbtCoderate::AUTO,
+            .lpCoderate = FrontendDvbtCoderate::AUTO,
+            .guardInterval = FrontendDvbtGuardInterval::AUTO,
+            .isHighPriority = true,
+            .standard = FrontendDvbtStandard::T,
+    });
+};
+
+/** Configuration array for the Lnb test */
+inline void initLnbConfig() {
+    lnbArray[LNB0].usingLnb = true;
+    lnbArray[LNB0].voltage = LnbVoltage::VOLTAGE_12V;
+    lnbArray[LNB0].tone = LnbTone::NONE;
+    lnbArray[LNB0].position = LnbPosition::UNDEFINED;
+    lnbArray[LNB_EXTERNAL].usingLnb = true;
+    lnbArray[LNB_EXTERNAL].name = "default_lnb_external";
+    lnbArray[LNB_EXTERNAL].voltage = LnbVoltage::VOLTAGE_5V;
+    lnbArray[LNB_EXTERNAL].tone = LnbTone::NONE;
+    lnbArray[LNB_EXTERNAL].position = LnbPosition::UNDEFINED;
+};
+
+/** Diseqc messages array for the Lnb test */
+inline void initDiseqcMsg() {
+    diseqcMsgArray[DISEQC_POWER_ON] = {0xE, 0x0, 0x0, 0x0, 0x0, 0x3};
+};
+
+/** Configuration array for the filter test */
+inline void initFilterConfig() {
+    // TS VIDEO filter setting for default implementation testing
+    filterArray[TS_VIDEO0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_VIDEO0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
+    filterArray[TS_VIDEO0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_VIDEO0].settings.ts().tpid = 256;
+    filterArray[TS_VIDEO0].settings.ts().filterSettings.av({.isPassthrough = false});
+    filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
+    filterArray[TS_VIDEO1].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_VIDEO1].settings.ts().tpid = 256;
+    filterArray[TS_VIDEO1].settings.ts().filterSettings.av({.isPassthrough = false});
+    // TS AUDIO filter setting
+    filterArray[TS_AUDIO0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_AUDIO0].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
+    filterArray[TS_AUDIO0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_AUDIO0].settings.ts().tpid = 256;
+    filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false});
+    // TS PES filter setting
+    filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES);
+    filterArray[TS_PES0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_PES0].settings.ts().tpid = 256;
+    filterArray[TS_PES0].settings.ts().filterSettings.pesData({
+            .isRaw = false,
+            .streamId = 0xbd,
+    });
+    // TS PCR filter setting
+    filterArray[TS_PCR0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_PCR0].type.subType.tsFilterType(DemuxTsFilterType::PCR);
+    filterArray[TS_PCR0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_PCR0].settings.ts().tpid = 256;
+    filterArray[TS_PCR0].settings.ts().filterSettings.noinit();
+    // TS filter setting
+    filterArray[TS_TS0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_TS0].type.subType.tsFilterType(DemuxTsFilterType::TS);
+    filterArray[TS_TS0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_TS0].settings.ts().tpid = 256;
+    filterArray[TS_TS0].settings.ts().filterSettings.noinit();
+    // TS SECTION filter setting
+    filterArray[TS_SECTION0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_SECTION0].type.subType.tsFilterType(DemuxTsFilterType::SECTION);
+    filterArray[TS_SECTION0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_SECTION0].settings.ts().tpid = 256;
+    filterArray[TS_SECTION0].settings.ts().filterSettings.section({
+            .isRaw = false,
+    });
+    // TS RECORD filter setting
+    filterArray[TS_RECORD0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_RECORD0].type.subType.tsFilterType(DemuxTsFilterType::RECORD);
+    filterArray[TS_RECORD0].settings.ts().tpid = 81;
+    filterArray[TS_RECORD0].settings.ts().filterSettings.record({
+            .scIndexType = DemuxRecordScIndexType::NONE,
+    });
+
+    // TS Linkage filter setting
+    filterLinkageTypes[SOURCE][0].mainType = DemuxFilterMainType::TS;
+    filterLinkageTypes[SOURCE][0].subType.tsFilterType(DemuxTsFilterType::TS);
+    filterLinkageTypes[SINK][0] = filterLinkageTypes[SOURCE][0];
+    // MMTP Linkage filter setting
+    filterLinkageTypes[SOURCE][1].mainType = DemuxFilterMainType::MMTP;
+    filterLinkageTypes[SOURCE][1].subType.mmtpFilterType(DemuxMmtpFilterType::AUDIO);
+    filterLinkageTypes[SINK][1] = filterLinkageTypes[SOURCE][1];
+    // IP Linkage filter setting
+    filterLinkageTypes[SOURCE][2].mainType = DemuxFilterMainType::IP;
+    filterLinkageTypes[SOURCE][2].subType.ipFilterType(DemuxIpFilterType::IP);
+    filterLinkageTypes[SINK][2] = filterLinkageTypes[SOURCE][2];
+    // TLV Linkage filter setting
+    filterLinkageTypes[SOURCE][3].mainType = DemuxFilterMainType::TLV;
+    filterLinkageTypes[SOURCE][3].subType.tlvFilterType(DemuxTlvFilterType::TLV);
+    filterLinkageTypes[SINK][3] = filterLinkageTypes[SOURCE][3];
+    // ALP Linkage PTP filter setting
+    filterLinkageTypes[SOURCE][4].mainType = DemuxFilterMainType::ALP;
+    filterLinkageTypes[SOURCE][4].subType.alpFilterType(DemuxAlpFilterType::PTP);
+    filterLinkageTypes[SINK][4] = filterLinkageTypes[SOURCE][4];
+};
+
+/** Configuration array for the timer filter test */
+inline void initTimeFilterConfig() {
+    timeFilterArray[TIMER0].supportTimeFilter = true;
+    timeFilterArray[TIMER0].timeStamp = 1;
+}
+
+/** Configuration array for the dvr test */
+inline void initDvrConfig() {
+    RecordSettings recordSettings{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x07fff,
+            .dataFormat = DataFormat::TS,
+            .packetSize = 188,
+    };
+    dvrArray[DVR_RECORD0].type = DvrType::RECORD;
+    dvrArray[DVR_RECORD0].bufferSize = FMQ_SIZE_4M;
+    dvrArray[DVR_RECORD0].settings.record(recordSettings);
+    PlaybackSettings playbackSettings{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x07fff,
+            .dataFormat = DataFormat::TS,
+            .packetSize = 188,
+    };
+    dvrArray[DVR_PLAYBACK0].type = DvrType::PLAYBACK;
+    dvrArray[DVR_PLAYBACK0].playbackInputFile = "/data/local/tmp/segment000000.ts";
+    dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M;
+    dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings);
+    PlaybackSettings softwareFePlaybackSettings{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x07fff,
+            .dataFormat = DataFormat::TS,
+            .packetSize = 188,
+    };
+    dvrArray[DVR_SOFTWARE_FE].type = DvrType::PLAYBACK;
+    dvrArray[DVR_SOFTWARE_FE].playbackInputFile = "/data/local/tmp/segment000000.ts";
+    dvrArray[DVR_SOFTWARE_FE].bufferSize = FMQ_SIZE_4M;
+    dvrArray[DVR_SOFTWARE_FE].settings.playback(softwareFePlaybackSettings);
+};
+
+/** Configuration array for the descrambler test */
+inline void initDescramblerConfig() {
+    descramblerArray[DESC_0].casSystemId = CLEAR_KEY_SYSTEM_ID;
+    descramblerArray[DESC_0].provisionStr = PROVISION_STR;
+    descramblerArray[DESC_0].hidlPvtData.resize(256);
+};
diff --git a/tv/tuner/README.md b/tv/tuner/README.md
new file mode 100644
index 0000000..aa1f62d
--- /dev/null
+++ b/tv/tuner/README.md
@@ -0,0 +1,12 @@
+# Tuner HALs
+
+## Overview
+
+TV specific tuners.
+
+See 1.0/ITuner.hal for an overview.
+
+*** note
+**Warning:** The HALs are not (yet) frozen, as the HAL definition is
+expected to evolve between Android releases.
+***
diff --git a/usb/1.2/vts/functional/Android.bp b/usb/1.2/vts/functional/Android.bp
index 761d37f..d6aaf2d 100644
--- a/usb/1.2/vts/functional/Android.bp
+++ b/usb/1.2/vts/functional/Android.bp
@@ -23,6 +23,8 @@
         "android.hardware.usb@1.1",
         "android.hardware.usb@1.2",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
-
diff --git a/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp
index 7b3dea9..5f901cd 100644
--- a/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp
+++ b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp
@@ -22,8 +22,10 @@
 #include <android/hardware/usb/1.2/types.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
 #include <log/log.h>
 #include <stdlib.h>
 #include <chrono>
@@ -139,24 +141,12 @@
     };
 };
 
-// Test environment for Usb HIDL HAL.
-class UsbHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static UsbHidlEnvironment* Instance() {
-        static UsbHidlEnvironment* instance = new UsbHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IUsb>(); }
-};
-
 // The main test class for the USB hidl HAL
-class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
+class UsbHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override {
         ALOGI(__FUNCTION__);
-        usb = ::testing::VtsHalHidlTargetTestBase::getService<IUsb>();
+        usb = IUsb::getService(GetParam());
         ASSERT_NE(usb, nullptr);
 
         usb_cb_2 = new UsbCallback(kCallbackIdentifier);
@@ -182,7 +172,7 @@
  * Callback oject is created and registered.
  * Check to see if the hidl transaction succeeded.
  */
-TEST_F(UsbHidlTest, setCallback) {
+TEST_P(UsbHidlTest, setCallback) {
     usb_cb_1 = new UsbCallback(1);
     ASSERT_NE(usb_cb_1, nullptr);
     Return<void> ret = usb->setCallback(usb_cb_1);
@@ -195,7 +185,7 @@
  * HAL service should call notifyPortStatusChange_1_2
  * instead of notifyPortStatusChange of V1_0/V1_1 interface
  */
-TEST_F(UsbHidlTest, queryPortStatus) {
+TEST_P(UsbHidlTest, queryPortStatus) {
     Return<void> ret = usb->queryPortStatus();
     ASSERT_TRUE(ret.isOk());
     auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
@@ -211,7 +201,7 @@
  * Check if supportedContaminantProtectionModes changes across queryPortStatus
  * call.
  */
-TEST_F(UsbHidlTest, checkSupportedContaminantProtectionModes) {
+TEST_P(UsbHidlTest, checkSupportedContaminantProtectionModes) {
     Return<void> ret = usb->queryPortStatus();
     ASSERT_TRUE(ret.isOk());
     auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
@@ -243,7 +233,7 @@
  * enableContaminantPresenceDetection should not enable/disable
  * contaminantPresenceProtection.
  */
-TEST_F(UsbHidlTest, presenceDetectionSupportedCheck) {
+TEST_P(UsbHidlTest, presenceDetectionSupportedCheck) {
     Return<void> ret = usb->queryPortStatus();
     ASSERT_TRUE(ret.isOk());
     auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
@@ -272,7 +262,7 @@
 /*
  * enableContaminantPresenceDetection should succeed atleast 90% when supported.
  */
-TEST_F(UsbHidlTest, contaminantPresenceDetectionStability) {
+TEST_P(UsbHidlTest, contaminantPresenceDetectionStability) {
     int successCount = 0;
     bool currentStatus;
     bool supported = true;
@@ -309,7 +299,7 @@
  * enableContaminantPresenceProtection should not enable/disable
  * contaminantPresenceProtection.
  */
-TEST_F(UsbHidlTest, presenceProtectionSupportedCheck) {
+TEST_P(UsbHidlTest, presenceProtectionSupportedCheck) {
     Return<void> ret = usb->queryPortStatus();
     ASSERT_TRUE(ret.isOk());
     auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
@@ -338,7 +328,7 @@
 /*
  * enableContaminantPresenceProtection should succeed atleast 90% when supported.
  */
-TEST_F(UsbHidlTest, contaminantPresenceProtectionStability) {
+TEST_P(UsbHidlTest, contaminantPresenceProtectionStability) {
     int successCount = 0;
     bool currentStatus;
     bool supported = true;
@@ -370,11 +360,7 @@
     if (!supported) EXPECT_GE(successCount, 9);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(UsbHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    UsbHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, UsbHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IUsb::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/usb/gadget/1.1/Android.bp b/usb/gadget/1.1/Android.bp
new file mode 100644
index 0000000..e510069
--- /dev/null
+++ b/usb/gadget/1.1/Android.bp
@@ -0,0 +1,14 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.usb.gadget@1.1",
+    root: "android.hardware",
+    srcs: [
+        "IUsbGadget.hal",
+    ],
+    interfaces: [
+        "android.hardware.usb.gadget@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/usb/gadget/1.1/IUsbGadget.hal b/usb/gadget/1.1/IUsbGadget.hal
new file mode 100644
index 0000000..af88ef0
--- /dev/null
+++ b/usb/gadget/1.1/IUsbGadget.hal
@@ -0,0 +1,31 @@
+/*
+ * 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.usb.gadget@1.1;
+
+import @1.0::IUsbGadget;
+import @1.0::Status;
+
+interface IUsbGadget extends @1.0::IUsbGadget {
+    /**
+     * This function is used to reset USB gadget driver.
+     * Performs USB data connection reset. The connection will disconnect and
+     * reconnect.
+     *
+     * return status indicate success or not.
+     */
+    reset() generates(Status status);
+};
diff --git a/usb/gadget/1.1/default/Android.bp b/usb/gadget/1.1/default/Android.bp
new file mode 100644
index 0000000..68e2a29
--- /dev/null
+++ b/usb/gadget/1.1/default/Android.bp
@@ -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.
+ */
+
+cc_binary {
+    name: "android.hardware.usb.gadget@1.1-service",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.usb.gadget@1.1-service.rc"],
+    vintf_fragments: ["android.hardware.usb.gadget@1.1-service.xml"],
+    vendor: true,
+    srcs: [
+        "service.cpp",
+        "UsbGadget.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.usb.gadget@1.0",
+        "android.hardware.usb.gadget@1.1",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: ["libusbconfigfs"],
+}
diff --git a/usb/gadget/1.1/default/UsbGadget.cpp b/usb/gadget/1.1/default/UsbGadget.cpp
new file mode 100644
index 0000000..36d865d
--- /dev/null
+++ b/usb/gadget/1.1/default/UsbGadget.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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.usb.gadget@1.1-service"
+
+#include "UsbGadget.h"
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+namespace V1_1 {
+namespace implementation {
+
+UsbGadget::UsbGadget() {
+    if (access(OS_DESC_PATH, R_OK) != 0) {
+        ALOGE("configfs setup not done yet");
+        abort();
+    }
+}
+
+void currentFunctionsAppliedCallback(bool functionsApplied, void* payload) {
+    UsbGadget* gadget = (UsbGadget*)payload;
+    gadget->mCurrentUsbFunctionsApplied = functionsApplied;
+}
+
+Return<void> UsbGadget::getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback>& callback) {
+    Return<void> ret = callback->getCurrentUsbFunctionsCb(
+            mCurrentUsbFunctions, mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED
+                                                              : Status::FUNCTIONS_NOT_APPLIED);
+    if (!ret.isOk()) ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.description().c_str());
+
+    return Void();
+}
+
+V1_0::Status UsbGadget::tearDownGadget() {
+    if (resetGadget() != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
+
+    if (monitorFfs.isMonitorRunning()) {
+        monitorFfs.reset();
+    } else {
+        ALOGI("mMonitor not running");
+    }
+    return V1_0::Status::SUCCESS;
+}
+
+Return<Status> UsbGadget::reset() {
+    if (!WriteStringToFile("none", PULLUP_PATH)) {
+        ALOGI("Gadget cannot be pulled down");
+        return Status::ERROR;
+    }
+
+    return Status::SUCCESS;
+}
+
+static V1_0::Status validateAndSetVidPid(uint64_t functions) {
+    V1_0::Status ret = V1_0::Status::SUCCESS;
+
+    switch (functions) {
+        case static_cast<uint64_t>(V1_0::GadgetFunction::MTP):
+            ret = setVidPid("0x18d1", "0x4ee1");
+            break;
+        case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::MTP:
+            ret = setVidPid("0x18d1", "0x4ee2");
+            break;
+        case static_cast<uint64_t>(V1_0::GadgetFunction::RNDIS):
+            ret = setVidPid("0x18d1", "0x4ee3");
+            break;
+        case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::RNDIS:
+            ret = setVidPid("0x18d1", "0x4ee4");
+            break;
+        case static_cast<uint64_t>(V1_0::GadgetFunction::PTP):
+            ret = setVidPid("0x18d1", "0x4ee5");
+            break;
+        case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::PTP:
+            ret = setVidPid("0x18d1", "0x4ee6");
+            break;
+        case static_cast<uint64_t>(V1_0::GadgetFunction::ADB):
+            ret = setVidPid("0x18d1", "0x4ee7");
+            break;
+        case static_cast<uint64_t>(V1_0::GadgetFunction::MIDI):
+            ret = setVidPid("0x18d1", "0x4ee8");
+            break;
+        case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::MIDI:
+            ret = setVidPid("0x18d1", "0x4ee9");
+            break;
+        case static_cast<uint64_t>(V1_0::GadgetFunction::ACCESSORY):
+            ret = setVidPid("0x18d1", "0x2d00");
+            break;
+        case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::ACCESSORY:
+            ret = setVidPid("0x18d1", "0x2d01");
+            break;
+        case static_cast<uint64_t>(V1_0::GadgetFunction::AUDIO_SOURCE):
+            ret = setVidPid("0x18d1", "0x2d02");
+            break;
+        case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::AUDIO_SOURCE:
+            ret = setVidPid("0x18d1", "0x2d03");
+            break;
+        case V1_0::GadgetFunction::ACCESSORY | V1_0::GadgetFunction::AUDIO_SOURCE:
+            ret = setVidPid("0x18d1", "0x2d04");
+            break;
+        case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::ACCESSORY |
+                V1_0::GadgetFunction::AUDIO_SOURCE:
+            ret = setVidPid("0x18d1", "0x2d05");
+            break;
+        default:
+            ALOGE("Combination not supported");
+            ret = V1_0::Status::CONFIGURATION_NOT_SUPPORTED;
+    }
+    return ret;
+}
+
+V1_0::Status UsbGadget::setupFunctions(uint64_t functions,
+                                       const sp<V1_0::IUsbGadgetCallback>& callback,
+                                       uint64_t timeout) {
+    bool ffsEnabled = false;
+    int i = 0;
+
+    if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=
+        V1_0::Status::SUCCESS)
+        return V1_0::Status::ERROR;
+
+    if ((functions & V1_0::GadgetFunction::ADB) != 0) {
+        ffsEnabled = true;
+        if (addAdb(&monitorFfs, &i) != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
+    }
+
+    // Pull up the gadget right away when there are no ffs functions.
+    if (!ffsEnabled) {
+        if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) return V1_0::Status::ERROR;
+        mCurrentUsbFunctionsApplied = true;
+        if (callback) callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
+        return V1_0::Status::SUCCESS;
+    }
+
+    monitorFfs.registerFunctionsAppliedCallback(&currentFunctionsAppliedCallback, this);
+    // Monitors the ffs paths to pull up the gadget when descriptors are written.
+    // Also takes of the pulling up the gadget again if the userspace process
+    // dies and restarts.
+    monitorFfs.startMonitor();
+
+    if (kDebug) ALOGI("Mainthread in Cv");
+
+    if (callback) {
+        bool pullup = monitorFfs.waitForPullUp(timeout);
+        Return<void> ret = callback->setCurrentUsbFunctionsCb(
+                functions, pullup ? V1_0::Status::SUCCESS : V1_0::Status::ERROR);
+        if (!ret.isOk()) ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());
+    }
+
+    return V1_0::Status::SUCCESS;
+}
+
+Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,
+                                               const sp<V1_0::IUsbGadgetCallback>& callback,
+                                               uint64_t timeout) {
+    std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
+
+    mCurrentUsbFunctions = functions;
+    mCurrentUsbFunctionsApplied = false;
+
+    // Unlink the gadget and stop the monitor if running.
+    V1_0::Status status = tearDownGadget();
+    if (status != V1_0::Status::SUCCESS) {
+        goto error;
+    }
+
+    ALOGI("Returned from tearDown gadget");
+
+    // Leave the gadget pulled down to give time for the host to sense disconnect.
+    usleep(kDisconnectWaitUs);
+
+    if (functions == static_cast<uint64_t>(V1_0::GadgetFunction::NONE)) {
+        if (callback == NULL) return Void();
+        Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
+        if (!ret.isOk())
+            ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
+        return Void();
+    }
+
+    status = validateAndSetVidPid(functions);
+
+    if (status != V1_0::Status::SUCCESS) {
+        goto error;
+    }
+
+    status = setupFunctions(functions, callback, timeout);
+    if (status != V1_0::Status::SUCCESS) {
+        goto error;
+    }
+
+    ALOGI("Usb Gadget setcurrent functions called successfully");
+    return Void();
+
+error:
+    ALOGI("Usb Gadget setcurrent functions failed");
+    if (callback == NULL) return Void();
+    Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
+    if (!ret.isOk())
+        ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
+    return Void();
+}
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gadget
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
diff --git a/usb/gadget/1.1/default/UsbGadget.h b/usb/gadget/1.1/default/UsbGadget.h
new file mode 100644
index 0000000..b278071
--- /dev/null
+++ b/usb/gadget/1.1/default/UsbGadget.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.
+ */
+
+#ifndef ANDROID_HARDWARE_USB_GADGET_V1_1_USBGADGET_H
+#define ANDROID_HARDWARE_USB_GADGET_V1_1_USBGADGET_H
+
+#include <UsbGadgetCommon.h>
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/usb/gadget/1.1/IUsbGadget.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::base::GetProperty;
+using ::android::base::SetProperty;
+using ::android::base::unique_fd;
+using ::android::base::WriteStringToFile;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::usb::gadget::addAdb;
+using ::android::hardware::usb::gadget::addEpollFd;
+using ::android::hardware::usb::gadget::getVendorFunctions;
+using ::android::hardware::usb::gadget::kDebug;
+using ::android::hardware::usb::gadget::kDisconnectWaitUs;
+using ::android::hardware::usb::gadget::linkFunction;
+using ::android::hardware::usb::gadget::MonitorFfs;
+using ::android::hardware::usb::gadget::resetGadget;
+using ::android::hardware::usb::gadget::setVidPid;
+using ::android::hardware::usb::gadget::unlinkFunctions;
+using ::std::string;
+
+constexpr char kGadgetName[] = "a600000.dwc3";
+static MonitorFfs monitorFfs(kGadgetName);
+
+struct UsbGadget : public IUsbGadget {
+    UsbGadget();
+
+    // Makes sure that only one request is processed at a time.
+    std::mutex mLockSetCurrentFunction;
+    uint64_t mCurrentUsbFunctions;
+    bool mCurrentUsbFunctionsApplied;
+
+    Return<void> setCurrentUsbFunctions(uint64_t functions,
+                                        const sp<V1_0::IUsbGadgetCallback>& callback,
+                                        uint64_t timeout) override;
+
+    Return<void> getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback>& callback) override;
+
+    Return<Status> reset() override;
+
+  private:
+    V1_0::Status tearDownGadget();
+    V1_0::Status setupFunctions(uint64_t functions, const sp<V1_0::IUsbGadgetCallback>& callback,
+                                uint64_t timeout);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gadget
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_USB_V1_1_USBGADGET_H
diff --git a/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.rc b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.rc
new file mode 100644
index 0000000..34ea7da
--- /dev/null
+++ b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.usb-gadget-hal-1-1 /vendor/bin/hw/android.hardware.usb.gadget@1.1-service
+    interface android.hardware.usb.gadget@1.0::IUsbGadget default
+    interface android.hardware.usb.gadget@1.1::IUsbGadget default
+    class hal
+    user root
+    group root shell mtp
diff --git a/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.xml b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.xml
new file mode 100644
index 0000000..b40fa77
--- /dev/null
+++ b/usb/gadget/1.1/default/android.hardware.usb.gadget@1.1-service.xml
@@ -0,0 +1,12 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.usb.gadget</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IUsbGadget</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
+
diff --git a/usb/gadget/1.1/default/lib/Android.bp b/usb/gadget/1.1/default/lib/Android.bp
new file mode 100644
index 0000000..bba8340
--- /dev/null
+++ b/usb/gadget/1.1/default/lib/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * 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: "libusbconfigfs",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+
+    srcs: [
+        "UsbGadgetUtils.cpp",
+        "MonitorFfs.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    shared_libs: [
+        "android.hardware.usb.gadget@1.0",
+        "android.hardware.usb.gadget@1.1",
+        "libbase",
+        "libcutils",
+        "libhidlbase",
+        "libutils",
+    ],
+}
diff --git a/usb/gadget/1.1/default/lib/MonitorFfs.cpp b/usb/gadget/1.1/default/lib/MonitorFfs.cpp
new file mode 100644
index 0000000..0cdf038
--- /dev/null
+++ b/usb/gadget/1.1/default/lib/MonitorFfs.cpp
@@ -0,0 +1,269 @@
+/*
+ * 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 "libusbconfigfs"
+
+#include "include/UsbGadgetCommon.h"
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+static volatile bool gadgetPullup;
+
+MonitorFfs::MonitorFfs(const char* const gadget)
+    : mWatchFd(),
+      mEndpointList(),
+      mLock(),
+      mCv(),
+      mLockFd(),
+      mCurrentUsbFunctionsApplied(false),
+      mMonitor(),
+      mCallback(NULL),
+      mPayload(NULL),
+      mGadgetName(gadget),
+      mMonitorRunning(false) {
+    unique_fd eventFd(eventfd(0, 0));
+    if (eventFd == -1) {
+        ALOGE("mEventFd failed to create %d", errno);
+        abort();
+    }
+
+    unique_fd epollFd(epoll_create(2));
+    if (epollFd == -1) {
+        ALOGE("mEpollFd failed to create %d", errno);
+        abort();
+    }
+
+    unique_fd inotifyFd(inotify_init());
+    if (inotifyFd < 0) {
+        ALOGE("inotify init failed");
+        abort();
+    }
+
+    if (addEpollFd(epollFd, inotifyFd) == -1) abort();
+
+    if (addEpollFd(epollFd, eventFd) == -1) abort();
+
+    mEpollFd = move(epollFd);
+    mInotifyFd = move(inotifyFd);
+    mEventFd = move(eventFd);
+    gadgetPullup = false;
+}
+
+static void displayInotifyEvent(struct inotify_event* i) {
+    ALOGE("    wd =%2d; ", i->wd);
+    if (i->cookie > 0) ALOGE("cookie =%4d; ", i->cookie);
+
+    ALOGE("mask = ");
+    if (i->mask & IN_ACCESS) ALOGE("IN_ACCESS ");
+    if (i->mask & IN_ATTRIB) ALOGE("IN_ATTRIB ");
+    if (i->mask & IN_CLOSE_NOWRITE) ALOGE("IN_CLOSE_NOWRITE ");
+    if (i->mask & IN_CLOSE_WRITE) ALOGE("IN_CLOSE_WRITE ");
+    if (i->mask & IN_CREATE) ALOGE("IN_CREATE ");
+    if (i->mask & IN_DELETE) ALOGE("IN_DELETE ");
+    if (i->mask & IN_DELETE_SELF) ALOGE("IN_DELETE_SELF ");
+    if (i->mask & IN_IGNORED) ALOGE("IN_IGNORED ");
+    if (i->mask & IN_ISDIR) ALOGE("IN_ISDIR ");
+    if (i->mask & IN_MODIFY) ALOGE("IN_MODIFY ");
+    if (i->mask & IN_MOVE_SELF) ALOGE("IN_MOVE_SELF ");
+    if (i->mask & IN_MOVED_FROM) ALOGE("IN_MOVED_FROM ");
+    if (i->mask & IN_MOVED_TO) ALOGE("IN_MOVED_TO ");
+    if (i->mask & IN_OPEN) ALOGE("IN_OPEN ");
+    if (i->mask & IN_Q_OVERFLOW) ALOGE("IN_Q_OVERFLOW ");
+    if (i->mask & IN_UNMOUNT) ALOGE("IN_UNMOUNT ");
+    ALOGE("\n");
+
+    if (i->len > 0) ALOGE("        name = %s\n", i->name);
+}
+
+void* MonitorFfs::startMonitorFd(void* param) {
+    MonitorFfs* monitorFfs = (MonitorFfs*)param;
+    char buf[kBufferSize];
+    bool writeUdc = true, stopMonitor = false;
+    struct epoll_event events[kEpollEvents];
+    steady_clock::time_point disconnect;
+
+    bool descriptorWritten = true;
+    for (int i = 0; i < static_cast<int>(monitorFfs->mEndpointList.size()); i++) {
+        if (access(monitorFfs->mEndpointList.at(i).c_str(), R_OK)) {
+            descriptorWritten = false;
+            break;
+        }
+    }
+
+    // notify here if the endpoints are already present.
+    if (descriptorWritten) {
+        usleep(kPullUpDelay);
+        if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
+            lock_guard<mutex> lock(monitorFfs->mLock);
+            monitorFfs->mCurrentUsbFunctionsApplied = true;
+            monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied, monitorFfs->mPayload);
+            gadgetPullup = true;
+            writeUdc = false;
+            ALOGI("GADGET pulled up");
+            monitorFfs->mCv.notify_all();
+        }
+    }
+
+    while (!stopMonitor) {
+        int nrEvents = epoll_wait(monitorFfs->mEpollFd, events, kEpollEvents, -1);
+
+        if (nrEvents <= 0) {
+            ALOGE("epoll wait did not return descriptor number");
+            continue;
+        }
+
+        for (int i = 0; i < nrEvents; i++) {
+            ALOGI("event=%u on fd=%d\n", events[i].events, events[i].data.fd);
+
+            if (events[i].data.fd == monitorFfs->mInotifyFd) {
+                // Process all of the events in buffer returned by read().
+                int numRead = read(monitorFfs->mInotifyFd, buf, kBufferSize);
+                for (char* p = buf; p < buf + numRead;) {
+                    struct inotify_event* event = (struct inotify_event*)p;
+                    if (kDebug) displayInotifyEvent(event);
+
+                    p += sizeof(struct inotify_event) + event->len;
+
+                    bool descriptorPresent = true;
+                    for (int j = 0; j < static_cast<int>(monitorFfs->mEndpointList.size()); j++) {
+                        if (access(monitorFfs->mEndpointList.at(j).c_str(), R_OK)) {
+                            if (kDebug) ALOGI("%s absent", monitorFfs->mEndpointList.at(j).c_str());
+                            descriptorPresent = false;
+                            break;
+                        }
+                    }
+
+                    if (!descriptorPresent && !writeUdc) {
+                        if (kDebug) ALOGI("endpoints not up");
+                        writeUdc = true;
+                        disconnect = std::chrono::steady_clock::now();
+                    } else if (descriptorPresent && writeUdc) {
+                        steady_clock::time_point temp = steady_clock::now();
+
+                        if (std::chrono::duration_cast<microseconds>(temp - disconnect).count() <
+                            kPullUpDelay)
+                            usleep(kPullUpDelay);
+
+                        if (!!WriteStringToFile(monitorFfs->mGadgetName, PULLUP_PATH)) {
+                            lock_guard<mutex> lock(monitorFfs->mLock);
+                            monitorFfs->mCurrentUsbFunctionsApplied = true;
+                            monitorFfs->mCallback(monitorFfs->mCurrentUsbFunctionsApplied,
+                                                  monitorFfs->mPayload);
+                            ALOGI("GADGET pulled up");
+                            writeUdc = false;
+                            gadgetPullup = true;
+                            // notify the main thread to signal userspace.
+                            monitorFfs->mCv.notify_all();
+                        }
+                    }
+                }
+            } else {
+                uint64_t flag;
+                read(monitorFfs->mEventFd, &flag, sizeof(flag));
+                if (flag == 100) {
+                    stopMonitor = true;
+                    break;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+void MonitorFfs::reset() {
+    lock_guard<mutex> lock(mLockFd);
+    uint64_t flag = 100;
+    unsigned long ret;
+
+    if (mMonitorRunning) {
+        // Stop the monitor thread by writing into signal fd.
+        ret = TEMP_FAILURE_RETRY(write(mEventFd, &flag, sizeof(flag)));
+        if (ret < 0) ALOGE("Error writing eventfd errno=%d", errno);
+
+        ALOGI("mMonitor signalled to exit");
+        mMonitor->join();
+        ALOGI("mMonitor destroyed");
+        mMonitorRunning = false;
+    }
+
+    for (std::vector<int>::size_type i = 0; i != mWatchFd.size(); i++)
+        inotify_rm_watch(mInotifyFd, mWatchFd[i]);
+
+    mEndpointList.clear();
+    gadgetPullup = false;
+    mCallback = NULL;
+    mPayload = NULL;
+}
+
+bool MonitorFfs::startMonitor() {
+    mMonitor = unique_ptr<thread>(new thread(this->startMonitorFd, this));
+    mMonitorRunning = true;
+    return true;
+}
+
+bool MonitorFfs::isMonitorRunning() {
+    return mMonitorRunning;
+}
+
+bool MonitorFfs::waitForPullUp(int timeout_ms) {
+    std::unique_lock<std::mutex> lk(mLock);
+
+    if (gadgetPullup) return true;
+
+    if (mCv.wait_for(lk, timeout_ms * 1ms, [] { return gadgetPullup; })) {
+        ALOGI("monitorFfs signalled true");
+        return true;
+    } else {
+        ALOGI("monitorFfs signalled error");
+        // continue monitoring as the descriptors might be written at a later
+        // point.
+        return false;
+    }
+}
+
+bool MonitorFfs::addInotifyFd(string fd) {
+    lock_guard<mutex> lock(mLockFd);
+    int wfd;
+
+    wfd = inotify_add_watch(mInotifyFd, fd.c_str(), IN_ALL_EVENTS);
+    if (wfd == -1)
+        return false;
+    else
+        mWatchFd.push_back(wfd);
+
+    return true;
+}
+
+void MonitorFfs::addEndPoint(string ep) {
+    lock_guard<mutex> lock(mLockFd);
+
+    mEndpointList.push_back(ep);
+}
+
+void MonitorFfs::registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied,
+                                                                   void* payload),
+                                                  void* payload) {
+    mCallback = callback;
+    mPayload = payload;
+}
+
+}  // namespace gadget
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
diff --git a/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp b/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp
new file mode 100644
index 0000000..8402853
--- /dev/null
+++ b/usb/gadget/1.1/default/lib/UsbGadgetUtils.cpp
@@ -0,0 +1,193 @@
+/*
+ * 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 "libusbconfigfs"
+
+#include "include/UsbGadgetCommon.h"
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+int unlinkFunctions(const char* path) {
+    DIR* config = opendir(path);
+    struct dirent* function;
+    char filepath[kMaxFilePathLength];
+    int ret = 0;
+
+    if (config == NULL) return -1;
+
+    // d_type does not seems to be supported in /config
+    // so filtering by name.
+    while (((function = readdir(config)) != NULL)) {
+        if ((strstr(function->d_name, FUNCTION_NAME) == NULL)) continue;
+        // build the path for each file in the folder.
+        sprintf(filepath, "%s/%s", path, function->d_name);
+        ret = remove(filepath);
+        if (ret) {
+            ALOGE("Unable  remove file %s errno:%d", filepath, errno);
+            break;
+        }
+    }
+
+    closedir(config);
+    return ret;
+}
+
+int addEpollFd(const unique_fd& epfd, const unique_fd& fd) {
+    struct epoll_event event;
+    int ret;
+
+    event.data.fd = fd;
+    event.events = EPOLLIN;
+
+    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
+    if (ret) ALOGE("epoll_ctl error %d", errno);
+
+    return ret;
+}
+
+int linkFunction(const char* function, int index) {
+    char functionPath[kMaxFilePathLength];
+    char link[kMaxFilePathLength];
+
+    sprintf(functionPath, "%s%s", FUNCTIONS_PATH, function);
+    sprintf(link, "%s%d", FUNCTION_PATH, index);
+    if (symlink(functionPath, link)) {
+        ALOGE("Cannot create symlink %s -> %s errno:%d", link, functionPath, errno);
+        return -1;
+    }
+    return 0;
+}
+
+Status setVidPid(const char* vid, const char* pid) {
+    if (!WriteStringToFile(vid, VENDOR_ID_PATH)) return Status::ERROR;
+
+    if (!WriteStringToFile(pid, PRODUCT_ID_PATH)) return Status::ERROR;
+
+    return Status::SUCCESS;
+}
+
+std::string getVendorFunctions() {
+    if (GetProperty(kBuildType, "") == "user") return "user";
+
+    std::string bootMode = GetProperty(PERSISTENT_BOOT_MODE, "");
+    std::string persistVendorFunctions = GetProperty(kPersistentVendorConfig, "");
+    std::string vendorFunctions = GetProperty(kVendorConfig, "");
+    std::string ret = "";
+
+    if (vendorFunctions != "") {
+        ret = vendorFunctions;
+    } else if (bootMode == "usbradio" || bootMode == "factory" || bootMode == "ffbm-00" ||
+               bootMode == "ffbm-01") {
+        if (persistVendorFunctions != "")
+            ret = persistVendorFunctions;
+        else
+            ret = "diag";
+        // vendor.usb.config will reflect the current configured functions
+        SetProperty(kVendorConfig, ret);
+    }
+
+    return ret;
+}
+
+Status resetGadget() {
+    ALOGI("setCurrentUsbFunctions None");
+
+    if (!WriteStringToFile("none", PULLUP_PATH)) ALOGI("Gadget cannot be pulled down");
+
+    if (!WriteStringToFile("0", DEVICE_CLASS_PATH)) return Status::ERROR;
+
+    if (!WriteStringToFile("0", DEVICE_SUB_CLASS_PATH)) return Status::ERROR;
+
+    if (!WriteStringToFile("0", DEVICE_PROTOCOL_PATH)) return Status::ERROR;
+
+    if (!WriteStringToFile("0", DESC_USE_PATH)) return Status::ERROR;
+
+    if (unlinkFunctions(CONFIG_PATH)) return Status::ERROR;
+
+    return Status::SUCCESS;
+}
+
+Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
+                                  int* functionCount) {
+    if (((functions & GadgetFunction::MTP) != 0)) {
+        *ffsEnabled = true;
+        ALOGI("setCurrentUsbFunctions mtp");
+        if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
+
+        if (!monitorFfs->addInotifyFd("/dev/usb-ffs/mtp/")) return Status::ERROR;
+
+        if (linkFunction("ffs.mtp", (*functionCount)++)) return Status::ERROR;
+
+        // Add endpoints to be monitored.
+        monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep1");
+        monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep2");
+        monitorFfs->addEndPoint("/dev/usb-ffs/mtp/ep3");
+    } else if (((functions & GadgetFunction::PTP) != 0)) {
+        *ffsEnabled = true;
+        ALOGI("setCurrentUsbFunctions ptp");
+        if (!WriteStringToFile("1", DESC_USE_PATH)) return Status::ERROR;
+
+        if (!monitorFfs->addInotifyFd("/dev/usb-ffs/ptp/")) return Status::ERROR;
+
+        if (linkFunction("ffs.ptp", (*functionCount)++)) return Status::ERROR;
+
+        // Add endpoints to be monitored.
+        monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep1");
+        monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep2");
+        monitorFfs->addEndPoint("/dev/usb-ffs/ptp/ep3");
+    }
+
+    if ((functions & GadgetFunction::MIDI) != 0) {
+        ALOGI("setCurrentUsbFunctions MIDI");
+        if (linkFunction("midi.gs5", (*functionCount)++)) return Status::ERROR;
+    }
+
+    if ((functions & GadgetFunction::ACCESSORY) != 0) {
+        ALOGI("setCurrentUsbFunctions Accessory");
+        if (linkFunction("accessory.gs2", (*functionCount)++)) return Status::ERROR;
+    }
+
+    if ((functions & GadgetFunction::AUDIO_SOURCE) != 0) {
+        ALOGI("setCurrentUsbFunctions Audio Source");
+        if (linkFunction("audio_source.gs3", (*functionCount)++)) return Status::ERROR;
+    }
+
+    if ((functions & GadgetFunction::RNDIS) != 0) {
+        ALOGI("setCurrentUsbFunctions rndis");
+        if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
+    }
+
+    return Status::SUCCESS;
+}
+
+Status addAdb(MonitorFfs* monitorFfs, int* functionCount) {
+    ALOGI("setCurrentUsbFunctions Adb");
+    if (!monitorFfs->addInotifyFd("/dev/usb-ffs/adb/")) return Status::ERROR;
+
+    if (linkFunction("ffs.adb", (*functionCount)++)) return Status::ERROR;
+    monitorFfs->addEndPoint("/dev/usb-ffs/adb/ep1");
+    monitorFfs->addEndPoint("/dev/usb-ffs/adb/ep2");
+    ALOGI("Service started");
+    return Status::SUCCESS;
+}
+
+}  // namespace gadget
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
diff --git a/usb/gadget/1.1/default/lib/include/UsbGadgetCommon.h b/usb/gadget/1.1/default/lib/include/UsbGadgetCommon.h
new file mode 100644
index 0000000..b30f18e
--- /dev/null
+++ b/usb/gadget/1.1/default/lib/include/UsbGadgetCommon.h
@@ -0,0 +1,177 @@
+/*
+ * 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 HARDWARE_USB_USBGADGETCOMMON_H
+#define HARDWARE_USB_USBGADGETCOMMON_H
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+
+#include <android/hardware/usb/gadget/1.1/IUsbGadget.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+constexpr int kBufferSize = 512;
+constexpr int kMaxFilePathLength = 256;
+constexpr int kEpollEvents = 10;
+constexpr bool kDebug = false;
+constexpr int kDisconnectWaitUs = 100000;
+constexpr int kPullUpDelay = 500000;
+constexpr int kShutdownMonitor = 100;
+
+constexpr char kBuildType[] = "ro.build.type";
+constexpr char kPersistentVendorConfig[] = "persist.vendor.usb.usbradio.config";
+constexpr char kVendorConfig[] = "vendor.usb.config";
+
+#define GADGET_PATH "/config/usb_gadget/g1/"
+#define PULLUP_PATH GADGET_PATH "UDC"
+#define PERSISTENT_BOOT_MODE "ro.bootmode"
+#define VENDOR_ID_PATH GADGET_PATH "idVendor"
+#define PRODUCT_ID_PATH GADGET_PATH "idProduct"
+#define DEVICE_CLASS_PATH GADGET_PATH "bDeviceClass"
+#define DEVICE_SUB_CLASS_PATH GADGET_PATH "bDeviceSubClass"
+#define DEVICE_PROTOCOL_PATH GADGET_PATH "bDeviceProtocol"
+#define DESC_USE_PATH GADGET_PATH "os_desc/use"
+#define OS_DESC_PATH GADGET_PATH "os_desc/b.1"
+#define CONFIG_PATH GADGET_PATH "configs/b.1/"
+#define FUNCTIONS_PATH GADGET_PATH "functions/"
+#define FUNCTION_NAME "function"
+#define FUNCTION_PATH CONFIG_PATH FUNCTION_NAME
+#define RNDIS_PATH FUNCTIONS_PATH "gsi.rndis"
+
+using ::android::base::GetProperty;
+using ::android::base::SetProperty;
+using ::android::base::unique_fd;
+using ::android::base::WriteStringToFile;
+using ::android::hardware::usb::gadget::V1_0::GadgetFunction;
+using ::android::hardware::usb::gadget::V1_0::Status;
+
+using ::std::lock_guard;
+using ::std::move;
+using ::std::mutex;
+using ::std::string;
+using ::std::thread;
+using ::std::unique_ptr;
+using ::std::vector;
+using ::std::chrono::microseconds;
+using ::std::chrono::steady_clock;
+using ::std::literals::chrono_literals::operator""ms;
+
+// MonitorFfs automously manages gadget pullup by monitoring
+// the ep file status. Restarts the usb gadget when the ep
+// owner restarts.
+class MonitorFfs {
+  private:
+    // Monitors the endpoints Inotify events.
+    unique_fd mInotifyFd;
+    // Control pipe for shutting down the mMonitor thread.
+    // mMonitor exits when SHUTDOWN_MONITOR is written into
+    // mEventFd/
+    unique_fd mEventFd;
+    // Pools on mInotifyFd and mEventFd.
+    unique_fd mEpollFd;
+    vector<int> mWatchFd;
+
+    // Maintains the list of Endpoints.
+    vector<string> mEndpointList;
+    // protects the CV.
+    std::mutex mLock;
+    std::condition_variable mCv;
+    // protects mInotifyFd, mEpollFd.
+    std::mutex mLockFd;
+
+    // Flag to maintain the current status of gadget pullup.
+    bool mCurrentUsbFunctionsApplied;
+
+    // Thread object that executes the ep monitoring logic.
+    unique_ptr<thread> mMonitor;
+    // Callback to be invoked when gadget is pulled up.
+    void (*mCallback)(bool functionsApplied, void* payload);
+    void* mPayload;
+    // Name of the USB gadget. Used for pullup.
+    const char* const mGadgetName;
+    // Monitor State
+    bool mMonitorRunning;
+
+  public:
+    MonitorFfs(const char* const gadget);
+    // Inits all the UniqueFds.
+    void reset();
+    // Starts monitoring endpoints and pullup the gadget when
+    // the descriptors are written.
+    bool startMonitor();
+    // Waits for timeout_ms for gadget pull up to happen.
+    // Returns immediately if the gadget is already pulled up.
+    bool waitForPullUp(int timeout_ms);
+    // Adds the given fd to the watch list.
+    bool addInotifyFd(string fd);
+    // Adds the given endpoint to the watch list.
+    void addEndPoint(string ep);
+    // Registers the async callback from the caller to notify the caller
+    // when the gadget pull up happens.
+    void registerFunctionsAppliedCallback(void (*callback)(bool functionsApplied, void*(payload)),
+                                          void* payload);
+    bool isMonitorRunning();
+    // Ep monitoring and the gadget pull up logic.
+    static void* startMonitorFd(void* param);
+};
+
+//**************** Helper functions ************************//
+
+// Adds the given fd to the epollfd(epfd).
+int addEpollFd(const unique_fd& epfd, const unique_fd& fd);
+// Removes all the usb functions link in the specified path.
+int unlinkFunctions(const char* path);
+// Craetes a configfs link for the function.
+int linkFunction(const char* function, int index);
+// Sets the USB VID and PID.
+Status setVidPid(const char* vid, const char* pid);
+// Extracts vendor functions from the vendor init properties.
+std::string getVendorFunctions();
+// Adds Adb to the usb configuration.
+Status addAdb(MonitorFfs* monitorFfs, int* functionCount);
+// Adds all applicable generic android usb functions other than ADB.
+Status addGenericAndroidFunctions(MonitorFfs* monitorFfs, uint64_t functions, bool* ffsEnabled,
+                                  int* functionCount);
+// Pulls down USB gadget.
+Status resetGadget();
+
+}  // namespace gadget
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
+#endif
diff --git a/usb/gadget/1.1/default/service.cpp b/usb/gadget/1.1/default/service.cpp
new file mode 100644
index 0000000..7414e89
--- /dev/null
+++ b/usb/gadget/1.1/default/service.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.usb.gadget@1.1-service"
+
+#include <hidl/HidlTransportSupport.h>
+#include "UsbGadget.h"
+
+using android::sp;
+
+// libhwbinder:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::usb::gadget::V1_1::IUsbGadget;
+using android::hardware::usb::gadget::V1_1::implementation::UsbGadget;
+
+using android::OK;
+using android::status_t;
+
+int main() {
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    android::sp<IUsbGadget> service2 = new UsbGadget();
+
+    status_t status = service2->registerAsService();
+
+    if (status != OK) {
+        ALOGE("Cannot register USB Gadget HAL service");
+        return 1;
+    }
+
+    ALOGI("USB Gadget HAL Ready.");
+    joinRpcThreadpool();
+    // Under noraml cases, execution will not reach this line.
+    ALOGI("USB Gadget HAL failed to join thread pool.");
+    return 1;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
index 84556b5..406a899 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
@@ -23,6 +23,9 @@
     /* Period of silence preceding primitive. */
     int delayMs;
     CompositePrimitive primitive;
-    /* 0.0 (exclusive) - 1.0 (inclusive) */
+    /*
+     * 0.0 (inclusive) - 1.0 (inclusive),
+     * where 0.0 is minimum "feelable" amplitude.
+     */
     float scale;
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
index 0fdfa5d..8e82db0 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -21,37 +21,53 @@
 enum CompositePrimitive {
     /**
      * No haptic effect. Used to generate extended delays between primitives.
+     *
+     * Support is required.
      */
     NOOP,
     /**
      * This effect should produce a sharp, crisp click sensation.
+     *
+     * Support is required.
      */
     CLICK,
     /**
      * A haptic effect that simulates downwards movement with gravity. Often
      * followed by extra energy of hitting and reverberation to augment
      * physicality.
+     *
+     * Support is optional.
      */
     THUD,
     /**
      * A haptic effect that simulates spinning momentum.
+     *
+     * Support is optional.
      */
     SPIN,
     /**
      * A haptic effect that simulates quick upward movement against gravity.
+     *
+     * Support is required.
      */
     QUICK_RISE,
     /**
      * A haptic effect that simulates slow upward movement against gravity.
+     *
+     * Support is required.
      */
     SLOW_RISE,
     /**
      * A haptic effect that simulates quick downwards movement with gravity.
+     *
+     * Support is required.
      */
     QUICK_FALL,
     /**
      * This very short effect should produce a light crisp sensation intended
      * to be used repetitively for dynamic feedback.
+     *
+     * Support is required.
      */
     LIGHT_TICK,
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index 6489c1d..0b21248 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -161,8 +161,8 @@
      * List of supported effect primitive.
      *
      * Return the effect primitives which are supported by the compose API.
-     * Implementations are expected to support all primitives of the interface
-     * version that they implement.
+     * Implementations are expected to support all required primitives of the
+     * interface version that they implement (see primitive definitions).
      */
     CompositePrimitive[] getSupportedPrimitives();
 
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 1a8fd3b..c446afd 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -146,7 +146,7 @@
         if (e.delayMs > kComposeDelayMaxMs) {
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
-        if (e.scale <= 0.0f || e.scale > 1.0f) {
+        if (e.scale < 0.0f || e.scale > 1.0f) {
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
         if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 22d50f9..888a403 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -21,6 +21,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 
+#include <cmath>
 #include <future>
 
 using android::ProcessState;
@@ -54,6 +55,11 @@
         android::enum_range<CompositePrimitive>().begin(),
         android::enum_range<CompositePrimitive>().end()};
 
+const std::vector<CompositePrimitive> kOptionalPrimitives = {
+        CompositePrimitive::THUD,
+        CompositePrimitive::SPIN,
+};
+
 const std::vector<CompositePrimitive> kInvalidPrimitives = {
         static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
         static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
@@ -129,7 +135,6 @@
             } else {
                 EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
                         << toString(effect) << " " << toString(strength);
-                EXPECT_EQ(lengthMs, 0);
             }
         }
     }
@@ -158,7 +163,6 @@
                 EXPECT_GT(lengthMs, 0);
             } else {
                 EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
-                EXPECT_EQ(lengthMs, 0);
             }
 
             if (!status.isOk()) continue;
@@ -178,7 +182,6 @@
             int lengthMs;
             Status status = vibrator->perform(effect, strength, callback, &lengthMs);
             EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
-            EXPECT_EQ(lengthMs, 0);
         }
     }
 }
@@ -268,38 +271,56 @@
 
         EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());
 
-        std::sort(supported.begin(), supported.end());
+        for (auto primitive : kCompositePrimitives) {
+            bool isPrimitiveSupported =
+                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
+            bool isPrimitiveOptional =
+                    std::find(kOptionalPrimitives.begin(), kOptionalPrimitives.end(), primitive) !=
+                    kOptionalPrimitives.end();
 
-        EXPECT_EQ(kCompositePrimitives, supported);
+            EXPECT_TRUE(isPrimitiveSupported || isPrimitiveOptional) << toString(primitive);
+        }
     }
 }
 
 TEST_P(VibratorAidl, GetPrimitiveDuration) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
-        int32_t duration;
+        std::vector<CompositePrimitive> supported;
+        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
 
         for (auto primitive : kCompositePrimitives) {
-            EXPECT_EQ(Status::EX_NONE,
-                      vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode());
+            bool isPrimitiveSupported =
+                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
+            int32_t duration;
+
+            Status status = vibrator->getPrimitiveDuration(primitive, &duration);
+
+            if (isPrimitiveSupported) {
+                EXPECT_EQ(Status::EX_NONE, status.exceptionCode());
+            } else {
+                EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
+            }
         }
     }
 }
 
 TEST_P(VibratorAidl, ComposeValidPrimitives) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        std::vector<CompositePrimitive> supported;
         int32_t maxDelay, maxSize;
 
+        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
         EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
         EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
 
         std::vector<CompositeEffect> composite;
 
-        for (auto primitive : kCompositePrimitives) {
+        for (auto primitive : supported) {
             CompositeEffect effect;
 
             effect.delayMs = std::rand() % (maxDelay + 1);
             effect.primitive = primitive;
-            effect.scale = static_cast<float>(std::rand()) / RAND_MAX ?: 1.0f;
+            effect.scale = static_cast<float>(std::rand()) / RAND_MAX;
             composite.emplace_back(effect);
 
             if (composite.size() == maxSize) {
@@ -318,7 +339,21 @@
 
 TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
-        for (auto primitive : kInvalidPrimitives) {
+        auto unsupported = kInvalidPrimitives;
+        std::vector<CompositePrimitive> supported;
+
+        ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
+
+        for (auto primitive : kCompositePrimitives) {
+            bool isPrimitiveSupported =
+                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
+
+            if (!isPrimitiveSupported) {
+                unsupported.push_back(primitive);
+            }
+        }
+
+        for (auto primitive : unsupported) {
             std::vector<CompositeEffect> composite(1);
 
             for (auto& effect : composite) {
@@ -333,7 +368,33 @@
     }
 }
 
-TEST_P(VibratorAidl, CompseDelayBoundary) {
+TEST_P(VibratorAidl, ComposeScaleBoundary) {
+    if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+        std::vector<CompositeEffect> composite(1);
+        CompositeEffect& effect = composite[0];
+
+        effect.delayMs = 0;
+        effect.primitive = CompositePrimitive::CLICK;
+
+        effect.scale = std::nextafter(0.0f, -1.0f);
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->compose(composite, nullptr).exceptionCode());
+
+        effect.scale = 0.0f;
+        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+
+        effect.scale = 1.0f;
+        EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+
+        effect.scale = std::nextafter(1.0f, 2.0f);
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->compose(composite, nullptr).exceptionCode());
+
+        vibrator->off();
+    }
+}
+
+TEST_P(VibratorAidl, ComposeDelayBoundary) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
         int32_t maxDelay;
 
@@ -358,7 +419,7 @@
     }
 }
 
-TEST_P(VibratorAidl, CompseSizeBoundary) {
+TEST_P(VibratorAidl, ComposeSizeBoundary) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
         int32_t maxSize;
 
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 95bb59c..14a8509 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -23,14 +23,14 @@
         "wifi_hidl_test_utils.cpp",
     ],
     export_include_dirs: [
-        "."
+        ".",
     ],
     shared_libs: [
         "libnativehelper",
     ],
     static_libs: [
         "android.hardware.wifi@1.0",
-        "libwifi-system-iface"
+        "libwifi-system-iface",
     ],
 }
 
@@ -38,8 +38,6 @@
     name: "VtsHalWifiV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiV1_0TargetTest.cpp",
-        "wifi_ap_iface_hidl_test.cpp",
         "wifi_chip_hidl_test.cpp",
         "wifi_p2p_iface_hidl_test.cpp",
         "wifi_rtt_controller_hidl_test.cpp",
@@ -51,22 +49,50 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
-        "libwifi-system-iface"
+        "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
 
+// These tests are split out so that they can be conditioned on presence of the
+// "android.hardware.wifi.aware" feature.
 cc_test {
     name: "VtsHalWifiNanV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiV1_0TargetTest.cpp",
+        "wifi_chip_hidl_nan_test.cpp",
         "wifi_nan_iface_hidl_test.cpp",
     ],
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
         "android.hardware.wifi@1.0",
-        "libwifi-system-iface"
+        "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+// These tests are split out so that they can be conditioned on presence of
+// the hostapd HAL, which indicates SoftAP support.
+cc_test {
+    name: "VtsHalWifiApV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "wifi_ap_iface_hidl_test.cpp",
+        "wifi_chip_hidl_ap_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
deleted file mode 100644
index e7b8593..0000000
--- a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "wifi_hidl_test_utils.h"
-
-class WifiVtsHidlEnvironment_1_0 : public WifiHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiVtsHidlEnvironment_1_0* Instance() {
-        static WifiVtsHidlEnvironment_1_0* instance =
-            new WifiVtsHidlEnvironment_1_0;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<android::hardware::wifi::V1_0::IWifi>();
-    }
-
-   private:
-    WifiVtsHidlEnvironment_1_0() {}
-};
-
-WifiHidlEnvironment* gEnv = WifiVtsHidlEnvironment_1_0::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        status = RUN_ALL_TESTS();
-        LOG(INFO) << "Test result = " << status;
-    }
-    return status;
-}
diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
index e5762f2..3599b94 100644
--- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -16,39 +16,40 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiApIface.h>
-
-#include <VtsHalHidlTargetTestBase.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::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiApIface;
 using ::android::hardware::wifi::V1_0::WifiBand;
 using ::android::hardware::wifi::V1_0::WifiStatusCode;
-using ::android::sp;
-
-extern WifiHidlEnvironment* gEnv;
 
 /**
  * Fixture to use for all AP Iface HIDL interface tests.
  */
-class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        if (!gEnv->isSoftApOn) return;
-        wifi_ap_iface_ = getWifiApIface();
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_ap_iface_ = getWifiApIface(GetInstanceName());
         ASSERT_NE(nullptr, wifi_ap_iface_.get());
     }
 
-    virtual void TearDown() override {
-        if (!gEnv->isSoftApOn) return;
-        stopWifi();
-    }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     sp<IWifiApIface> wifi_ap_iface_;
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -56,18 +57,15 @@
  * Ensures that an instance of the IWifiApIface proxy object is
  * successfully created.
  */
-TEST(WifiApIfaceHidlTestNoFixture, Create) {
-    if (!gEnv->isSoftApOn) return;
-    EXPECT_NE(nullptr, getWifiApIface().get());
-    stopWifi();
+TEST_P(WifiApIfaceHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
 
 /*
  * GetType:
  * Ensures that the correct interface type is returned for AP interface.
  */
-TEST_F(WifiApIfaceHidlTest, GetType) {
-    if (!gEnv->isSoftApOn) return;
+TEST_P(WifiApIfaceHidlTest, GetType) {
     const auto& status_and_type = HIDL_INVOKE(wifi_ap_iface_, getType);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code);
     EXPECT_EQ(IfaceType::AP, status_and_type.second);
@@ -78,8 +76,7 @@
  * Ensures that a call to set the country code will return with a success
  * status code.
  */
-TEST_F(WifiApIfaceHidlTest, SetCountryCode) {
-    if (!gEnv->isSoftApOn) return;
+TEST_P(WifiApIfaceHidlTest, SetCountryCode) {
     const android::hardware::hidl_array<int8_t, 2> kCountryCode{
         std::array<int8_t, 2>{{0x55, 0x53}}};
     EXPECT_EQ(WifiStatusCode::SUCCESS,
@@ -90,10 +87,15 @@
  * GetValidFrequenciesForBand:
  * Ensures that we can retrieve valid frequencies for 2.4 GHz band.
  */
-TEST_F(WifiApIfaceHidlTest, GetValidFrequenciesForBand) {
-    if (!gEnv->isSoftApOn) return;
+TEST_P(WifiApIfaceHidlTest, GetValidFrequenciesForBand) {
     const auto& status_and_freqs = HIDL_INVOKE(
         wifi_ap_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code);
     EXPECT_GT(status_and_freqs.second.size(), 0u);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiApIfaceHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
new file mode 100644
index 0000000..5a2c6a7
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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 <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.0/IWifiChip.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::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiApIface;
+using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::V1_0::IWifiIface;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+
+/**
+ * Fixture for IWifiChip tests that are conditioned on SoftAP support.
+ */
+class WifiChipHidlApTest : public ::testing::TestWithParam<std::string> {
+   public:
+    virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_chip_ = getWifiChip(GetInstanceName());
+        ASSERT_NE(nullptr, wifi_chip_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+   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;
+    }
+
+    std::string getIfaceName(const sp<IWifiIface>& iface) {
+        const auto& status_and_name = HIDL_INVOKE(iface, getName);
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_name.first.code);
+        return status_and_name.second;
+    }
+
+    WifiStatusCode createApIface(sp<IWifiApIface>* ap_iface) {
+        const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createApIface);
+        *ap_iface = status_and_iface.second;
+        return status_and_iface.first.code;
+    }
+
+    WifiStatusCode removeApIface(const std::string& name) {
+        return HIDL_INVOKE(wifi_chip_, removeApIface, name).code;
+    }
+
+    sp<IWifiChip> wifi_chip_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * CreateApIface
+ * Configures the chip in AP mode and ensures that at least 1 iface creation
+ * succeeds.
+ */
+TEST_P(WifiChipHidlApTest, CreateApIface) {
+    configureChipForIfaceType(IfaceType::AP, true);
+
+    sp<IWifiApIface> iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
+    EXPECT_NE(nullptr, iface.get());
+}
+
+/*
+ * GetApIfaceNames
+ * Configures the chip in AP mode and ensures that the iface list is empty
+ * before creating the iface. Then, create the iface and ensure that
+ * iface name is returned via the list.
+ */
+TEST_P(WifiChipHidlApTest, GetApIfaceNames) {
+    configureChipForIfaceType(IfaceType::AP, true);
+
+    const auto& status_and_iface_names1 =
+        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
+    EXPECT_EQ(0u, status_and_iface_names1.second.size());
+
+    sp<IWifiApIface> iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
+    EXPECT_NE(nullptr, iface.get());
+
+    std::string iface_name = getIfaceName(iface);
+    const auto& status_and_iface_names2 =
+        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
+    EXPECT_EQ(1u, status_and_iface_names2.second.size());
+    EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
+
+    EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
+    const auto& status_and_iface_names3 =
+        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
+    EXPECT_EQ(0u, status_and_iface_names3.second.size());
+}
+
+/*
+ * GetApIface
+ * Configures the chip in AP mode and create an iface. Then, retrieve
+ * the iface object using the correct name and ensure any other name
+ * doesn't retrieve an iface object.
+ */
+TEST_P(WifiChipHidlApTest, GetApIface) {
+    configureChipForIfaceType(IfaceType::AP, true);
+
+    sp<IWifiApIface> ap_iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
+    EXPECT_NE(nullptr, ap_iface.get());
+
+    std::string iface_name = getIfaceName(ap_iface);
+    const auto& status_and_iface1 =
+        HIDL_INVOKE(wifi_chip_, getApIface, iface_name);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
+    EXPECT_NE(nullptr, status_and_iface1.second.get());
+
+    std::string invalid_name = iface_name + "0";
+    const auto& status_and_iface2 =
+        HIDL_INVOKE(wifi_chip_, getApIface, invalid_name);
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
+    EXPECT_EQ(nullptr, status_and_iface2.second.get());
+}
+
+/*
+ * RemoveApIface
+ * Configures the chip in AP mode and create an iface. Then, remove
+ * the iface object using the correct name and ensure any other name
+ * doesn't remove the iface.
+ */
+TEST_P(WifiChipHidlApTest, RemoveApIface) {
+    configureChipForIfaceType(IfaceType::AP, true);
+
+    sp<IWifiApIface> ap_iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
+    EXPECT_NE(nullptr, ap_iface.get());
+
+    std::string iface_name = getIfaceName(ap_iface);
+    std::string invalid_name = iface_name + "0";
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(invalid_name));
+    EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
+
+    // No such iface exists now. So, this should return failure.
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlApTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
new file mode 100644
index 0000000..bb7a3a6
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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 <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.0/IWifiChip.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::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::V1_0::IWifiIface;
+using ::android::hardware::wifi::V1_0::IWifiNanIface;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+
+/**
+ * Fixture for IWifiChip tests that are conditioned on NAN support.
+ */
+class WifiChipHidlNanTest : public ::testing::TestWithParam<std::string> {
+   public:
+    virtual void SetUp() override {
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.aware"))
+            GTEST_SKIP() << "Skipping this test since NAN is not supported.";
+
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_chip_ = getWifiChip(GetInstanceName());
+        ASSERT_NE(nullptr, wifi_chip_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+   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;
+    }
+
+    std::string getIfaceName(const sp<IWifiIface>& iface) {
+        const auto& status_and_name = HIDL_INVOKE(iface, getName);
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_name.first.code);
+        return status_and_name.second;
+    }
+
+    WifiStatusCode createNanIface(sp<IWifiNanIface>* nan_iface) {
+        const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createNanIface);
+        *nan_iface = status_and_iface.second;
+        return status_and_iface.first.code;
+    }
+
+    WifiStatusCode removeNanIface(const std::string& name) {
+        return HIDL_INVOKE(wifi_chip_, removeNanIface, name).code;
+    }
+
+    sp<IWifiChip> wifi_chip_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * CreateNanIface
+ * Configures the chip in NAN mode and ensures that at least 1 iface creation
+ * succeeds.
+ */
+TEST_P(WifiChipHidlNanTest, CreateNanIface) {
+    configureChipForIfaceType(IfaceType::NAN, true);
+
+    sp<IWifiNanIface> iface;
+    ASSERT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
+    EXPECT_NE(nullptr, iface.get());
+}
+
+/*
+ * GetNanIfaceNames
+ * Configures the chip in NAN mode and ensures that the iface list is empty
+ * before creating the iface. Then, create the iface and ensure that
+ * iface name is returned via the list.
+ */
+TEST_P(WifiChipHidlNanTest, GetNanIfaceNames) {
+    configureChipForIfaceType(IfaceType::NAN, true);
+
+    const auto& status_and_iface_names1 =
+        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
+    ASSERT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
+    EXPECT_EQ(0u, status_and_iface_names1.second.size());
+
+    sp<IWifiNanIface> iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
+    EXPECT_NE(nullptr, iface.get());
+
+    std::string iface_name = getIfaceName(iface);
+    const auto& status_and_iface_names2 =
+        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
+    EXPECT_EQ(1u, status_and_iface_names2.second.size());
+    EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
+
+    EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
+    const auto& status_and_iface_names3 =
+        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
+    EXPECT_EQ(0u, status_and_iface_names3.second.size());
+}
+
+/*
+ * GetNanIface
+ * Configures the chip in NAN mode and create an iface. Then, retrieve
+ * the iface object using the correct name and ensure any other name
+ * doesn't retrieve an iface object.
+ */
+TEST_P(WifiChipHidlNanTest, GetNanIface) {
+    configureChipForIfaceType(IfaceType::NAN, true);
+
+    sp<IWifiNanIface> nan_iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
+    EXPECT_NE(nullptr, nan_iface.get());
+
+    std::string iface_name = getIfaceName(nan_iface);
+    const auto& status_and_iface1 =
+        HIDL_INVOKE(wifi_chip_, getNanIface, iface_name);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
+    EXPECT_NE(nullptr, status_and_iface1.second.get());
+
+    std::string invalid_name = iface_name + "0";
+    const auto& status_and_iface2 =
+        HIDL_INVOKE(wifi_chip_, getNanIface, invalid_name);
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
+    EXPECT_EQ(nullptr, status_and_iface2.second.get());
+}
+
+/*
+ * RemoveNanIface
+ * Configures the chip in NAN mode and create an iface. Then, remove
+ * the iface object using the correct name and ensure any other name
+ * doesn't remove the iface.
+ */
+TEST_P(WifiChipHidlNanTest, RemoveNanIface) {
+    configureChipForIfaceType(IfaceType::NAN, true);
+
+    sp<IWifiNanIface> nan_iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
+    EXPECT_NE(nullptr, nan_iface.get());
+
+    std::string iface_name = getIfaceName(nan_iface);
+    std::string invalid_name = iface_name + "0";
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(invalid_name));
+
+    EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
+
+    // No such iface exists now. So, this should return failure.
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlNanTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
index 1b7e821..53131ce 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -16,10 +16,12 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiChip.h>
 #include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.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"
@@ -27,23 +29,20 @@
 using ::android::sp;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
-using ::android::hardware::wifi::V1_0::IfaceType;
 using ::android::hardware::wifi::V1_0::ChipId;
 using ::android::hardware::wifi::V1_0::ChipModeId;
-using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus;
-using ::android::hardware::wifi::V1_0::WifiDebugRingBufferVerboseLevel;
-using ::android::hardware::wifi::V1_0::WifiDebugHostWakeReasonStats;
-using ::android::hardware::wifi::V1_0::WifiStatus;
-using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiChip;
-using ::android::hardware::wifi::V1_0::IWifiApIface;
 using ::android::hardware::wifi::V1_0::IWifiIface;
-using ::android::hardware::wifi::V1_0::IWifiNanIface;
 using ::android::hardware::wifi::V1_0::IWifiP2pIface;
 using ::android::hardware::wifi::V1_0::IWifiRttController;
 using ::android::hardware::wifi::V1_0::IWifiStaIface;
-
-extern WifiHidlEnvironment* gEnv;
+using ::android::hardware::wifi::V1_0::WifiDebugHostWakeReasonStats;
+using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus;
+using ::android::hardware::wifi::V1_0::WifiDebugRingBufferVerboseLevel;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
 
 namespace {
 constexpr WifiDebugRingBufferVerboseLevel kDebugRingBufferVerboseLvl =
@@ -64,16 +63,22 @@
 }  // namespace
 
 /**
- * Fixture to use for all Wifi chip HIDL interface tests.
+ * Fixture for IWifiChip tests.
+ *
+ * Tests that require SoftAP or NAN support should go into WifiChipHidlApTest or
+ * WifiChipHidlNanTest respectively.
  */
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_chip_ = getWifiChip();
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_chip_ = getWifiChip(GetInstanceName());
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     // Helper function to configure the Chip in one of the supported modes.
@@ -114,26 +119,6 @@
         return status_and_name.second;
     }
 
-    WifiStatusCode createApIface(sp<IWifiApIface>* ap_iface) {
-        const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createApIface);
-        *ap_iface = status_and_iface.second;
-        return status_and_iface.first.code;
-    }
-
-    WifiStatusCode removeApIface(const std::string& name) {
-        return HIDL_INVOKE(wifi_chip_, removeApIface, name).code;
-    }
-
-    WifiStatusCode createNanIface(sp<IWifiNanIface>* nan_iface) {
-        const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createNanIface);
-        *nan_iface = status_and_iface.second;
-        return status_and_iface.first.code;
-    }
-
-    WifiStatusCode removeNanIface(const std::string& name) {
-        return HIDL_INVOKE(wifi_chip_, removeNanIface, name).code;
-    }
-
     WifiStatusCode createP2pIface(sp<IWifiP2pIface>* p2p_iface) {
         const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createP2pIface);
         *p2p_iface = status_and_iface.second;
@@ -155,6 +140,9 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -162,15 +150,14 @@
  * Ensures that an instance of the IWifiChip proxy object is
  * successfully created.
  */
-TEST(WifiChipHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiChip().get());
-    stopWifi();
+TEST_P(WifiChipHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
 
 /*
  * GetId:
  */
-TEST_F(WifiChipHidlTest, GetId) {
+TEST_P(WifiChipHidlTest, GetId) {
     EXPECT_EQ(WifiStatusCode::SUCCESS,
               HIDL_INVOKE(wifi_chip_, getId).first.code);
 }
@@ -178,7 +165,7 @@
 /*
  * GetAvailableMode:
  */
-TEST_F(WifiChipHidlTest, GetAvailableModes) {
+TEST_P(WifiChipHidlTest, GetAvailableModes) {
     const auto& status_and_modes = HIDL_INVOKE(wifi_chip_, getAvailableModes);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_modes.first.code);
     EXPECT_LT(0u, status_and_modes.second.size());
@@ -187,17 +174,17 @@
 /*
  * ConfigureChip:
  */
-TEST_F(WifiChipHidlTest, ConfigureChip) {
+TEST_P(WifiChipHidlTest, ConfigureChip) {
     const auto& status_and_modes = HIDL_INVOKE(wifi_chip_, getAvailableModes);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_modes.first.code);
     EXPECT_LT(0u, status_and_modes.second.size());
     for (const auto& mode : status_and_modes.second) {
         // configureChip() requires to be called with a fresh IWifiChip object.
-        wifi_chip_ = getWifiChip();
+        wifi_chip_ = getWifiChip(GetInstanceName());
         ASSERT_NE(nullptr, wifi_chip_.get());
         EXPECT_EQ(WifiStatusCode::SUCCESS,
                   HIDL_INVOKE(wifi_chip_, configureChip, mode.id).code);
-        stopWifi();
+        stopWifi(GetInstanceName());
         // Sleep for 5 milliseconds between each wifi state toggle.
         usleep(5000);
     }
@@ -206,7 +193,7 @@
 /*
  * GetCapabilities:
  */
-TEST_F(WifiChipHidlTest, GetCapabilities) {
+TEST_P(WifiChipHidlTest, GetCapabilities) {
     configureChipForIfaceType(IfaceType::STA, true);
     const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities);
     if (status_and_caps.first.code != WifiStatusCode::SUCCESS) {
@@ -219,7 +206,7 @@
 /*
  * GetMode:
  */
-TEST_F(WifiChipHidlTest, GetMode) {
+TEST_P(WifiChipHidlTest, GetMode) {
     ChipModeId chip_mode_id = configureChipForIfaceType(IfaceType::STA, true);
     const auto& status_and_mode = HIDL_INVOKE(wifi_chip_, getMode);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mode.first.code);
@@ -229,7 +216,7 @@
 /*
  * RequestChipDebugInfo:
  */
-TEST_F(WifiChipHidlTest, RequestChipDebugInfo) {
+TEST_P(WifiChipHidlTest, RequestChipDebugInfo) {
     configureChipForIfaceType(IfaceType::STA, true);
     const auto& status_and_chip_info =
         HIDL_INVOKE(wifi_chip_, requestChipDebugInfo);
@@ -241,7 +228,7 @@
 /*
  * RequestFirmwareDebugDump
  */
-TEST_F(WifiChipHidlTest, RequestFirmwareDebugDump) {
+TEST_P(WifiChipHidlTest, RequestFirmwareDebugDump) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status_and_firmware_dump =
         HIDL_INVOKE(wifi_chip_, requestFirmwareDebugDump);
@@ -256,7 +243,7 @@
 /*
  * RequestDriverDebugDump
  */
-TEST_F(WifiChipHidlTest, RequestDriverDebugDump) {
+TEST_P(WifiChipHidlTest, RequestDriverDebugDump) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status_and_driver_dump =
         HIDL_INVOKE(wifi_chip_, requestDriverDebugDump);
@@ -273,7 +260,7 @@
 /*
  * GetDebugRingBuffersStatus
  */
-TEST_F(WifiChipHidlTest, GetDebugRingBuffersStatus) {
+TEST_P(WifiChipHidlTest, GetDebugRingBuffersStatus) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status_and_ring_buffer_status =
         HIDL_INVOKE(wifi_chip_, getDebugRingBuffersStatus);
@@ -292,7 +279,7 @@
 /*
  * StartLoggingToDebugRingBuffer
  */
-TEST_F(WifiChipHidlTest, StartLoggingToDebugRingBuffer) {
+TEST_P(WifiChipHidlTest, StartLoggingToDebugRingBuffer) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     std::string ring_name;
     const auto& status_and_ring_buffer_status =
@@ -320,7 +307,7 @@
 /*
  * ForceDumpToDebugRingBuffer
  */
-TEST_F(WifiChipHidlTest, ForceDumpToDebugRingBuffer) {
+TEST_P(WifiChipHidlTest, ForceDumpToDebugRingBuffer) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     std::string ring_name;
     const auto& status_and_ring_buffer_status =
@@ -346,7 +333,7 @@
 /*
  * GetDebugHostWakeReasonStats
  */
-TEST_F(WifiChipHidlTest, GetDebugHostWakeReasonStats) {
+TEST_P(WifiChipHidlTest, GetDebugHostWakeReasonStats) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status_and_debug_wake_reason =
         HIDL_INVOKE(wifi_chip_, getDebugHostWakeReasonStats);
@@ -360,206 +347,11 @@
 }
 
 /*
- * CreateApIface
- * Configures the chip in AP mode and ensures that at least 1 iface creation
- * succeeds.
- */
-TEST_F(WifiChipHidlTest, CreateApIface) {
-    if (!gEnv->isSoftApOn) return;
-    configureChipForIfaceType(IfaceType::AP, true);
-
-    sp<IWifiApIface> iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
-}
-
-/*
- * GetApIfaceNames
- * Configures the chip in AP mode and ensures that the iface list is empty
- * before creating the iface. Then, create the iface and ensure that
- * iface name is returned via the list.
- */
-TEST_F(WifiChipHidlTest, GetApIfaceNames) {
-    if (!gEnv->isSoftApOn) return;
-    configureChipForIfaceType(IfaceType::AP, true);
-
-    const auto& status_and_iface_names1 =
-        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
-    EXPECT_EQ(0u, status_and_iface_names1.second.size());
-
-    sp<IWifiApIface> iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
-
-    std::string iface_name = getIfaceName(iface);
-    const auto& status_and_iface_names2 =
-        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
-    EXPECT_EQ(1u, status_and_iface_names2.second.size());
-    EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
-
-    EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
-    const auto& status_and_iface_names3 =
-        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
-    EXPECT_EQ(0u, status_and_iface_names3.second.size());
-}
-
-/*
- * GetApIface
- * Configures the chip in AP mode and create an iface. Then, retrieve
- * the iface object using the correct name and ensure any other name
- * doesn't retrieve an iface object.
- */
-TEST_F(WifiChipHidlTest, GetApIface) {
-    if (!gEnv->isSoftApOn) return;
-    configureChipForIfaceType(IfaceType::AP, true);
-
-    sp<IWifiApIface> ap_iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
-    EXPECT_NE(nullptr, ap_iface.get());
-
-    std::string iface_name = getIfaceName(ap_iface);
-    const auto& status_and_iface1 =
-        HIDL_INVOKE(wifi_chip_, getApIface, iface_name);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
-    EXPECT_NE(nullptr, status_and_iface1.second.get());
-
-    std::string invalid_name = iface_name + "0";
-    const auto& status_and_iface2 =
-        HIDL_INVOKE(wifi_chip_, getApIface, invalid_name);
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
-    EXPECT_EQ(nullptr, status_and_iface2.second.get());
-}
-
-/*
- * RemoveApIface
- * Configures the chip in AP mode and create an iface. Then, remove
- * the iface object using the correct name and ensure any other name
- * doesn't remove the iface.
- */
-TEST_F(WifiChipHidlTest, RemoveApIface) {
-    if (!gEnv->isSoftApOn) return;
-    configureChipForIfaceType(IfaceType::AP, true);
-
-    sp<IWifiApIface> ap_iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
-    EXPECT_NE(nullptr, ap_iface.get());
-
-    std::string iface_name = getIfaceName(ap_iface);
-    std::string invalid_name = iface_name + "0";
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(invalid_name));
-    EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
-
-    // No such iface exists now. So, this should return failure.
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name));
-}
-
-/*
- * CreateNanIface
- * Configures the chip in NAN mode and ensures that at least 1 iface creation
- * succeeds.
- */
-TEST_F(WifiChipHidlTest, CreateNanIface) {
-    if (!gEnv->isNanOn) return;
-    configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
-    sp<IWifiNanIface> iface;
-    ASSERT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
-}
-
-/*
- * GetNanIfaceNames
- * Configures the chip in NAN mode and ensures that the iface list is empty
- * before creating the iface. Then, create the iface and ensure that
- * iface name is returned via the list.
- */
-TEST_F(WifiChipHidlTest, GetNanIfaceNames) {
-    if (!gEnv->isNanOn) return;
-    configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
-    const auto& status_and_iface_names1 =
-        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
-    ASSERT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
-    EXPECT_EQ(0u, status_and_iface_names1.second.size());
-
-    sp<IWifiNanIface> iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
-
-    std::string iface_name = getIfaceName(iface);
-    const auto& status_and_iface_names2 =
-        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
-    EXPECT_EQ(1u, status_and_iface_names2.second.size());
-    EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
-
-    EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
-    const auto& status_and_iface_names3 =
-        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
-    EXPECT_EQ(0u, status_and_iface_names3.second.size());
-}
-
-/*
- * GetNanIface
- * Configures the chip in NAN mode and create an iface. Then, retrieve
- * the iface object using the correct name and ensure any other name
- * doesn't retrieve an iface object.
- */
-TEST_F(WifiChipHidlTest, GetNanIface) {
-    if (!gEnv->isNanOn) return;
-    configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
-    sp<IWifiNanIface> nan_iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
-    EXPECT_NE(nullptr, nan_iface.get());
-
-    std::string iface_name = getIfaceName(nan_iface);
-    const auto& status_and_iface1 =
-        HIDL_INVOKE(wifi_chip_, getNanIface, iface_name);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
-    EXPECT_NE(nullptr, status_and_iface1.second.get());
-
-    std::string invalid_name = iface_name + "0";
-    const auto& status_and_iface2 =
-        HIDL_INVOKE(wifi_chip_, getNanIface, invalid_name);
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
-    EXPECT_EQ(nullptr, status_and_iface2.second.get());
-}
-
-/*
- * RemoveNanIface
- * Configures the chip in NAN mode and create an iface. Then, remove
- * the iface object using the correct name and ensure any other name
- * doesn't remove the iface.
- */
-TEST_F(WifiChipHidlTest, RemoveNanIface) {
-    if (!gEnv->isNanOn) return;
-    configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
-    sp<IWifiNanIface> nan_iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
-    EXPECT_NE(nullptr, nan_iface.get());
-
-    std::string iface_name = getIfaceName(nan_iface);
-    std::string invalid_name = iface_name + "0";
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(invalid_name));
-
-    EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
-
-    // No such iface exists now. So, this should return failure.
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name));
-}
-
-/*
  * CreateP2pIface
  * Configures the chip in P2P mode and ensures that at least 1 iface creation
  * succeeds.
  */
-TEST_F(WifiChipHidlTest, CreateP2pIface) {
+TEST_P(WifiChipHidlTest, CreateP2pIface) {
     configureChipForIfaceType(IfaceType::P2P, true);
 
     sp<IWifiP2pIface> iface;
@@ -573,7 +365,7 @@
  * before creating the iface. Then, create the iface and ensure that
  * iface name is returned via the list.
  */
-TEST_F(WifiChipHidlTest, GetP2pIfaceNames) {
+TEST_P(WifiChipHidlTest, GetP2pIfaceNames) {
     configureChipForIfaceType(IfaceType::P2P, true);
 
     const auto& status_and_iface_names1 =
@@ -583,7 +375,7 @@
 
     sp<IWifiP2pIface> iface;
     EXPECT_EQ(WifiStatusCode::SUCCESS, createP2pIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
+    ASSERT_NE(nullptr, iface.get());
 
     std::string iface_name = getIfaceName(iface);
     const auto& status_and_iface_names2 =
@@ -605,12 +397,12 @@
  * the iface object using the correct name and ensure any other name
  * doesn't retrieve an iface object.
  */
-TEST_F(WifiChipHidlTest, GetP2pIface) {
+TEST_P(WifiChipHidlTest, GetP2pIface) {
     configureChipForIfaceType(IfaceType::P2P, true);
 
     sp<IWifiP2pIface> p2p_iface;
     EXPECT_EQ(WifiStatusCode::SUCCESS, createP2pIface(&p2p_iface));
-    EXPECT_NE(nullptr, p2p_iface.get());
+    ASSERT_NE(nullptr, p2p_iface.get());
 
     std::string iface_name = getIfaceName(p2p_iface);
     const auto& status_and_iface1 =
@@ -631,12 +423,12 @@
  * the iface object using the correct name and ensure any other name
  * doesn't remove the iface.
  */
-TEST_F(WifiChipHidlTest, RemoveP2pIface) {
+TEST_P(WifiChipHidlTest, RemoveP2pIface) {
     configureChipForIfaceType(IfaceType::P2P, true);
 
     sp<IWifiP2pIface> p2p_iface;
     EXPECT_EQ(WifiStatusCode::SUCCESS, createP2pIface(&p2p_iface));
-    EXPECT_NE(nullptr, p2p_iface.get());
+    ASSERT_NE(nullptr, p2p_iface.get());
 
     std::string iface_name = getIfaceName(p2p_iface);
     std::string invalid_name = iface_name + "0";
@@ -652,7 +444,7 @@
  * Configures the chip in STA mode and ensures that at least 1 iface creation
  * succeeds.
  */
-TEST_F(WifiChipHidlTest, CreateStaIface) {
+TEST_P(WifiChipHidlTest, CreateStaIface) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     sp<IWifiStaIface> iface;
@@ -666,7 +458,7 @@
  * before creating the iface. Then, create the iface and ensure that
  * iface name is returned via the list.
  */
-TEST_F(WifiChipHidlTest, GetStaIfaceNames) {
+TEST_P(WifiChipHidlTest, GetStaIfaceNames) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     const auto& status_and_iface_names1 =
@@ -676,7 +468,7 @@
 
     sp<IWifiStaIface> iface;
     EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
+    ASSERT_NE(nullptr, iface.get());
 
     std::string iface_name = getIfaceName(iface);
     const auto& status_and_iface_names2 =
@@ -698,12 +490,12 @@
  * the iface object using the correct name and ensure any other name
  * doesn't retrieve an iface object.
  */
-TEST_F(WifiChipHidlTest, GetStaIface) {
+TEST_P(WifiChipHidlTest, GetStaIface) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     sp<IWifiStaIface> sta_iface;
     EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&sta_iface));
-    EXPECT_NE(nullptr, sta_iface.get());
+    ASSERT_NE(nullptr, sta_iface.get());
 
     std::string iface_name = getIfaceName(sta_iface);
     const auto& status_and_iface1 =
@@ -724,12 +516,12 @@
  * the iface object using the correct name and ensure any other name
  * doesn't remove the iface.
  */
-TEST_F(WifiChipHidlTest, RemoveStaIface) {
+TEST_P(WifiChipHidlTest, RemoveStaIface) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     sp<IWifiStaIface> sta_iface;
     EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&sta_iface));
-    EXPECT_NE(nullptr, sta_iface.get());
+    ASSERT_NE(nullptr, sta_iface.get());
 
     std::string iface_name = getIfaceName(sta_iface);
     std::string invalid_name = iface_name + "0";
@@ -743,15 +535,25 @@
 /*
  * CreateRttController
  */
-TEST_F(WifiChipHidlTest, CreateRttController) {
+TEST_P(WifiChipHidlTest, CreateRttController) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     sp<IWifiStaIface> iface;
     EXPECT_EQ(WifiStatusCode::SUCCESS, createStaIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
+    ASSERT_NE(nullptr, iface.get());
 
     const auto& status_and_rtt_controller =
         HIDL_INVOKE(wifi_chip_, createRttController, iface);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_rtt_controller.first.code);
-    EXPECT_NE(nullptr, status_and_rtt_controller.second.get());
+    if (status_and_rtt_controller.first.code !=
+        WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        EXPECT_EQ(WifiStatusCode::SUCCESS,
+                  status_and_rtt_controller.first.code);
+        EXPECT_NE(nullptr, status_and_rtt_controller.second.get());
+    }
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_hidl_call_util.h b/wifi/1.0/vts/functional/wifi_hidl_call_util.h
index f3ca517..3be14c3 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_call_util.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_call_util.h
@@ -16,13 +16,12 @@
 
 #pragma once
 
+#include <gtest/gtest.h>
 #include <functional>
 #include <tuple>
 #include <type_traits>
 #include <utility>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace {
 namespace detail {
 template <typename>
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
index b8e501c..f3c82da 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
@@ -18,7 +18,9 @@
 
 #include <android/hardware/wifi/1.0/IWifi.h>
 
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_test_utils.h"
 
@@ -28,13 +30,17 @@
 /**
  * Fixture to use for all root Wifi HIDL interface tests.
  */
-class WifiHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiHidlTest : public ::testing::TestWithParam<std::string> {
    public:
-    virtual void SetUp() override {}
+    virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+    }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -42,7 +48,12 @@
  * Ensures that an instance of the IWifi proxy object is
  * successfully created.
  */
-TEST(WifiHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifi().get());
-    stopWifi();
+TEST_P(WifiHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index d584d4b..5b11dd3 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -16,8 +16,6 @@
 
 #include <android/log.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 #include <wifi_system/interface_tool.h>
 
 #include "wifi_hidl_call_util.h"
@@ -41,8 +39,6 @@
 using ::android::hardware::hidl_vec;
 using ::android::wifi_system::InterfaceTool;
 
-extern WifiHidlEnvironment* gEnv;
-
 namespace {
 constexpr uint32_t kHalStartRetryMaxCount = 5;
 constexpr uint32_t kHalStartRetryIntervalInMs = 2;
@@ -94,16 +90,7 @@
 }  // namespace
 
 sp<IWifi> getWifi(const std::string& instance_name) {
-    if ((!gEnv && instance_name.empty()) || (gEnv && !instance_name.empty())) {
-        ALOGE("instance_name and gEnv must have one and only one set.");
-        return nullptr;
-    }
-    if (gEnv) {
-        return ::testing::VtsHalHidlTargetTestBase::getService<IWifi>(
-            gEnv->getServiceName<IWifi>());
-    } else {
-        return IWifi::getService(instance_name);
-    }
+    return IWifi::getService(instance_name);
 }
 
 sp<IWifiChip> getWifiChip(const std::string& instance_name) {
@@ -209,23 +196,6 @@
     return status_and_iface.second;
 }
 
-sp<IWifiRttController> getWifiRttController(const std::string& instance_name) {
-    sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
-    if (!wifi_chip.get()) {
-        return nullptr;
-    }
-    sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface(instance_name);
-    if (!wifi_sta_iface.get()) {
-        return nullptr;
-    }
-    const auto& status_and_controller =
-        HIDL_INVOKE(wifi_chip, createRttController, wifi_sta_iface);
-    if (status_and_controller.first.code != WifiStatusCode::SUCCESS) {
-        return nullptr;
-    }
-    return status_and_controller.second;
-}
-
 bool configureChipToSupportIfaceType(const sp<IWifiChip>& wifi_chip,
                                      IfaceType type,
                                      ChipModeId* configured_mode_id) {
@@ -234,7 +204,7 @@
 }
 
 void stopWifi(const std::string& instance_name) {
-    sp<IWifi> wifi = getWifi(instance_name);
+    sp<IWifi> wifi = IWifi::getService(instance_name);
     ASSERT_NE(wifi, nullptr);
     HIDL_INVOKE(wifi, stop);
 }
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
index 529b142..5c78637 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -31,21 +31,18 @@
 // Note: We only have a single instance of each of these objects currently.
 // These helper functions should be modified to return vectors if we support
 // multiple instances.
-// TODO(b/143892896): Remove the default value as part of the cleanup.
 android::sp<android::hardware::wifi::V1_0::IWifi> getWifi(
-    const std::string& instance_name = "");
+    const std::string& instance_name);
 android::sp<android::hardware::wifi::V1_0::IWifiChip> getWifiChip(
-    const std::string& instance_name = "");
+    const std::string& instance_name);
 android::sp<android::hardware::wifi::V1_0::IWifiApIface> getWifiApIface(
-    const std::string& instance_name = "");
+    const std::string& instance_name);
 android::sp<android::hardware::wifi::V1_0::IWifiNanIface> getWifiNanIface(
-    const std::string& instance_name = "");
+    const std::string& instance_name);
 android::sp<android::hardware::wifi::V1_0::IWifiP2pIface> getWifiP2pIface(
-    const std::string& instance_name = "");
+    const std::string& instance_name);
 android::sp<android::hardware::wifi::V1_0::IWifiStaIface> getWifiStaIface(
-    const std::string& instance_name = "");
-android::sp<android::hardware::wifi::V1_0::IWifiRttController>
-getWifiRttController(const std::string& instance_name = "");
+    const std::string& instance_name);
 // Configure the chip in a mode to support the creation of the provided
 // iface type.
 bool configureChipToSupportIfaceType(
@@ -53,56 +50,4 @@
     android::hardware::wifi::V1_0::IfaceType type,
     android::hardware::wifi::V1_0::ChipModeId* configured_mode_id);
 // Used to trigger IWifi.stop() at the end of every test.
-void stopWifi(const std::string& instance_name = "");
-
-class WifiHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   protected:
-    virtual void HidlSetUp() override {
-        stopWifi();
-        sleep(5);
-    }
-
-   public:
-    // Whether NaN feature is supported on the device.
-    bool isNanOn = false;
-    // Whether SoftAp feature is supported on the device.
-    bool isSoftApOn = false;
-
-    void usage(char* me, char* arg) {
-        fprintf(stderr,
-                "unrecognized option: %s\n\n"
-                "usage: %s <gtest options> <test options>\n\n"
-                "test options are:\n\n"
-                "-N, --nan_on: Whether NAN feature is supported\n"
-                "-S, --softap_on: Whether SOFTAP feature is supported\n",
-                arg, me);
-    }
-
-    int initFromOptions(int argc, char** argv) {
-        static struct option options[] = {{"nan_on", no_argument, 0, 'N'},
-                                          {"softap_on", no_argument, 0, 'S'},
-                                          {0, 0, 0, 0}};
-
-        int c;
-        while ((c = getopt_long(argc, argv, "NS", options, NULL)) >= 0) {
-            switch (c) {
-                case 'N':
-                    isNanOn = true;
-                    break;
-                case 'S':
-                    isSoftApOn = true;
-                    break;
-                default:
-                    usage(argv[0], argv[optind]);
-                    return 2;
-            }
-        }
-
-        if (optind < argc) {
-            usage(argv[0], argv[optind]);
-            return 2;
-        }
-
-        return 0;
-    }
-};
+void stopWifi(const std::string& instance_name);
diff --git a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
index 64b4fb6..2b63ddc 100644
--- a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -16,10 +16,13 @@
 
 #include <android-base/logging.h>
 
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiNanIface.h>
 #include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -29,27 +32,34 @@
 
 using namespace ::android::hardware::wifi::V1_0;
 
+using ::android::sp;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::sp;
+using ::android::hardware::wifi::V1_0::IWifi;
 
 #define TIMEOUT_PERIOD 10
 
 /**
  * Fixture to use for all NAN Iface HIDL interface tests.
  */
-class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-  public:
+class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+   public:
     virtual void SetUp() override {
-      iwifiNanIface = getWifiNanIface();
-      ASSERT_NE(nullptr, iwifiNanIface.get());
-      ASSERT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, registerEventCallback,
-            new WifiNanIfaceEventCallback(*this)).code);
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.aware"))
+            GTEST_SKIP() << "Skipping this test since NAN is not supported.";
+
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
+        iwifiNanIface = getWifiNanIface(GetInstanceName());
+        ASSERT_NE(nullptr, iwifiNanIface.get());
+        ASSERT_EQ(WifiStatusCode::SUCCESS,
+                  HIDL_INVOKE(iwifiNanIface, registerEventCallback,
+                              new WifiNanIfaceEventCallback(*this))
+                      .code);
     }
 
-    virtual void TearDown() override {
-      stopWifi();
-    }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
     /* Used as a mechanism to inform the test about data/event callback */
     inline void notify() {
@@ -438,6 +448,8 @@
       NanFollowupReceivedInd nanFollowupReceivedInd;
       NanDataPathRequestInd nanDataPathRequestInd;
       NanDataPathConfirmInd nanDataPathConfirmInd;
+
+      std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -445,9 +457,8 @@
  * Ensures that an instance of the IWifiNanIface proxy object is
  * successfully created.
  */
-TEST(WifiNanIfaceHidlTestNoFixture, Create) {
-  ASSERT_NE(nullptr, getWifiNanIface().get());
-  stopWifi();
+TEST_P(WifiNanIfaceHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
 
 /*
@@ -455,41 +466,51 @@
  * Ensure that API calls fail with ERROR_WIFI_IFACE_INVALID when using an interface once wifi
  * is disabled.
  */
-TEST(WifiNanIfaceHidlTestNoFixture, FailOnIfaceInvalid) {
-  android::sp<IWifiNanIface> iwifiNanIface = getWifiNanIface();
-  ASSERT_NE(nullptr, iwifiNanIface.get());
-  stopWifi();
-  sleep(5); // make sure that all chips/interfaces are invalidated
-  ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-          HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code);
+TEST_P(WifiNanIfaceHidlTest, FailOnIfaceInvalid) {
+    stopWifi(GetInstanceName());
+    android::sp<IWifiNanIface> iwifiNanIface =
+        getWifiNanIface(GetInstanceName());
+    ASSERT_NE(nullptr, iwifiNanIface.get());
+    stopWifi(GetInstanceName());
+    sleep(5);  // make sure that all chips/interfaces are invalidated
+    ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+              HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code);
 }
 
 /*
  * getCapabilitiesRequest: validate that returns capabilities.
  */
-TEST_F(WifiNanIfaceHidlTest, getCapabilitiesRequest) {
-  uint16_t inputCmdId = 10;
-  callbackType = INVALID;
-  ASSERT_EQ(WifiStatusCode::SUCCESS,
+TEST_P(WifiNanIfaceHidlTest, getCapabilitiesRequest) {
+    uint16_t inputCmdId = 10;
+    callbackType = INVALID;
+    ASSERT_EQ(
+        WifiStatusCode::SUCCESS,
         HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, inputCmdId).code);
-  // wait for a callback
-  ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
-  ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType);
-  ASSERT_EQ(id, inputCmdId);
+    // wait for a callback
+    ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
+    ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType);
+    ASSERT_EQ(id, inputCmdId);
 
-  // check for reasonable capability values
-  EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxPublishes, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxSubscribes, (unsigned int) 0);
-  EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int) 255);
-  EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int) 255);
-  EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int) 255);
-  EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int) 255);
-  EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen, (unsigned int) 255);
-  EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxNdpSessions, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int) 0);
-  EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int) 0);
-  EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int) 0);
+    // check for reasonable capability values
+    EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int)0);
+    EXPECT_GT(capabilities.maxPublishes, (unsigned int)0);
+    EXPECT_GT(capabilities.maxSubscribes, (unsigned int)0);
+    EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int)255);
+    EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int)255);
+    EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int)255);
+    EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int)255);
+    EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen,
+              (unsigned int)255);
+    EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int)0);
+    EXPECT_GT(capabilities.maxNdpSessions, (unsigned int)0);
+    EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int)0);
+    EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int)0);
+    EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int)0);
+    EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int)0);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiNanIfaceHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
index 269eb6c..fd175f5 100644
--- a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
@@ -16,25 +16,32 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiP2pIface.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "wifi_hidl_test_utils.h"
 
-using ::android::hardware::wifi::V1_0::IWifiP2pIface;
 using ::android::sp;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiP2pIface;
 
 /**
  * Fixture to use for all P2P Iface HIDL interface tests.
  */
-class WifiP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiP2pIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
-    virtual void SetUp() override {}
+    virtual void SetUp() override {
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+    }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -42,7 +49,13 @@
  * Ensures that an instance of the IWifiP2pIface proxy object is
  * successfully created.
  */
-TEST(WifiP2pIfaceHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiP2pIface().get());
-    stopWifi();
+TEST_P(WifiP2pIfaceHidlTest, Create) {
+    stopWifi(GetInstanceName());
+    EXPECT_NE(nullptr, getWifiP2pIface(GetInstanceName()).get());
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiP2pIfaceHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
index e13086d..3c9ed9e 100644
--- a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -16,25 +16,39 @@
 
 #include <android-base/logging.h>
 
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiRttController.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
 
-using ::android::hardware::wifi::V1_0::IWifiRttController;
 using ::android::sp;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::V1_0::IWifiRttController;
+using ::android::hardware::wifi::V1_0::IWifiStaIface;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
 
 /**
  * Fixture to use for all RTT controller HIDL interface tests.
  */
-class WifiRttControllerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiRttControllerHidlTest : public ::testing::TestWithParam<std::string> {
    public:
-    virtual void SetUp() override {}
+    virtual void SetUp() override {
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.rtt"))
+            GTEST_SKIP() << "Skipping this test since RTT is not supported.";
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+    }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -42,7 +56,28 @@
  * Ensures that an instance of the IWifiRttController proxy object is
  * successfully created.
  */
-TEST(WifiRttControllerHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiRttController().get());
-    stopWifi();
+TEST_P(WifiRttControllerHidlTest, Create) {
+    stopWifi(GetInstanceName());
+
+    const std::string& instance_name = GetInstanceName();
+
+    sp<IWifiChip> wifi_chip = getWifiChip(instance_name);
+    ASSERT_NE(nullptr, wifi_chip.get());
+
+    sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface(instance_name);
+    ASSERT_NE(nullptr, wifi_sta_iface.get());
+
+    const auto& status_and_controller =
+        HIDL_INVOKE(wifi_chip, createRttController, wifi_sta_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, WifiRttControllerHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
index a413863..e311c84 100644
--- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -16,10 +16,12 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiStaIface.h>
 #include <android/hardware/wifi/1.3/IWifiStaIface.h>
-
-#include <VtsHalHidlTargetTestBase.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"
@@ -28,6 +30,7 @@
 using ::android::hardware::wifi::V1_0::Bssid;
 using ::android::hardware::wifi::V1_0::CommandId;
 using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiStaIface;
 using ::android::hardware::wifi::V1_0::Rssi;
 using ::android::hardware::wifi::V1_0::Ssid;
@@ -41,14 +44,17 @@
 /**
  * Fixture to use for all STA Iface HIDL interface tests.
  */
-class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_sta_iface_ = getWifiStaIface();
+        // Make sure test starts with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_sta_iface_ = getWifiStaIface(GetInstanceName());
         ASSERT_NE(nullptr, wifi_sta_iface_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
@@ -59,6 +65,7 @@
     }
 
     sp<IWifiStaIface> wifi_sta_iface_;
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -66,15 +73,14 @@
  * Ensures that an instance of the IWifiStaIface proxy object is
  * successfully created.
  */
-TEST(WifiStaIfaceHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiStaIface().get());
-    stopWifi();
+TEST_P(WifiStaIfaceHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
 
 /*
  * GetCapabilities:
  */
-TEST_F(WifiStaIfaceHidlTest, GetCapabilities) {
+TEST_P(WifiStaIfaceHidlTest, GetCapabilities) {
     const auto& status_and_caps = HIDL_INVOKE(wifi_sta_iface_, getCapabilities);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
     EXPECT_GT(status_and_caps.second, 0u);
@@ -84,7 +90,7 @@
  * GetType:
  * Ensures that the correct interface type is returned for station interface.
  */
-TEST_F(WifiStaIfaceHidlTest, GetType) {
+TEST_P(WifiStaIfaceHidlTest, GetType) {
     const auto& status_and_type = HIDL_INVOKE(wifi_sta_iface_, getType);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code);
     EXPECT_EQ(IfaceType::STA, status_and_type.second);
@@ -94,7 +100,7 @@
  * GetApfPacketFilterCapabilities:
  * Ensures that we can retrieve APF packet filter capabilites.
  */
-TEST_F(WifiStaIfaceHidlTest, GetApfPacketFilterCapabilities) {
+TEST_P(WifiStaIfaceHidlTest, GetApfPacketFilterCapabilities) {
     if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) {
         // No-op if APF packet filer is not supported.
         return;
@@ -109,7 +115,7 @@
  * GetBackgroundScanCapabilities:
  * Ensures that we can retrieve background scan capabilities.
  */
-TEST_F(WifiStaIfaceHidlTest, GetBackgroundScanCapabilities) {
+TEST_P(WifiStaIfaceHidlTest, GetBackgroundScanCapabilities) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::BACKGROUND_SCAN)) {
         // No-op if background scan is not supported.
@@ -125,7 +131,7 @@
  * GetValidFrequenciesForBand:
  * Ensures that we can retrieve valid frequencies for 2.4 GHz band.
  */
-TEST_F(WifiStaIfaceHidlTest, GetValidFrequenciesForBand) {
+TEST_P(WifiStaIfaceHidlTest, GetValidFrequenciesForBand) {
     const auto& status_and_freqs = HIDL_INVOKE(
         wifi_sta_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code);
@@ -137,7 +143,7 @@
  * Ensures that calls to enable, disable, and retrieve link layer stats
  * will return a success status code.
  */
-TEST_F(WifiStaIfaceHidlTest, LinkLayerStatsCollection) {
+TEST_P(WifiStaIfaceHidlTest, LinkLayerStatsCollection) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
         // No-op if link layer stats is not supported.
@@ -172,7 +178,7 @@
  * Ensures that calls to disable RSSI monitoring will return an error status
  * code if RSSI monitoring is not enabled.
  */
-TEST_F(WifiStaIfaceHidlTest, RSSIMonitoring) {
+TEST_P(WifiStaIfaceHidlTest, RSSIMonitoring) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::RSSI_MONITOR)) {
         // No-op if RSSI monitor is not supported.
@@ -197,7 +203,7 @@
  * Ensures that calls to configure and enable roaming will return a success
  * status code.
  */
-TEST_F(WifiStaIfaceHidlTest, RoamingControl) {
+TEST_P(WifiStaIfaceHidlTest, RoamingControl) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::CONTROL_ROAMING)) {
         // No-op if roaming control is not supported.
@@ -242,9 +248,9 @@
  * Ensures that calls to enable neighbor discovery offload will return a success
  * status code.
  */
-TEST_F(WifiStaIfaceHidlTest, EnableNDOffload) {
-   if (!isCapabilitySupported(
-           IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) {
+TEST_P(WifiStaIfaceHidlTest, EnableNDOffload) {
+    if (!isCapabilitySupported(
+            IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) {
         // No-op if nd offload is not supported.
         return;
     }
@@ -254,10 +260,10 @@
 
 /*
  * SetScanningMacOui:
- * Ensures that calls to set scanning MAC OUI will return a success status
- * code.
+ * Ensures that calls to set scanning MAC OUI will return a NOT_SUPPORTED
+ * code since it is now deprecated.
  */
-TEST_F(WifiStaIfaceHidlTest, SetScanningMacOui) {
+TEST_P(WifiStaIfaceHidlTest, SetScanningMacOui) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::SCAN_RAND)) {
         // No-op if SetScanningMacOui is not supported.
@@ -265,7 +271,7 @@
     }
     const android::hardware::hidl_array<uint8_t, 3> kOui{
         std::array<uint8_t, 3>{{0x10, 0x22, 0x33}}};
-    EXPECT_EQ(WifiStatusCode::SUCCESS,
+    EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED,
               HIDL_INVOKE(wifi_sta_iface_, setScanningMacOui, kOui).code);
 }
 
@@ -274,9 +280,9 @@
  * Ensures that calls to start packet fate monitoring and retrieve TX/RX
  * packets will return a success status code.
  */
-TEST_F(WifiStaIfaceHidlTest, PacketFateMonitoring) {
-   if (!isCapabilitySupported(
-           IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) {
+TEST_P(WifiStaIfaceHidlTest, PacketFateMonitoring) {
+    if (!isCapabilitySupported(
+            IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) {
         // No-op if packet fate monitor is not supported.
         return;
     }
@@ -291,3 +297,9 @@
     EXPECT_EQ(WifiStatusCode::SUCCESS,
               HIDL_INVOKE(wifi_sta_iface_, getDebugRxPacketFates).first.code);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiStaIfaceHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp
index 6d7635d..7dc78e4 100644
--- a/wifi/1.1/vts/functional/Android.bp
+++ b/wifi/1.1/vts/functional/Android.bp
@@ -18,15 +18,18 @@
     name: "VtsHalWifiV1_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiV1_1TargetTest.cpp",
-        "wifi_chip_hidl_test.cpp"],
+        "wifi_chip_hidl_test.cpp",
+    ],
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
         "android.hardware.wifi@1.0",
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
-        "libwifi-system-iface"
+        "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
deleted file mode 100644
index a0f97f8..0000000
--- a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.1/IWifi.h>
-
-#include "wifi_hidl_test_utils.h"
-
-class WifiHidlEnvironment_1_1 : public WifiHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiHidlEnvironment_1_1* Instance() {
-        static WifiHidlEnvironment_1_1* instance = new WifiHidlEnvironment_1_1;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<android::hardware::wifi::V1_1::IWifi>();
-    }
-
-   private:
-    WifiHidlEnvironment_1_1() {}
-};
-
-WifiHidlEnvironment* gEnv = WifiHidlEnvironment_1_1::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        int status = RUN_ALL_TESTS();
-        LOG(INFO) << "Test result = " << status;
-    }
-    return status;
-}
diff --git a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
index 6323547..4b94acb 100644
--- a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
@@ -19,8 +19,9 @@
 #include <android/hardware/wifi/1.1/IWifi.h>
 #include <android/hardware/wifi/1.1/IWifiChip.h>
 #include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.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"
@@ -45,14 +46,17 @@
 /**
  * Fixture to use for all Wifi chip HIDL interface tests.
  */
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_chip_ = IWifiChip::castFrom(getWifiChip());
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     uint32_t configureChipForStaIfaceAndGetCapabilities() {
@@ -77,12 +81,15 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
  * SelectTxPowerScenario
  */
-TEST_F(WifiChipHidlTest, SelectTxPowerScenario) {
+TEST_P(WifiChipHidlTest, SelectTxPowerScenario) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, selectTxPowerScenario, kFakePowerScenario);
@@ -96,7 +103,7 @@
 /*
  * ResetTxPowerScenario
  */
-TEST_F(WifiChipHidlTest, ResetTxPowerScenario) {
+TEST_P(WifiChipHidlTest, ResetTxPowerScenario) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, resetTxPowerScenario);
@@ -106,3 +113,9 @@
         EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
     }
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.2/IWifiStaIface.hal b/wifi/1.2/IWifiStaIface.hal
index 3a7f777..d65b33b 100644
--- a/wifi/1.2/IWifiStaIface.hal
+++ b/wifi/1.2/IWifiStaIface.hal
@@ -23,7 +23,7 @@
 /**
  * Interface used to represent a single STA iface.
  *
- * IWifiChip.createStaIface() may return a @1.2::IWifiStaIface when supported.
+ * IWifiChip.createStaIface() must return a @1.2::IWifiStaIface when supported.
  */
 interface IWifiStaIface extends @1.0::IWifiStaIface {
     /**
diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp
index 97853d0..159ba94 100644
--- a/wifi/1.2/vts/functional/Android.bp
+++ b/wifi/1.2/vts/functional/Android.bp
@@ -18,7 +18,6 @@
     name: "VtsHalWifiV1_2TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiV1_2TargetTest.cpp",
         "wifi_chip_hidl_test.cpp",
         "wifi_sta_iface_hidl_test.cpp",
     ],
@@ -28,16 +27,19 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
-        "libwifi-system-iface"
+        "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    disable_framework: true,
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
 
 cc_test {
     name: "VtsHalWifiNanV1_2TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiV1_2TargetTest.cpp",
         "wifi_nan_iface_hidl_test.cpp",
     ],
     static_libs: [
@@ -45,7 +47,10 @@
         "android.hardware.wifi@1.0",
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
-        "libwifi-system-iface"
+        "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp b/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
deleted file mode 100644
index c765cdc..0000000
--- a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
+++ /dev/null
@@ -1,48 +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 <android-base/logging.h>
-#include <android/hardware/wifi/1.2/IWifi.h>
-
-#include "wifi_hidl_test_utils.h"
-
-using ::android::hardware::wifi::V1_2::IWifi;
-
-// Test environment for Wifi HIDL HAL.
-class WifiHidlEnvironment_1_2 : public WifiHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiHidlEnvironment_1_2* Instance() {
-        static WifiHidlEnvironment_1_2* instance = new WifiHidlEnvironment_1_2;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IWifi>(); }
-
-   private:
-    WifiHidlEnvironment_1_2() {}
-};
-
-WifiHidlEnvironment_1_2* gEnv = WifiHidlEnvironment_1_2::Instance();
-
-int main(int argc, char** argv) {
-  ::testing::AddGlobalTestEnvironment(gEnv);
-  ::testing::InitGoogleTest(&argc, argv);
-  gEnv->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
diff --git a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
index 9d567fe..b04acad 100644
--- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
@@ -16,12 +16,14 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.2/IWifi.h>
 #include <android/hardware/wifi/1.2/IWifiChip.h>
 #include <android/hardware/wifi/1.2/IWifiChipEventCallback.h>
 #include <android/hardware/wifi/1.3/IWifiChip.h>
-
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
 
 #include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
@@ -50,14 +52,17 @@
 /**
  * Fixture to use for all Wifi chip HIDL interface tests.
  */
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-    wifi_chip_ = IWifiChip::castFrom(getWifiChip());
-    ASSERT_NE(nullptr, wifi_chip_.get());
+      // Make sure test starts with a clean state
+      stopWifi(GetInstanceName());
+
+      wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
+      ASSERT_NE(nullptr, wifi_chip_.get());
   }
 
-  virtual void TearDown() override { stopWifi(); }
+  virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
   // A simple test implementation of WifiChipEventCallback.
   class WifiChipEventCallback
@@ -123,6 +128,9 @@
   }
 
   sp<IWifiChip> wifi_chip_;
+
+ private:
+  std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -130,7 +138,7 @@
  * This test case tests the selectTxPowerScenario_1_2() API with SAR scenarios
  * newly defined in 1.2
  */
-TEST_F(WifiChipHidlTest, SelectTxPowerScenario_1_2_body) {
+TEST_P(WifiChipHidlTest, SelectTxPowerScenario_1_2_body) {
   uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
   const auto& status =
       HIDL_INVOKE(wifi_chip_, selectTxPowerScenario_1_2, kPowerScenarioBody);
@@ -147,7 +155,7 @@
  * This test case tests the selectTxPowerScenario_1_2() API with previously
  * defined SAR scenarios
  */
-TEST_F(WifiChipHidlTest, SelectTxPowerScenario_1_2_voiceCall) {
+TEST_P(WifiChipHidlTest, SelectTxPowerScenario_1_2_voiceCall) {
   uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
   const auto& status =
       HIDL_INVOKE(wifi_chip_, selectTxPowerScenario_1_2, kPowerScenarioVoiceCall);
@@ -167,9 +175,19 @@
  * since event is triggered internally in the HAL implementation, and can not be
  * triggered from the test case
  */
-TEST_F(WifiChipHidlTest, registerEventCallback_1_2) {
+TEST_P(WifiChipHidlTest, registerEventCallback_1_2) {
     sp<WifiChipEventCallback> wifiChipEventCallback = new WifiChipEventCallback();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, registerEventCallback_1_2, wifiChipEventCallback);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+
+    if (status.code != WifiStatusCode::SUCCESS) {
+        EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
+        return;
+    }
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_2::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
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 4dbc82b..bc392a9 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
@@ -16,10 +16,13 @@
 
 #include <android-base/logging.h>
 
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.2/IWifi.h>
 #include <android/hardware/wifi/1.2/IWifiNanIface.h>
 #include <android/hardware/wifi/1.2/IWifiNanIfaceEventCallback.h>
-
-#include <VtsHalHidlTargetTestBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -36,19 +39,24 @@
 
 #define TIMEOUT_PERIOD 10
 
-android::sp<android::hardware::wifi::V1_2::IWifiNanIface>
-getWifiNanIface_1_2() {
+android::sp<android::hardware::wifi::V1_2::IWifiNanIface> getWifiNanIface_1_2(
+    const std::string& instance_name) {
     return android::hardware::wifi::V1_2::IWifiNanIface::castFrom(
-        getWifiNanIface());
+        getWifiNanIface(instance_name));
 }
 
 /**
  * Fixture to use for all NAN Iface HIDL interface tests.
  */
-class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        iwifiNanIface = getWifiNanIface_1_2();
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.aware"))
+            GTEST_SKIP() << "Skipping this test since NAN is not supported.";
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        iwifiNanIface = getWifiNanIface_1_2(GetInstanceName());
         ASSERT_NE(nullptr, iwifiNanIface.get());
         ASSERT_EQ(WifiStatusCode::SUCCESS,
                   HIDL_INVOKE(iwifiNanIface, registerEventCallback_1_2,
@@ -56,7 +64,7 @@
                       .code);
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
     /* Used as a mechanism to inform the test about data/event callback */
     inline void notify() {
@@ -434,7 +442,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;
@@ -458,6 +466,8 @@
     ::android::hardware::wifi::V1_2::NanDataPathConfirmInd
         nanDataPathConfirmInd_1_2;
     NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd;
+
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -465,76 +475,92 @@
  * Ensures that an instance of the IWifiNanIface proxy object is
  * successfully created.
  */
-TEST(WifiNanIfaceHidlTestNoFixture, Create) {
-    ASSERT_NE(nullptr, getWifiNanIface_1_2().get());
-    stopWifi();
+TEST_P(WifiNanIfaceHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
 }
 
 /*
  * enableRequest_1_2InvalidArgs: validate that fails with invalid arguments
  */
-TEST_F(WifiNanIfaceHidlTest, enableRequest_1_2InvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_2InvalidArgs) {
     uint16_t inputCmdId = 10;
     callbackType = INVALID;
     NanEnableRequest nanEnableRequest = {};
     NanConfigRequestSupplemental nanConfigRequestSupp = {};
-    ASSERT_EQ(WifiStatusCode::SUCCESS,
-              HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
-                          nanEnableRequest, nanConfigRequestSupp)
-                  .code);
-    // wait for a callback
-    ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
-    ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
-    ASSERT_EQ(id, inputCmdId);
-    ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+    const auto& halStatus =
+        HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
+                    nanEnableRequest, nanConfigRequestSupp);
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+        // wait for a callback
+        ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
+        ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
+        ASSERT_EQ(id, inputCmdId);
+        ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+    }
 }
 
 /*
  * enableRequest_1_2ShimInvalidArgs: validate that fails with invalid arguments
  * to the shim
  */
-TEST_F(WifiNanIfaceHidlTest, enableRequest_1_2ShimInvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_2ShimInvalidArgs) {
     uint16_t inputCmdId = 10;
     NanEnableRequest nanEnableRequest = {};
     nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon =
         128;  // must be <= 127
     NanConfigRequestSupplemental nanConfigRequestSupp = {};
-    ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
-              HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
-                          nanEnableRequest, nanConfigRequestSupp)
-                  .code);
+    const auto& halStatus =
+        HIDL_INVOKE(iwifiNanIface, enableRequest_1_2, inputCmdId,
+                    nanEnableRequest, nanConfigRequestSupp);
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+    }
 }
 
 /*
  * configRequest_1_2InvalidArgs: validate that fails with invalid arguments
  */
-TEST_F(WifiNanIfaceHidlTest, configRequest_1_2InvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_2InvalidArgs) {
     uint16_t inputCmdId = 10;
     callbackType = INVALID;
     NanConfigRequest nanConfigRequest = {};
     NanConfigRequestSupplemental nanConfigRequestSupp = {};
-    ASSERT_EQ(WifiStatusCode::SUCCESS,
-              HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
-                          nanConfigRequest, nanConfigRequestSupp)
-                  .code);
-    // wait for a callback
-    ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
-    ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType);
-    ASSERT_EQ(id, inputCmdId);
-    ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+    const auto& halStatus =
+        HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
+                    nanConfigRequest, nanConfigRequestSupp);
+
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+        // wait for a callback
+        ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
+        ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType);
+        ASSERT_EQ(id, inputCmdId);
+        ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+    }
 }
 
 /*
  * configRequest_1_2ShimInvalidArgs: validate that fails with invalid arguments
  * to the shim
  */
-TEST_F(WifiNanIfaceHidlTest, configRequest_1_2ShimInvalidArgs) {
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_2ShimInvalidArgs) {
     uint16_t inputCmdId = 10;
     NanConfigRequest nanConfigRequest = {};
     nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128;  // must be <= 127
     NanConfigRequestSupplemental nanConfigRequestSupp = {};
-    ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
-              HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
-                          nanConfigRequest, nanConfigRequestSupp)
-                  .code);
+    const auto& halStatus =
+        HIDL_INVOKE(iwifiNanIface, configRequest_1_2, inputCmdId,
+                    nanConfigRequest, nanConfigRequestSupp);
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+    }
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiNanIfaceHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_2::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
index 92f5d14..066dcaa 100644
--- a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -19,9 +19,11 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.2/IWifi.h>
 #include <android/hardware/wifi/1.2/IWifiStaIface.h>
-
-#include <VtsHalHidlTargetTestBase.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"
@@ -34,14 +36,18 @@
 /**
  * Fixture to use for all STA Iface HIDL interface tests.
  */
-class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface());
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_sta_iface_ =
+            IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_sta_iface_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
@@ -52,6 +58,9 @@
     }
 
     sp<IWifiStaIface> wifi_sta_iface_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -59,7 +68,7 @@
  * Ensures that calls to set MAC address will return a success status
  * code.
  */
-TEST_F(WifiStaIfaceHidlTest, SetMacAddress) {
+TEST_P(WifiStaIfaceHidlTest, SetMacAddress) {
     const android::hardware::hidl_array<uint8_t, 6> kMac{
         std::array<uint8_t, 6>{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}}};
     EXPECT_EQ(WifiStatusCode::SUCCESS,
@@ -76,7 +85,7 @@
  * TODO: We can't execute APF opcodes from this test because there's no way
  * to loop test packets through the wifi firmware (b/73804303#comment29).
  */
-TEST_F(WifiStaIfaceHidlTest, DISABLED_ReadApfPacketFilterData) {
+TEST_P(WifiStaIfaceHidlTest, DISABLED_ReadApfPacketFilterData) {
     if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) {
         // Disable test if APF packet filer is not supported.
         LOG(WARNING) << "TEST SKIPPED: APF packet filtering not supported";
@@ -107,3 +116,9 @@
 
     EXPECT_EQ(status_and_data.second, data);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiStaIfaceHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_2::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.3/IWifiStaIface.hal b/wifi/1.3/IWifiStaIface.hal
index 81c0c38..3a75509 100644
--- a/wifi/1.3/IWifiStaIface.hal
+++ b/wifi/1.3/IWifiStaIface.hal
@@ -23,7 +23,7 @@
 /**
  * Interface used to represent a single STA iface.
  *
- * IWifiChip.createStaIface() may return a @1.3::IWifiStaIface when supported.
+ * IWifiChip.createStaIface() must return a @1.3::IWifiStaIface when supported.
  */
 interface IWifiStaIface extends @1.2::IWifiStaIface {
     /**
diff --git a/wifi/1.3/default/Android.mk b/wifi/1.3/default/Android.mk
deleted file mode 100644
index 29f1c42..0000000
--- a/wifi/1.3/default/Android.mk
+++ /dev/null
@@ -1,169 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-LOCAL_PATH := $(call my-dir)
-
-###
-### android.hardware.wifi static library
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-lib
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-ifdef WIFI_HAL_INTERFACE_COMBINATIONS
-LOCAL_CPPFLAGS += -DWIFI_HAL_INTERFACE_COMBINATIONS="$(WIFI_HAL_INTERFACE_COMBINATIONS)"
-endif
-ifdef WIFI_HIDL_FEATURE_AWARE
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE
-endif
-ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DUAL_INTERFACE
-endif
-ifdef WIFI_HIDL_FEATURE_DISABLE_AP
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP
-endif
-ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-endif
-# Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
-LOCAL_CFLAGS += -Wno-error=implicit-fallthrough
-LOCAL_SRC_FILES := \
-    hidl_struct_util.cpp \
-    hidl_sync_util.cpp \
-    ringbuffer.cpp \
-    wifi.cpp \
-    wifi_ap_iface.cpp \
-    wifi_chip.cpp \
-    wifi_feature_flags.cpp \
-    wifi_iface_util.cpp \
-    wifi_legacy_hal.cpp \
-    wifi_legacy_hal_stubs.cpp \
-    wifi_mode_controller.cpp \
-    wifi_nan_iface.cpp \
-    wifi_p2p_iface.cpp \
-    wifi_rtt_controller.cpp \
-    wifi_sta_iface.cpp \
-    wifi_status_util.cpp
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libhidlbase \
-    liblog \
-    libnl \
-    libutils \
-    libwifi-hal \
-    libwifi-system-iface \
-    android.hardware.wifi@1.0 \
-    android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-include $(BUILD_STATIC_LIBRARY)
-
-###
-### android.hardware.wifi daemon
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
-    service.cpp
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libhidlbase \
-    liblog \
-    libnl \
-    libutils \
-    libwifi-hal \
-    libwifi-system-iface \
-    android.hardware.wifi@1.0 \
-    android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3
-LOCAL_STATIC_LIBRARIES := \
-    android.hardware.wifi@1.0-service-lib
-LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
-include $(BUILD_EXECUTABLE)
-
-###
-### android.hardware.wifi daemon
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy
-LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service
-LOCAL_CFLAGS := -DLAZY_SERVICE
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
-    service.cpp
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libhidlbase \
-    liblog \
-    libnl \
-    libutils \
-    libwifi-hal \
-    libwifi-system-iface \
-    android.hardware.wifi@1.0 \
-    android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3
-LOCAL_STATIC_LIBRARIES := \
-    android.hardware.wifi@1.0-service-lib
-LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc
-include $(BUILD_EXECUTABLE)
-
-###
-### android.hardware.wifi unit tests.
-###
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service-tests
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-LOCAL_SRC_FILES := \
-    tests/hidl_struct_util_unit_tests.cpp \
-    tests/main.cpp \
-    tests/mock_interface_tool.cpp \
-    tests/mock_wifi_feature_flags.cpp \
-    tests/mock_wifi_iface_util.cpp \
-    tests/mock_wifi_legacy_hal.cpp \
-    tests/mock_wifi_mode_controller.cpp \
-    tests/ringbuffer_unit_tests.cpp \
-    tests/wifi_ap_iface_unit_tests.cpp \
-    tests/wifi_nan_iface_unit_tests.cpp \
-    tests/wifi_chip_unit_tests.cpp \
-    tests/wifi_iface_util_unit_tests.cpp
-LOCAL_STATIC_LIBRARIES := \
-    libgmock \
-    libgtest \
-    android.hardware.wifi@1.0-service-lib
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libhidlbase \
-    liblog \
-    libnl \
-    libutils \
-    libwifi-hal \
-    libwifi-system-iface \
-    android.hardware.wifi@1.0 \
-    android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3
-include $(BUILD_NATIVE_TEST)
diff --git a/wifi/1.3/default/android.hardware.wifi@1.0-service.rc b/wifi/1.3/default/android.hardware.wifi@1.0-service.rc
deleted file mode 100644
index 2317bac..0000000
--- a/wifi/1.3/default/android.hardware.wifi@1.0-service.rc
+++ /dev/null
@@ -1,8 +0,0 @@
-service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
-    interface android.hardware.wifi@1.0::IWifi default
-    interface android.hardware.wifi@1.1::IWifi default
-    interface android.hardware.wifi@1.2::IWifi default
-    class hal
-    capabilities NET_ADMIN NET_RAW SYS_MODULE
-    user wifi
-    group wifi gps
diff --git a/wifi/1.3/default/hidl_callback_util.h b/wifi/1.3/default/hidl_callback_util.h
deleted file mode 100644
index a44af79..0000000
--- a/wifi/1.3/default/hidl_callback_util.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HIDL_CALLBACK_UTIL_H_
-#define HIDL_CALLBACK_UTIL_H_
-
-#include <set>
-
-#include <hidl/HidlSupport.h>
-
-namespace {
-// Type of callback invoked by the death handler.
-using on_death_cb_function = std::function<void(uint64_t)>;
-
-// Private class used to keep track of death of individual
-// callbacks stored in HidlCallbackHandler.
-template <typename CallbackType>
-class HidlDeathHandler : public android::hardware::hidl_death_recipient {
-   public:
-    HidlDeathHandler(const on_death_cb_function& user_cb_function)
-        : cb_function_(user_cb_function) {}
-    ~HidlDeathHandler() = default;
-
-    // Death notification for callbacks.
-    void serviceDied(
-        uint64_t cookie,
-        const android::wp<android::hidl::base::V1_0::IBase>& /* who */)
-        override {
-        cb_function_(cookie);
-    }
-
-   private:
-    on_death_cb_function cb_function_;
-
-    DISALLOW_COPY_AND_ASSIGN(HidlDeathHandler);
-};
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_callback_util {
-template <typename CallbackType>
-// Provides a class to manage callbacks for the various HIDL interfaces and
-// handle the death of the process hosting each callback.
-class HidlCallbackHandler {
-   public:
-    HidlCallbackHandler()
-        : death_handler_(new HidlDeathHandler<CallbackType>(
-              std::bind(&HidlCallbackHandler::onObjectDeath, this,
-                        std::placeholders::_1))) {}
-    ~HidlCallbackHandler() = default;
-
-    bool addCallback(const sp<CallbackType>& cb) {
-        // TODO(b/33818800): Can't compare proxies yet. So, use the cookie
-        // (callback proxy's raw pointer) to track the death of individual
-        // clients.
-        uint64_t cookie = reinterpret_cast<uint64_t>(cb.get());
-        if (cb_set_.find(cb) != cb_set_.end()) {
-            LOG(WARNING) << "Duplicate death notification registration";
-            return true;
-        }
-        if (!cb->linkToDeath(death_handler_, cookie)) {
-            LOG(ERROR) << "Failed to register death notification";
-            return false;
-        }
-        cb_set_.insert(cb);
-        return true;
-    }
-
-    const std::set<android::sp<CallbackType>>& getCallbacks() {
-        return cb_set_;
-    }
-
-    // Death notification for callbacks.
-    void onObjectDeath(uint64_t cookie) {
-        CallbackType* cb = reinterpret_cast<CallbackType*>(cookie);
-        const auto& iter = cb_set_.find(cb);
-        if (iter == cb_set_.end()) {
-            LOG(ERROR) << "Unknown callback death notification received";
-            return;
-        }
-        cb_set_.erase(iter);
-        LOG(DEBUG) << "Dead callback removed from list";
-    }
-
-    void invalidate() {
-        for (const sp<CallbackType>& cb : cb_set_) {
-            if (!cb->unlinkToDeath(death_handler_)) {
-                LOG(ERROR) << "Failed to deregister death notification";
-            }
-        }
-        cb_set_.clear();
-    }
-
-   private:
-    std::set<sp<CallbackType>> cb_set_;
-    sp<HidlDeathHandler<CallbackType>> death_handler_;
-
-    DISALLOW_COPY_AND_ASSIGN(HidlCallbackHandler);
-};
-
-}  // namespace hidl_callback_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_CALLBACK_UTIL_H_
diff --git a/wifi/1.3/default/hidl_return_util.h b/wifi/1.3/default/hidl_return_util.h
deleted file mode 100644
index 9707444..0000000
--- a/wifi/1.3/default/hidl_return_util.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 HIDL_RETURN_UTIL_H_
-#define HIDL_RETURN_UTIL_H_
-
-#include "hidl_sync_util.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_return_util {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * These utility functions are used to invoke a method on the provided
- * HIDL interface object.
- * These functions checks if the provided HIDL interface object is valid.
- * a) if valid, Invokes the corresponding internal implementation function of
- * the HIDL method. It then invokes the HIDL continuation callback with
- * the status and any returned values.
- * b) if invalid, invokes the HIDL continuation callback with the
- * provided error status and default values.
- */
-// Use for HIDL methods which return only an instance of WifiStatus.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        hidl_cb((obj->*work)(std::forward<Args>(args)...));
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid));
-    }
-    return Void();
-}
-
-// Use for HIDL methods which return only an instance of WifiStatus.
-// This version passes the global lock acquired to the body of the method.
-// Note: Only used by IWifi::stop() currently.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCallWithLock(
-    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
-    auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...));
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid));
-    }
-    return Void();
-}
-
-// Use for HIDL methods which return instance of WifiStatus and a single return
-// value.
-template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
-    Args&&... args) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
-        const WifiStatus& status = std::get<0>(ret_pair);
-        const auto& ret_value = std::get<1>(ret_pair);
-        hidl_cb(status, ret_value);
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid),
-                typename std::remove_reference<ReturnT>::type());
-    }
-    return Void();
-}
-
-// Use for HIDL methods which return instance of WifiStatus and 2 return
-// values.
-template <typename ObjT, typename WorkFuncT, typename ReturnT1,
-          typename ReturnT2, typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
-    const std::function<void(const WifiStatus&, ReturnT1, ReturnT2)>& hidl_cb,
-    Args&&... args) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (obj->isValid()) {
-        const auto& ret_tuple = (obj->*work)(std::forward<Args>(args)...);
-        const WifiStatus& status = std::get<0>(ret_tuple);
-        const auto& ret_value1 = std::get<1>(ret_tuple);
-        const auto& ret_value2 = std::get<2>(ret_tuple);
-        hidl_cb(status, ret_value1, ret_value2);
-    } else {
-        hidl_cb(createWifiStatus(status_code_if_invalid),
-                typename std::remove_reference<ReturnT1>::type(),
-                typename std::remove_reference<ReturnT2>::type());
-    }
-    return Void();
-}
-
-}  // namespace hidl_return_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_RETURN_UTIL_H_
diff --git a/wifi/1.3/default/hidl_struct_util.cpp b/wifi/1.3/default/hidl_struct_util.cpp
deleted file mode 100644
index d305c09..0000000
--- a/wifi/1.3/default/hidl_struct_util.cpp
+++ /dev/null
@@ -1,2701 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <utils/SystemClock.h>
-
-#include "hidl_struct_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_struct_util {
-
-WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
-    legacy_hal::wifi_channel_width type);
-
-hidl_string safeConvertChar(const char* str, size_t max_len) {
-    const char* c = str;
-    size_t size = 0;
-    while (*c && (unsigned char)*c < 128 && size < max_len) {
-        ++size;
-        ++c;
-    }
-    return hidl_string(str, size);
-}
-
-IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(
-    uint32_t feature) {
-    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
-    switch (feature) {
-        case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
-            return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP;
-        case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
-            return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP;
-        case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
-            return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT;
-        case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
-            return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT;
-        case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
-            return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-IWifiStaIface::StaIfaceCapabilityMask
-convertLegacyLoggerFeatureToHidlStaIfaceCapability(uint32_t feature) {
-    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-    switch (feature) {
-        case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
-            return HidlStaIfaceCaps::DEBUG_PACKET_FATE;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
-    uint32_t feature) {
-    using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
-    switch (feature) {
-        case WIFI_FEATURE_SET_TX_POWER_LIMIT:
-            return HidlChipCaps::SET_TX_POWER_LIMIT;
-        case WIFI_FEATURE_USE_BODY_HEAD_SAR:
-            return HidlChipCaps::USE_BODY_HEAD_SAR;
-        case WIFI_FEATURE_D2D_RTT:
-            return HidlChipCaps::D2D_RTT;
-        case WIFI_FEATURE_D2AP_RTT:
-            return HidlChipCaps::D2AP_RTT;
-        case WIFI_FEATURE_SET_LATENCY_MODE:
-            return HidlChipCaps::SET_LATENCY_MODE;
-        case WIFI_FEATURE_P2P_RAND_MAC:
-            return HidlChipCaps::P2P_RAND_MAC;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-IWifiStaIface::StaIfaceCapabilityMask
-convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) {
-    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-    switch (feature) {
-        case WIFI_FEATURE_GSCAN:
-            return HidlStaIfaceCaps::BACKGROUND_SCAN;
-        case WIFI_FEATURE_LINK_LAYER_STATS:
-            return HidlStaIfaceCaps::LINK_LAYER_STATS;
-        case WIFI_FEATURE_RSSI_MONITOR:
-            return HidlStaIfaceCaps::RSSI_MONITOR;
-        case WIFI_FEATURE_CONTROL_ROAMING:
-            return HidlStaIfaceCaps::CONTROL_ROAMING;
-        case WIFI_FEATURE_IE_WHITELIST:
-            return HidlStaIfaceCaps::PROBE_IE_WHITELIST;
-        case WIFI_FEATURE_SCAN_RAND:
-            return HidlStaIfaceCaps::SCAN_RAND;
-        case WIFI_FEATURE_INFRA_5G:
-            return HidlStaIfaceCaps::STA_5G;
-        case WIFI_FEATURE_HOTSPOT:
-            return HidlStaIfaceCaps::HOTSPOT;
-        case WIFI_FEATURE_PNO:
-            return HidlStaIfaceCaps::PNO;
-        case WIFI_FEATURE_TDLS:
-            return HidlStaIfaceCaps::TDLS;
-        case WIFI_FEATURE_TDLS_OFFCHANNEL:
-            return HidlStaIfaceCaps::TDLS_OFFCHANNEL;
-        case WIFI_FEATURE_CONFIG_NDO:
-            return HidlStaIfaceCaps::ND_OFFLOAD;
-        case WIFI_FEATURE_MKEEP_ALIVE:
-            return HidlStaIfaceCaps::KEEP_ALIVE;
-    };
-    CHECK(false) << "Unknown legacy feature: " << feature;
-    return {};
-}
-
-bool convertLegacyFeaturesToHidlChipCapabilities(
-    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
-    for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
-                               legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
-                               legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
-                               legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
-                               legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
-        if (feature & legacy_logger_feature_set) {
-            *hidl_caps |=
-                convertLegacyLoggerFeatureToHidlChipCapability(feature);
-        }
-    }
-    std::vector<uint32_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
-                                      WIFI_FEATURE_USE_BODY_HEAD_SAR,
-                                      WIFI_FEATURE_D2D_RTT,
-                                      WIFI_FEATURE_D2AP_RTT,
-                                      WIFI_FEATURE_SET_LATENCY_MODE,
-                                      WIFI_FEATURE_P2P_RAND_MAC};
-    for (const auto feature : features) {
-        if (feature & legacy_feature_set) {
-            *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
-        }
-    }
-
-    // There are no flags for these 3 in the legacy feature set. Adding them to
-    // the set because all the current devices support it.
-    *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
-    *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
-    *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
-    return true;
-}
-
-WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(
-    uint32_t flag) {
-    switch (flag) {
-        case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
-            return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
-        case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
-            return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
-    };
-    CHECK(false) << "Unknown legacy flag: " << flag;
-    return {};
-}
-
-bool convertLegacyDebugRingBufferStatusToHidl(
-    const legacy_hal::wifi_ring_buffer_status& legacy_status,
-    WifiDebugRingBufferStatus* hidl_status) {
-    if (!hidl_status) {
-        return false;
-    }
-    *hidl_status = {};
-    hidl_status->ringName =
-        safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
-                        sizeof(legacy_status.name));
-    hidl_status->flags = 0;
-    for (const auto flag : {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES,
-                            WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
-        if (flag & legacy_status.flags) {
-            hidl_status->flags |= static_cast<
-                std::underlying_type<WifiDebugRingBufferFlags>::type>(
-                convertLegacyDebugRingBufferFlagsToHidl(flag));
-        }
-    }
-    hidl_status->ringId = legacy_status.ring_id;
-    hidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
-    // Calculate free size of the ring the buffer. We don't need to send the
-    // exact read/write pointers that were there in the legacy HAL interface.
-    if (legacy_status.written_bytes >= legacy_status.read_bytes) {
-        hidl_status->freeSizeInBytes =
-            legacy_status.ring_buffer_byte_size -
-            (legacy_status.written_bytes - legacy_status.read_bytes);
-    } else {
-        hidl_status->freeSizeInBytes =
-            legacy_status.read_bytes - legacy_status.written_bytes;
-    }
-    hidl_status->verboseLevel = legacy_status.verbose_level;
-    return true;
-}
-
-bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
-    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
-    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
-    if (!hidl_status_vec) {
-        return false;
-    }
-    *hidl_status_vec = {};
-    for (const auto& legacy_status : legacy_status_vec) {
-        WifiDebugRingBufferStatus hidl_status;
-        if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status,
-                                                      &hidl_status)) {
-            return false;
-        }
-        hidl_status_vec->push_back(hidl_status);
-    }
-    return true;
-}
-
-bool convertLegacyWakeReasonStatsToHidl(
-    const legacy_hal::WakeReasonStats& legacy_stats,
-    WifiDebugHostWakeReasonStats* hidl_stats) {
-    if (!hidl_stats) {
-        return false;
-    }
-    *hidl_stats = {};
-    hidl_stats->totalCmdEventWakeCnt =
-        legacy_stats.wake_reason_cnt.total_cmd_event_wake;
-    hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
-    hidl_stats->totalDriverFwLocalWakeCnt =
-        legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
-    hidl_stats->driverFwLocalWakeCntPerType =
-        legacy_stats.driver_fw_local_wake_cnt;
-    hidl_stats->totalRxPacketWakeCnt =
-        legacy_stats.wake_reason_cnt.total_rx_data_wake;
-    hidl_stats->rxPktWakeDetails.rxUnicastCnt =
-        legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
-    hidl_stats->rxPktWakeDetails.rxMulticastCnt =
-        legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
-    hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
-        legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
-    hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
-        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
-            .ipv4_rx_multicast_addr_cnt;
-    hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
-        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
-            .ipv6_rx_multicast_addr_cnt;
-    hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
-        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
-            .other_rx_multicast_addr_cnt;
-    hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
-        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
-        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
-        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
-        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
-    hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
-        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
-    return true;
-}
-
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
-    V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
-    switch (hidl_scenario) {
-        // This is the only supported scenario for V1_1
-        case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
-            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
-    };
-    CHECK(false);
-}
-
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
-    V1_2::IWifiChip::TxPowerScenario hidl_scenario) {
-    switch (hidl_scenario) {
-        // This is the only supported scenario for V1_1
-        case V1_2::IWifiChip::TxPowerScenario::VOICE_CALL:
-            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
-        // Those are the supported scenarios for V1_2
-        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
-        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
-        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
-        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
-            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
-    };
-    CHECK(false);
-}
-
-legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
-    IWifiChip::LatencyMode hidl_latency_mode) {
-    switch (hidl_latency_mode) {
-        case IWifiChip::LatencyMode::NORMAL:
-            return legacy_hal::WIFI_LATENCY_MODE_NORMAL;
-        case IWifiChip::LatencyMode::LOW:
-            return legacy_hal::WIFI_LATENCY_MODE_LOW;
-    }
-    CHECK(false);
-}
-
-bool convertLegacyWifiMacInfoToHidl(
-    const legacy_hal::WifiMacInfo& legacy_mac_info,
-    V1_2::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
-    if (!hidl_radio_mode_info) {
-        return false;
-    }
-    *hidl_radio_mode_info = {};
-
-    hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
-    // Convert from bitmask of bands in the legacy HAL to enum value in
-    // the HIDL interface.
-    if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
-        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
-        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
-        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ;
-    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
-        hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ;
-    } else {
-        hidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED;
-    }
-    std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
-    for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
-        V1_2::IWifiChipEventCallback::IfaceInfo iface_info;
-        iface_info.name = legacy_iface_info.name;
-        iface_info.channel = legacy_iface_info.channel;
-        iface_info_vec.push_back(iface_info);
-    }
-    hidl_radio_mode_info->ifaceInfos = iface_info_vec;
-    return true;
-}
-
-bool convertLegacyWifiMacInfosToHidl(
-    const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-    std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>*
-        hidl_radio_mode_infos) {
-    if (!hidl_radio_mode_infos) {
-        return false;
-    }
-    *hidl_radio_mode_infos = {};
-
-    for (const auto& legacy_mac_info : legacy_mac_infos) {
-        V1_2::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
-        if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
-                                            &hidl_radio_mode_info)) {
-            return false;
-        }
-        hidl_radio_mode_infos->push_back(hidl_radio_mode_info);
-    }
-    return true;
-}
-
-bool convertLegacyFeaturesToHidlStaCapabilities(
-    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-    for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
-        if (feature & legacy_logger_feature_set) {
-            *hidl_caps |=
-                convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
-        }
-    }
-    for (const auto feature :
-         {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS,
-          WIFI_FEATURE_RSSI_MONITOR, WIFI_FEATURE_CONTROL_ROAMING,
-          WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND,
-          WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO,
-          WIFI_FEATURE_TDLS, WIFI_FEATURE_TDLS_OFFCHANNEL,
-          WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) {
-        if (feature & legacy_feature_set) {
-            *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
-        }
-    }
-    // There is no flag for this one in the legacy feature set. Adding it to the
-    // set because all the current devices support it.
-    *hidl_caps |= HidlStaIfaceCaps::APF;
-    return true;
-}
-
-bool convertLegacyApfCapabilitiesToHidl(
-    const legacy_hal::PacketFilterCapabilities& legacy_caps,
-    StaApfPacketFilterCapabilities* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    hidl_caps->version = legacy_caps.version;
-    hidl_caps->maxLength = legacy_caps.max_len;
-    return true;
-}
-
-uint8_t convertHidlGscanReportEventFlagToLegacy(
-    StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
-    using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
-    switch (hidl_flag) {
-        case HidlFlag::EACH_SCAN:
-            return REPORT_EVENTS_EACH_SCAN;
-        case HidlFlag::FULL_RESULTS:
-            return REPORT_EVENTS_FULL_RESULTS;
-        case HidlFlag::NO_BATCH:
-            return REPORT_EVENTS_NO_BATCH;
-    };
-    CHECK(false);
-}
-
-StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(uint8_t legacy_flag) {
-    switch (legacy_flag) {
-        case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
-            return StaScanDataFlagMask::INTERRUPTED;
-    };
-    CHECK(false) << "Unknown legacy flag: " << legacy_flag;
-    // To silence the compiler warning about reaching the end of non-void
-    // function.
-    return {};
-}
-
-bool convertLegacyGscanCapabilitiesToHidl(
-    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
-    StaBackgroundScanCapabilities* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
-    hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
-    hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
-    hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
-    return true;
-}
-
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band) {
-    switch (band) {
-        case WifiBand::BAND_UNSPECIFIED:
-            return legacy_hal::WIFI_BAND_UNSPECIFIED;
-        case WifiBand::BAND_24GHZ:
-            return legacy_hal::WIFI_BAND_BG;
-        case WifiBand::BAND_5GHZ:
-            return legacy_hal::WIFI_BAND_A;
-        case WifiBand::BAND_5GHZ_DFS:
-            return legacy_hal::WIFI_BAND_A_DFS;
-        case WifiBand::BAND_5GHZ_WITH_DFS:
-            return legacy_hal::WIFI_BAND_A_WITH_DFS;
-        case WifiBand::BAND_24GHZ_5GHZ:
-            return legacy_hal::WIFI_BAND_ABG;
-        case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
-            return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
-    };
-    CHECK(false);
-}
-
-bool convertHidlGscanParamsToLegacy(
-    const StaBackgroundScanParameters& hidl_scan_params,
-    legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
-    if (!legacy_scan_params) {
-        return false;
-    }
-    *legacy_scan_params = {};
-    legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
-    legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
-    legacy_scan_params->report_threshold_percent =
-        hidl_scan_params.reportThresholdPercent;
-    legacy_scan_params->report_threshold_num_scans =
-        hidl_scan_params.reportThresholdNumScans;
-    if (hidl_scan_params.buckets.size() > MAX_BUCKETS) {
-        return false;
-    }
-    legacy_scan_params->num_buckets = hidl_scan_params.buckets.size();
-    for (uint32_t bucket_idx = 0; bucket_idx < hidl_scan_params.buckets.size();
-         bucket_idx++) {
-        const StaBackgroundScanBucketParameters& hidl_bucket_spec =
-            hidl_scan_params.buckets[bucket_idx];
-        legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
-            legacy_scan_params->buckets[bucket_idx];
-        if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
-            return false;
-        }
-        legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
-        legacy_bucket_spec.band =
-            convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
-        legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
-        legacy_bucket_spec.max_period =
-            hidl_bucket_spec.exponentialMaxPeriodInMs;
-        legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
-        legacy_bucket_spec.step_count = hidl_bucket_spec.exponentialStepCount;
-        legacy_bucket_spec.report_events = 0;
-        using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
-        for (const auto flag : {HidlFlag::EACH_SCAN, HidlFlag::FULL_RESULTS,
-                                HidlFlag::NO_BATCH}) {
-            if (hidl_bucket_spec.eventReportScheme &
-                static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
-                legacy_bucket_spec.report_events |=
-                    convertHidlGscanReportEventFlagToLegacy(flag);
-            }
-        }
-        if (hidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
-            return false;
-        }
-        legacy_bucket_spec.num_channels = hidl_bucket_spec.frequencies.size();
-        for (uint32_t freq_idx = 0;
-             freq_idx < hidl_bucket_spec.frequencies.size(); freq_idx++) {
-            legacy_bucket_spec.channels[freq_idx].channel =
-                hidl_bucket_spec.frequencies[freq_idx];
-        }
-    }
-    return true;
-}
-
-bool convertLegacyIeToHidl(
-    const legacy_hal::wifi_information_element& legacy_ie,
-    WifiInformationElement* hidl_ie) {
-    if (!hidl_ie) {
-        return false;
-    }
-    *hidl_ie = {};
-    hidl_ie->id = legacy_ie.id;
-    hidl_ie->data =
-        std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
-    return true;
-}
-
-bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob, uint32_t ie_blob_len,
-                               std::vector<WifiInformationElement>* hidl_ies) {
-    if (!ie_blob || !hidl_ies) {
-        return false;
-    }
-    *hidl_ies = {};
-    const uint8_t* ies_begin = ie_blob;
-    const uint8_t* ies_end = ie_blob + ie_blob_len;
-    const uint8_t* next_ie = ies_begin;
-    using wifi_ie = legacy_hal::wifi_information_element;
-    constexpr size_t kIeHeaderLen = sizeof(wifi_ie);
-    // Each IE should atleast have the header (i.e |id| & |len| fields).
-    while (next_ie + kIeHeaderLen <= ies_end) {
-        const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
-        uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
-        if (next_ie + curr_ie_len > ies_end) {
-            LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void*)next_ie
-                       << ", Curr IE len: " << curr_ie_len
-                       << ", IEs End: " << (void*)ies_end;
-            break;
-        }
-        WifiInformationElement hidl_ie;
-        if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
-            LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id
-                       << ", len: " << legacy_ie.len;
-            break;
-        }
-        hidl_ies->push_back(std::move(hidl_ie));
-        next_ie += curr_ie_len;
-    }
-    // Check if the blob has been fully consumed.
-    if (next_ie != ies_end) {
-        LOG(ERROR) << "Failed to fully parse IE blob. Next IE: "
-                   << (void*)next_ie << ", IEs End: " << (void*)ies_end;
-    }
-    return true;
-}
-
-bool convertLegacyGscanResultToHidl(
-    const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
-    StaScanResult* hidl_scan_result) {
-    if (!hidl_scan_result) {
-        return false;
-    }
-    *hidl_scan_result = {};
-    hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
-    hidl_scan_result->ssid = std::vector<uint8_t>(
-        legacy_scan_result.ssid,
-        legacy_scan_result.ssid + strnlen(legacy_scan_result.ssid,
-                                          sizeof(legacy_scan_result.ssid) - 1));
-    memcpy(hidl_scan_result->bssid.data(), legacy_scan_result.bssid,
-           hidl_scan_result->bssid.size());
-    hidl_scan_result->frequency = legacy_scan_result.channel;
-    hidl_scan_result->rssi = legacy_scan_result.rssi;
-    hidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
-    hidl_scan_result->capability = legacy_scan_result.capability;
-    if (has_ie_data) {
-        std::vector<WifiInformationElement> ies;
-        if (!convertLegacyIeBlobToHidl(
-                reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
-                legacy_scan_result.ie_length, &ies)) {
-            return false;
-        }
-        hidl_scan_result->informationElements = std::move(ies);
-    }
-    return true;
-}
-
-bool convertLegacyCachedGscanResultsToHidl(
-    const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
-    StaScanData* hidl_scan_data) {
-    if (!hidl_scan_data) {
-        return false;
-    }
-    *hidl_scan_data = {};
-    hidl_scan_data->flags = 0;
-    for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
-        if (legacy_cached_scan_result.flags & flag) {
-            hidl_scan_data->flags |=
-                static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
-                    convertLegacyGscanDataFlagToHidl(flag));
-        }
-    }
-    hidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
-
-    CHECK(legacy_cached_scan_result.num_results >= 0 &&
-          legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN);
-    std::vector<StaScanResult> hidl_scan_results;
-    for (int32_t result_idx = 0;
-         result_idx < legacy_cached_scan_result.num_results; result_idx++) {
-        StaScanResult hidl_scan_result;
-        if (!convertLegacyGscanResultToHidl(
-                legacy_cached_scan_result.results[result_idx], false,
-                &hidl_scan_result)) {
-            return false;
-        }
-        hidl_scan_results.push_back(hidl_scan_result);
-    }
-    hidl_scan_data->results = std::move(hidl_scan_results);
-    return true;
-}
-
-bool convertLegacyVectorOfCachedGscanResultsToHidl(
-    const std::vector<legacy_hal::wifi_cached_scan_results>&
-        legacy_cached_scan_results,
-    std::vector<StaScanData>* hidl_scan_datas) {
-    if (!hidl_scan_datas) {
-        return false;
-    }
-    *hidl_scan_datas = {};
-    for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
-        StaScanData hidl_scan_data;
-        if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result,
-                                                   &hidl_scan_data)) {
-            return false;
-        }
-        hidl_scan_datas->push_back(hidl_scan_data);
-    }
-    return true;
-}
-
-WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(
-    legacy_hal::wifi_tx_packet_fate fate) {
-    switch (fate) {
-        case legacy_hal::TX_PKT_FATE_ACKED:
-            return WifiDebugTxPacketFate::ACKED;
-        case legacy_hal::TX_PKT_FATE_SENT:
-            return WifiDebugTxPacketFate::SENT;
-        case legacy_hal::TX_PKT_FATE_FW_QUEUED:
-            return WifiDebugTxPacketFate::FW_QUEUED;
-        case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
-            return WifiDebugTxPacketFate::FW_DROP_INVALID;
-        case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
-            return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
-        case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
-            return WifiDebugTxPacketFate::FW_DROP_OTHER;
-        case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
-            return WifiDebugTxPacketFate::DRV_QUEUED;
-        case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
-            return WifiDebugTxPacketFate::DRV_DROP_INVALID;
-        case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
-            return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
-        case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
-            return WifiDebugTxPacketFate::DRV_DROP_OTHER;
-    };
-    CHECK(false) << "Unknown legacy fate type: " << fate;
-}
-
-WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToHidl(
-    legacy_hal::wifi_rx_packet_fate fate) {
-    switch (fate) {
-        case legacy_hal::RX_PKT_FATE_SUCCESS:
-            return WifiDebugRxPacketFate::SUCCESS;
-        case legacy_hal::RX_PKT_FATE_FW_QUEUED:
-            return WifiDebugRxPacketFate::FW_QUEUED;
-        case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
-            return WifiDebugRxPacketFate::FW_DROP_FILTER;
-        case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
-            return WifiDebugRxPacketFate::FW_DROP_INVALID;
-        case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
-            return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
-        case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
-            return WifiDebugRxPacketFate::FW_DROP_OTHER;
-        case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
-            return WifiDebugRxPacketFate::DRV_QUEUED;
-        case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
-            return WifiDebugRxPacketFate::DRV_DROP_FILTER;
-        case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
-            return WifiDebugRxPacketFate::DRV_DROP_INVALID;
-        case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
-            return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
-        case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
-            return WifiDebugRxPacketFate::DRV_DROP_OTHER;
-    };
-    CHECK(false) << "Unknown legacy fate type: " << fate;
-}
-
-WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToHidl(
-    legacy_hal::frame_type type) {
-    switch (type) {
-        case legacy_hal::FRAME_TYPE_UNKNOWN:
-            return WifiDebugPacketFateFrameType::UNKNOWN;
-        case legacy_hal::FRAME_TYPE_ETHERNET_II:
-            return WifiDebugPacketFateFrameType::ETHERNET_II;
-        case legacy_hal::FRAME_TYPE_80211_MGMT:
-            return WifiDebugPacketFateFrameType::MGMT_80211;
-    };
-    CHECK(false) << "Unknown legacy frame type: " << type;
-}
-
-bool convertLegacyDebugPacketFateFrameToHidl(
-    const legacy_hal::frame_info& legacy_frame,
-    WifiDebugPacketFateFrameInfo* hidl_frame) {
-    if (!hidl_frame) {
-        return false;
-    }
-    *hidl_frame = {};
-    hidl_frame->frameType =
-        convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
-    hidl_frame->frameLen = legacy_frame.frame_len;
-    hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
-    hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
-    const uint8_t* frame_begin = reinterpret_cast<const uint8_t*>(
-        legacy_frame.frame_content.ethernet_ii_bytes);
-    hidl_frame->frameContent =
-        std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
-    return true;
-}
-
-bool convertLegacyDebugTxPacketFateToHidl(
-    const legacy_hal::wifi_tx_report& legacy_fate,
-    WifiDebugTxPacketFateReport* hidl_fate) {
-    if (!hidl_fate) {
-        return false;
-    }
-    *hidl_fate = {};
-    hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
-    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
-                                                   &hidl_fate->frameInfo);
-}
-
-bool convertLegacyVectorOfDebugTxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
-    std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
-    if (!hidl_fates) {
-        return false;
-    }
-    *hidl_fates = {};
-    for (const auto& legacy_fate : legacy_fates) {
-        WifiDebugTxPacketFateReport hidl_fate;
-        if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
-            return false;
-        }
-        hidl_fates->push_back(hidl_fate);
-    }
-    return true;
-}
-
-bool convertLegacyDebugRxPacketFateToHidl(
-    const legacy_hal::wifi_rx_report& legacy_fate,
-    WifiDebugRxPacketFateReport* hidl_fate) {
-    if (!hidl_fate) {
-        return false;
-    }
-    *hidl_fate = {};
-    hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
-    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
-                                                   &hidl_fate->frameInfo);
-}
-
-bool convertLegacyVectorOfDebugRxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
-    std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
-    if (!hidl_fates) {
-        return false;
-    }
-    *hidl_fates = {};
-    for (const auto& legacy_fate : legacy_fates) {
-        WifiDebugRxPacketFateReport hidl_fate;
-        if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
-            return false;
-        }
-        hidl_fates->push_back(hidl_fate);
-    }
-    return true;
-}
-
-bool convertLegacyLinkLayerRadioStatsToHidl(
-    const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
-    V1_3::StaLinkLayerRadioStats* hidl_radio_stat) {
-    if (!hidl_radio_stat) {
-        return false;
-    }
-    *hidl_radio_stat = {};
-
-    hidl_radio_stat->V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
-    hidl_radio_stat->V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
-    hidl_radio_stat->V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
-    hidl_radio_stat->V1_0.onTimeInMsForScan =
-        legacy_radio_stat.stats.on_time_scan;
-    hidl_radio_stat->V1_0.txTimeInMsPerLevel =
-        legacy_radio_stat.tx_time_per_levels;
-    hidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
-    hidl_radio_stat->onTimeInMsForBgScan =
-        legacy_radio_stat.stats.on_time_gscan;
-    hidl_radio_stat->onTimeInMsForRoamScan =
-        legacy_radio_stat.stats.on_time_roam_scan;
-    hidl_radio_stat->onTimeInMsForPnoScan =
-        legacy_radio_stat.stats.on_time_pno_scan;
-    hidl_radio_stat->onTimeInMsForHs20Scan =
-        legacy_radio_stat.stats.on_time_hs20;
-
-    std::vector<V1_3::WifiChannelStats> hidl_channel_stats;
-
-    for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
-        V1_3::WifiChannelStats hidl_channel_stat;
-        hidl_channel_stat.onTimeInMs = channel_stat.on_time;
-        hidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
-        /*
-         * TODO once b/119142899 is fixed,
-         * replace below code with convertLegacyWifiChannelInfoToHidl()
-         */
-        hidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20;
-        hidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq;
-        hidl_channel_stat.channel.centerFreq0 =
-            channel_stat.channel.center_freq0;
-        hidl_channel_stat.channel.centerFreq1 =
-            channel_stat.channel.center_freq1;
-        hidl_channel_stats.push_back(hidl_channel_stat);
-    }
-
-    hidl_radio_stat->channelStats = hidl_channel_stats;
-
-    return true;
-}
-
-bool convertLegacyLinkLayerStatsToHidl(
-    const legacy_hal::LinkLayerStats& legacy_stats,
-    V1_3::StaLinkLayerStats* hidl_stats) {
-    if (!hidl_stats) {
-        return false;
-    }
-    *hidl_stats = {};
-    // iface legacy_stats conversion.
-    hidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx;
-    hidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
-    hidl_stats->iface.wmeBePktStats.rxMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
-    hidl_stats->iface.wmeBePktStats.txMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
-    hidl_stats->iface.wmeBePktStats.lostMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
-    hidl_stats->iface.wmeBePktStats.retries =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
-    hidl_stats->iface.wmeBkPktStats.rxMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
-    hidl_stats->iface.wmeBkPktStats.txMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
-    hidl_stats->iface.wmeBkPktStats.lostMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
-    hidl_stats->iface.wmeBkPktStats.retries =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
-    hidl_stats->iface.wmeViPktStats.rxMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
-    hidl_stats->iface.wmeViPktStats.txMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
-    hidl_stats->iface.wmeViPktStats.lostMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
-    hidl_stats->iface.wmeViPktStats.retries =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
-    hidl_stats->iface.wmeVoPktStats.rxMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
-    hidl_stats->iface.wmeVoPktStats.txMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
-    hidl_stats->iface.wmeVoPktStats.lostMpdu =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
-    hidl_stats->iface.wmeVoPktStats.retries =
-        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
-    // radio legacy_stats conversion.
-    std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
-    for (const auto& legacy_radio_stats : legacy_stats.radios) {
-        V1_3::StaLinkLayerRadioStats hidl_radio_stats;
-        if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats,
-                                                    &hidl_radio_stats)) {
-            return false;
-        }
-        hidl_radios_stats.push_back(hidl_radio_stats);
-    }
-    hidl_stats->radios = hidl_radios_stats;
-    // Timestamp in the HAL wrapper here since it's not provided in the legacy
-    // HAL API.
-    hidl_stats->timeStampInMs = uptimeMillis();
-    return true;
-}
-
-bool convertLegacyRoamingCapabilitiesToHidl(
-    const legacy_hal::wifi_roaming_capabilities& legacy_caps,
-    StaRoamingCapabilities* hidl_caps) {
-    if (!hidl_caps) {
-        return false;
-    }
-    *hidl_caps = {};
-    hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
-    hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
-    return true;
-}
-
-bool convertHidlRoamingConfigToLegacy(
-    const StaRoamingConfig& hidl_config,
-    legacy_hal::wifi_roaming_config* legacy_config) {
-    if (!legacy_config) {
-        return false;
-    }
-    *legacy_config = {};
-    if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
-        hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
-        return false;
-    }
-    legacy_config->num_blacklist_bssid = hidl_config.bssidBlacklist.size();
-    uint32_t i = 0;
-    for (const auto& bssid : hidl_config.bssidBlacklist) {
-        CHECK(bssid.size() == sizeof(legacy_hal::mac_addr));
-        memcpy(legacy_config->blacklist_bssid[i++], bssid.data(), bssid.size());
-    }
-    legacy_config->num_whitelist_ssid = hidl_config.ssidWhitelist.size();
-    i = 0;
-    for (const auto& ssid : hidl_config.ssidWhitelist) {
-        CHECK(ssid.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
-        legacy_config->whitelist_ssid[i].length = ssid.size();
-        memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data(),
-               ssid.size());
-        i++;
-    }
-    return true;
-}
-
-legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
-    StaRoamingState state) {
-    switch (state) {
-        case StaRoamingState::ENABLED:
-            return legacy_hal::ROAMING_ENABLE;
-        case StaRoamingState::DISABLED:
-            return legacy_hal::ROAMING_DISABLE;
-    };
-    CHECK(false);
-}
-
-legacy_hal::NanMatchAlg convertHidlNanMatchAlgToLegacy(NanMatchAlg type) {
-    switch (type) {
-        case NanMatchAlg::MATCH_ONCE:
-            return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
-        case NanMatchAlg::MATCH_CONTINUOUS:
-            return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
-        case NanMatchAlg::MATCH_NEVER:
-            return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
-    }
-    CHECK(false);
-}
-
-legacy_hal::NanPublishType convertHidlNanPublishTypeToLegacy(
-    NanPublishType type) {
-    switch (type) {
-        case NanPublishType::UNSOLICITED:
-            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
-        case NanPublishType::SOLICITED:
-            return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
-        case NanPublishType::UNSOLICITED_SOLICITED:
-            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
-    }
-    CHECK(false);
-}
-
-legacy_hal::NanTxType convertHidlNanTxTypeToLegacy(NanTxType type) {
-    switch (type) {
-        case NanTxType::BROADCAST:
-            return legacy_hal::NAN_TX_TYPE_BROADCAST;
-        case NanTxType::UNICAST:
-            return legacy_hal::NAN_TX_TYPE_UNICAST;
-    }
-    CHECK(false);
-}
-
-legacy_hal::NanSubscribeType convertHidlNanSubscribeTypeToLegacy(
-    NanSubscribeType type) {
-    switch (type) {
-        case NanSubscribeType::PASSIVE:
-            return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
-        case NanSubscribeType::ACTIVE:
-            return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
-    }
-    CHECK(false);
-}
-
-legacy_hal::NanSRFType convertHidlNanSrfTypeToLegacy(NanSrfType type) {
-    switch (type) {
-        case NanSrfType::BLOOM_FILTER:
-            return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
-        case NanSrfType::PARTIAL_MAC_ADDR:
-            return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
-    }
-    CHECK(false);
-}
-
-legacy_hal::NanDataPathChannelCfg convertHidlNanDataPathChannelCfgToLegacy(
-    NanDataPathChannelCfg type) {
-    switch (type) {
-        case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED:
-            return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED;
-        case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP:
-            return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP;
-        case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP:
-            return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP;
-    }
-    CHECK(false);
-}
-
-NanStatusType convertLegacyNanStatusTypeToHidl(legacy_hal::NanStatusType type) {
-    switch (type) {
-        case legacy_hal::NAN_STATUS_SUCCESS:
-            return NanStatusType::SUCCESS;
-        case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
-            return NanStatusType::INTERNAL_FAILURE;
-        case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
-            return NanStatusType::PROTOCOL_FAILURE;
-        case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
-            return NanStatusType::INVALID_SESSION_ID;
-        case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
-            return NanStatusType::NO_RESOURCES_AVAILABLE;
-        case legacy_hal::NAN_STATUS_INVALID_PARAM:
-            return NanStatusType::INVALID_ARGS;
-        case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
-            return NanStatusType::INVALID_PEER_ID;
-        case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
-            return NanStatusType::INVALID_NDP_ID;
-        case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
-            return NanStatusType::NAN_NOT_ALLOWED;
-        case legacy_hal::NAN_STATUS_NO_OTA_ACK:
-            return NanStatusType::NO_OTA_ACK;
-        case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
-            return NanStatusType::ALREADY_ENABLED;
-        case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
-            return NanStatusType::FOLLOWUP_TX_QUEUE_FULL;
-        case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
-            return NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
-    }
-    CHECK(false);
-}
-
-void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
-                            size_t max_len, WifiNanStatus* wifiNanStatus) {
-    wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(type);
-    wifiNanStatus->description = safeConvertChar(str, max_len);
-}
-
-bool convertHidlNanEnableRequestToLegacy(
-    const NanEnableRequest& hidl_request,
-    legacy_hal::NanEnableRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanEnableRequestToLegacy: null legacy_request";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->config_2dot4g_support = 1;
-    legacy_request->support_2dot4g_val =
-        hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_support_5g = 1;
-    legacy_request->support_5g_val =
-        hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-    legacy_request->config_hop_count_limit = 1;
-    legacy_request->hop_count_limit_val = hidl_request.hopCountMax;
-    legacy_request->master_pref = hidl_request.configParams.masterPref;
-    legacy_request->discovery_indication_cfg = 0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.configParams.disableDiscoveryAddressChangeIndication ? 0x1
-                                                                          : 0x0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
-    legacy_request->config_sid_beacon = 1;
-    if (hidl_request.configParams.numberOfPublishServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
-                      "numberOfPublishServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->sid_beacon_val =
-        (hidl_request.configParams.includePublishServiceIdsInBeacon ? 0x1
-                                                                    : 0x0) |
-        (hidl_request.configParams.numberOfPublishServiceIdsInBeacon << 1);
-    legacy_request->config_subscribe_sid_beacon = 1;
-    if (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
-                      "numberOfSubscribeServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->subscribe_sid_beacon_val =
-        (hidl_request.configParams.includeSubscribeServiceIdsInBeacon ? 0x1
-                                                                      : 0x0) |
-        (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
-    legacy_request->config_rssi_window_size = 1;
-    legacy_request->rssi_window_size_val =
-        hidl_request.configParams.rssiWindowSize;
-    legacy_request->config_disc_mac_addr_randomization = 1;
-    legacy_request->disc_mac_addr_rand_interval_sec =
-        hidl_request.configParams.macAddressRandomizationIntervalSec;
-    legacy_request->config_2dot4g_rssi_close = 1;
-    if (hidl_request.configParams.bandSpecificConfig.size() != 2) {
-        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
-                      "bandSpecificConfig.size() != 2";
-        return false;
-    }
-    legacy_request->rssi_close_2dot4g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .rssiClose;
-    legacy_request->config_2dot4g_rssi_middle = 1;
-    legacy_request->rssi_middle_2dot4g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .rssiMiddle;
-    legacy_request->config_2dot4g_rssi_proximity = 1;
-    legacy_request->rssi_proximity_2dot4g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .rssiCloseProximity;
-    legacy_request->config_scan_params = 1;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .scanPeriodSec;
-    legacy_request->config_dw.config_2dot4g_dw_band =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_2dot4g_interval_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .discoveryWindowIntervalVal;
-    legacy_request->config_5g_rssi_close = 1;
-    legacy_request->rssi_close_5g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .rssiClose;
-    legacy_request->config_5g_rssi_middle = 1;
-    legacy_request->rssi_middle_5g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .rssiMiddle;
-    legacy_request->config_5g_rssi_close_proximity = 1;
-    legacy_request->rssi_close_proximity_5g_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .rssiCloseProximity;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .scanPeriodSec;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .scanPeriodSec;
-    legacy_request->config_dw.config_5g_dw_band =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_5g_interval_val =
-        hidl_request.configParams
-            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .discoveryWindowIntervalVal;
-    if (hidl_request.debugConfigs.validClusterIdVals) {
-        legacy_request->cluster_low =
-            hidl_request.debugConfigs.clusterIdBottomRangeVal;
-        legacy_request->cluster_high =
-            hidl_request.debugConfigs.clusterIdTopRangeVal;
-    } else {  // need 'else' since not configurable in legacy HAL
-        legacy_request->cluster_low = 0x0000;
-        legacy_request->cluster_high = 0xFFFF;
-    }
-    legacy_request->config_intf_addr =
-        hidl_request.debugConfigs.validIntfAddrVal;
-    memcpy(legacy_request->intf_addr_val,
-           hidl_request.debugConfigs.intfAddrVal.data(), 6);
-    legacy_request->config_oui = hidl_request.debugConfigs.validOuiVal;
-    legacy_request->oui_val = hidl_request.debugConfigs.ouiVal;
-    legacy_request->config_random_factor_force =
-        hidl_request.debugConfigs.validRandomFactorForceVal;
-    legacy_request->random_factor_force_val =
-        hidl_request.debugConfigs.randomFactorForceVal;
-    legacy_request->config_hop_count_force =
-        hidl_request.debugConfigs.validHopCountForceVal;
-    legacy_request->hop_count_force_val =
-        hidl_request.debugConfigs.hopCountForceVal;
-    legacy_request->config_24g_channel =
-        hidl_request.debugConfigs.validDiscoveryChannelVal;
-    legacy_request->channel_24g_val =
-        hidl_request.debugConfigs
-            .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_5g_channel =
-        hidl_request.debugConfigs.validDiscoveryChannelVal;
-    legacy_request->channel_5g_val =
-        hidl_request.debugConfigs
-            .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-    legacy_request->config_2dot4g_beacons =
-        hidl_request.debugConfigs.validUseBeaconsInBandVal;
-    legacy_request->beacon_2dot4g_val =
-        hidl_request.debugConfigs
-            .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_5g_beacons =
-        hidl_request.debugConfigs.validUseBeaconsInBandVal;
-    legacy_request->beacon_5g_val =
-        hidl_request.debugConfigs
-            .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-    legacy_request->config_2dot4g_sdf =
-        hidl_request.debugConfigs.validUseSdfInBandVal;
-    legacy_request->sdf_2dot4g_val =
-        hidl_request.debugConfigs
-            .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
-    legacy_request->config_5g_sdf =
-        hidl_request.debugConfigs.validUseSdfInBandVal;
-    legacy_request->sdf_5g_val =
-        hidl_request.debugConfigs
-            .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
-
-    return true;
-}
-
-bool convertHidlNanEnableRequest_1_2ToLegacy(
-    const NanEnableRequest& hidl_request1,
-    const V1_2::NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanEnableRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanEnableRequest_1_2ToLegacy: null legacy_request";
-        return false;
-    }
-
-    *legacy_request = {};
-    if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
-        return false;
-    }
-
-    legacy_request->config_discovery_beacon_int = 1;
-    legacy_request->discovery_beacon_interval =
-        hidl_request2.discoveryBeaconIntervalMs;
-    legacy_request->config_nss = 1;
-    legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
-    legacy_request->config_dw_early_termination = 1;
-    legacy_request->enable_dw_termination =
-        hidl_request2.enableDiscoveryWindowEarlyTermination;
-    legacy_request->config_enable_ranging = 1;
-    legacy_request->enable_ranging = hidl_request2.enableRanging;
-
-    return true;
-}
-
-bool convertHidlNanPublishRequestToLegacy(
-    const NanPublishRequest& hidl_request,
-    legacy_hal::NanPublishRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanPublishRequestToLegacy: null legacy_request";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
-    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
-    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
-    legacy_request->publish_count = hidl_request.baseConfigs.discoveryCount;
-    legacy_request->service_name_len =
-        hidl_request.baseConfigs.serviceName.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_name_len "
-                      "too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name,
-           hidl_request.baseConfigs.serviceName.data(),
-           legacy_request->service_name_len);
-    legacy_request->publish_match_indicator = convertHidlNanMatchAlgToLegacy(
-        hidl_request.baseConfigs.discoveryMatchIndicator);
-    legacy_request->service_specific_info_len =
-        hidl_request.baseConfigs.serviceSpecificInfo.size();
-    if (legacy_request->service_specific_info_len >
-        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_specific_info,
-           hidl_request.baseConfigs.serviceSpecificInfo.data(),
-           legacy_request->service_specific_info_len);
-    legacy_request->sdea_service_specific_info_len =
-        hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
-    if (legacy_request->sdea_service_specific_info_len >
-        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "sdea_service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->sdea_service_specific_info,
-           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
-           legacy_request->sdea_service_specific_info_len);
-    legacy_request->rx_match_filter_len =
-        hidl_request.baseConfigs.rxMatchFilter.size();
-    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "rx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->rx_match_filter,
-           hidl_request.baseConfigs.rxMatchFilter.data(),
-           legacy_request->rx_match_filter_len);
-    legacy_request->tx_match_filter_len =
-        hidl_request.baseConfigs.txMatchFilter.size();
-    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                      "tx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->tx_match_filter,
-           hidl_request.baseConfigs.txMatchFilter.data(),
-           legacy_request->tx_match_filter_len);
-    legacy_request->rssi_threshold_flag =
-        hidl_request.baseConfigs.useRssiThreshold;
-    legacy_request->recv_indication_cfg = 0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
-                                                                       : 0x0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
-    legacy_request->recv_indication_cfg |= 0x8;
-    legacy_request->cipher_type =
-        (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
-    if (hidl_request.baseConfigs.securityConfig.securityType ==
-        NanDataPathSecurityType::PMK) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-        legacy_request->key_info.body.pmk_info.pmk_len =
-            hidl_request.baseConfigs.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len !=
-            NAN_PMK_INFO_LEN) {
-            LOG(ERROR)
-                << "convertHidlNanPublishRequestToLegacy: invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk,
-               hidl_request.baseConfigs.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_request.baseConfigs.securityConfig.securityType ==
-        NanDataPathSecurityType::PASSPHRASE) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-        legacy_request->key_info.body.passphrase_info.passphrase_len =
-            hidl_request.baseConfigs.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.baseConfigs.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->sdea_params.security_cfg =
-        (hidl_request.baseConfigs.securityConfig.securityType !=
-         NanDataPathSecurityType::OPEN)
-            ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-    legacy_request->sdea_params.ranging_state =
-        hidl_request.baseConfigs.rangingRequired
-            ? legacy_hal::NAN_RANGING_ENABLE
-            : legacy_hal::NAN_RANGING_DISABLE;
-    legacy_request->ranging_cfg.ranging_interval_msec =
-        hidl_request.baseConfigs.rangingIntervalMsec;
-    legacy_request->ranging_cfg.config_ranging_indications =
-        hidl_request.baseConfigs.configRangingIndications;
-    legacy_request->ranging_cfg.distance_ingress_mm =
-        hidl_request.baseConfigs.distanceIngressCm * 10;
-    legacy_request->ranging_cfg.distance_egress_mm =
-        hidl_request.baseConfigs.distanceEgressCm * 10;
-    legacy_request->ranging_auto_response =
-        hidl_request.baseConfigs.rangingRequired
-            ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
-            : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
-    legacy_request->sdea_params.range_report =
-        legacy_hal::NAN_DISABLE_RANGE_REPORT;
-    legacy_request->publish_type =
-        convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
-    legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
-    legacy_request->service_responder_policy =
-        hidl_request.autoAcceptDataPathRequests
-            ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
-            : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
-
-    return true;
-}
-
-bool convertHidlNanSubscribeRequestToLegacy(
-    const NanSubscribeRequest& hidl_request,
-    legacy_hal::NanSubscribeRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
-    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
-    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
-    legacy_request->subscribe_count = hidl_request.baseConfigs.discoveryCount;
-    legacy_request->service_name_len =
-        hidl_request.baseConfigs.serviceName.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name,
-           hidl_request.baseConfigs.serviceName.data(),
-           legacy_request->service_name_len);
-    legacy_request->subscribe_match_indicator = convertHidlNanMatchAlgToLegacy(
-        hidl_request.baseConfigs.discoveryMatchIndicator);
-    legacy_request->service_specific_info_len =
-        hidl_request.baseConfigs.serviceSpecificInfo.size();
-    if (legacy_request->service_specific_info_len >
-        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_specific_info,
-           hidl_request.baseConfigs.serviceSpecificInfo.data(),
-           legacy_request->service_specific_info_len);
-    legacy_request->sdea_service_specific_info_len =
-        hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
-    if (legacy_request->sdea_service_specific_info_len >
-        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "sdea_service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->sdea_service_specific_info,
-           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
-           legacy_request->sdea_service_specific_info_len);
-    legacy_request->rx_match_filter_len =
-        hidl_request.baseConfigs.rxMatchFilter.size();
-    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "rx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->rx_match_filter,
-           hidl_request.baseConfigs.rxMatchFilter.data(),
-           legacy_request->rx_match_filter_len);
-    legacy_request->tx_match_filter_len =
-        hidl_request.baseConfigs.txMatchFilter.size();
-    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "tx_match_filter_len too large";
-        return false;
-    }
-    memcpy(legacy_request->tx_match_filter,
-           hidl_request.baseConfigs.txMatchFilter.data(),
-           legacy_request->tx_match_filter_len);
-    legacy_request->rssi_threshold_flag =
-        hidl_request.baseConfigs.useRssiThreshold;
-    legacy_request->recv_indication_cfg = 0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
-                                                                       : 0x0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
-    legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
-    legacy_request->cipher_type =
-        (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
-    if (hidl_request.baseConfigs.securityConfig.securityType ==
-        NanDataPathSecurityType::PMK) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-        legacy_request->key_info.body.pmk_info.pmk_len =
-            hidl_request.baseConfigs.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len !=
-            NAN_PMK_INFO_LEN) {
-            LOG(ERROR)
-                << "convertHidlNanSubscribeRequestToLegacy: invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk,
-               hidl_request.baseConfigs.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_request.baseConfigs.securityConfig.securityType ==
-        NanDataPathSecurityType::PASSPHRASE) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-        legacy_request->key_info.body.passphrase_info.passphrase_len =
-            hidl_request.baseConfigs.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.baseConfigs.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->sdea_params.security_cfg =
-        (hidl_request.baseConfigs.securityConfig.securityType !=
-         NanDataPathSecurityType::OPEN)
-            ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-    legacy_request->sdea_params.ranging_state =
-        hidl_request.baseConfigs.rangingRequired
-            ? legacy_hal::NAN_RANGING_ENABLE
-            : legacy_hal::NAN_RANGING_DISABLE;
-    legacy_request->ranging_cfg.ranging_interval_msec =
-        hidl_request.baseConfigs.rangingIntervalMsec;
-    legacy_request->ranging_cfg.config_ranging_indications =
-        hidl_request.baseConfigs.configRangingIndications;
-    legacy_request->ranging_cfg.distance_ingress_mm =
-        hidl_request.baseConfigs.distanceIngressCm * 10;
-    legacy_request->ranging_cfg.distance_egress_mm =
-        hidl_request.baseConfigs.distanceEgressCm * 10;
-    legacy_request->ranging_auto_response =
-        hidl_request.baseConfigs.rangingRequired
-            ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
-            : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
-    legacy_request->sdea_params.range_report =
-        legacy_hal::NAN_DISABLE_RANGE_REPORT;
-    legacy_request->subscribe_type =
-        convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
-    legacy_request->serviceResponseFilter =
-        convertHidlNanSrfTypeToLegacy(hidl_request.srfType);
-    legacy_request->serviceResponseInclude =
-        hidl_request.srfRespondIfInAddressSet
-            ? legacy_hal::NAN_SRF_INCLUDE_RESPOND
-            : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
-    legacy_request->useServiceResponseFilter =
-        hidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF
-                                  : legacy_hal::NAN_DO_NOT_USE_SRF;
-    legacy_request->ssiRequiredForMatchIndication =
-        hidl_request.isSsiRequiredForMatch
-            ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND
-            : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
-    legacy_request->num_intf_addr_present = hidl_request.intfAddr.size();
-    if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
-        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
-                      "num_intf_addr_present - too many";
-        return false;
-    }
-    for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
-        memcpy(legacy_request->intf_addr[i], hidl_request.intfAddr[i].data(),
-               6);
-    }
-
-    return true;
-}
-
-bool convertHidlNanTransmitFollowupRequestToLegacy(
-    const NanTransmitFollowupRequest& hidl_request,
-    legacy_hal::NanTransmitFollowupRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
-    legacy_request->requestor_instance_id = hidl_request.peerId;
-    memcpy(legacy_request->addr, hidl_request.addr.data(), 6);
-    legacy_request->priority = hidl_request.isHighPriority
-                                   ? legacy_hal::NAN_TX_PRIORITY_HIGH
-                                   : legacy_hal::NAN_TX_PRIORITY_NORMAL;
-    legacy_request->dw_or_faw = hidl_request.shouldUseDiscoveryWindow
-                                    ? legacy_hal::NAN_TRANSMIT_IN_DW
-                                    : legacy_hal::NAN_TRANSMIT_IN_FAW;
-    legacy_request->service_specific_info_len =
-        hidl_request.serviceSpecificInfo.size();
-    if (legacy_request->service_specific_info_len >
-        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
-                      "service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_specific_info,
-           hidl_request.serviceSpecificInfo.data(),
-           legacy_request->service_specific_info_len);
-    legacy_request->sdea_service_specific_info_len =
-        hidl_request.extendedServiceSpecificInfo.size();
-    if (legacy_request->sdea_service_specific_info_len >
-        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
-                      "sdea_service_specific_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->sdea_service_specific_info,
-           hidl_request.extendedServiceSpecificInfo.data(),
-           legacy_request->sdea_service_specific_info_len);
-    legacy_request->recv_indication_cfg =
-        hidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
-
-    return true;
-}
-
-bool convertHidlNanConfigRequestToLegacy(
-    const NanConfigRequest& hidl_request,
-    legacy_hal::NanConfigRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR)
-            << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown
-    // defaults
-    legacy_request->master_pref = hidl_request.masterPref;
-    legacy_request->discovery_indication_cfg = 0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.disableStartedClusterIndication ? 0x2 : 0x0;
-    legacy_request->discovery_indication_cfg |=
-        hidl_request.disableJoinedClusterIndication ? 0x4 : 0x0;
-    legacy_request->config_sid_beacon = 1;
-    if (hidl_request.numberOfPublishServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
-                      "numberOfPublishServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->sid_beacon =
-        (hidl_request.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
-        (hidl_request.numberOfPublishServiceIdsInBeacon << 1);
-    legacy_request->config_subscribe_sid_beacon = 1;
-    if (hidl_request.numberOfSubscribeServiceIdsInBeacon > 127) {
-        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
-                      "numberOfSubscribeServiceIdsInBeacon > 127";
-        return false;
-    }
-    legacy_request->subscribe_sid_beacon_val =
-        (hidl_request.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
-        (hidl_request.numberOfSubscribeServiceIdsInBeacon << 1);
-    legacy_request->config_rssi_window_size = 1;
-    legacy_request->rssi_window_size_val = hidl_request.rssiWindowSize;
-    legacy_request->config_disc_mac_addr_randomization = 1;
-    legacy_request->disc_mac_addr_rand_interval_sec =
-        hidl_request.macAddressRandomizationIntervalSec;
-    /* TODO : missing
-    legacy_request->config_2dot4g_rssi_close = 1;
-    legacy_request->rssi_close_2dot4g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
-    legacy_request->config_2dot4g_rssi_middle = 1;
-    legacy_request->rssi_middle_2dot4g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
-    legacy_request->config_2dot4g_rssi_proximity = 1;
-    legacy_request->rssi_proximity_2dot4g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiCloseProximity;
-    */
-    legacy_request->config_scan_params = 1;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .scanPeriodSec;
-    legacy_request->config_dw.config_2dot4g_dw_band =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_2dot4g_interval_val =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
-            .discoveryWindowIntervalVal;
-    /* TODO: missing
-    legacy_request->config_5g_rssi_close = 1;
-    legacy_request->rssi_close_5g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
-    legacy_request->config_5g_rssi_middle = 1;
-    legacy_request->rssi_middle_5g_val =
-          hidl_request.bandSpecificConfig[
-              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
-    */
-    legacy_request->config_5g_rssi_close_proximity = 1;
-    legacy_request->rssi_close_proximity_5g_val =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .rssiCloseProximity;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .scanPeriodSec;
-    legacy_request->scan_params_val
-        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .dwellTimeMs;
-    legacy_request->scan_params_val
-        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .scanPeriodSec;
-    legacy_request->config_dw.config_5g_dw_band =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .validDiscoveryWindowIntervalVal;
-    legacy_request->config_dw.dw_5g_interval_val =
-        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
-            .discoveryWindowIntervalVal;
-
-    return true;
-}
-
-bool convertHidlNanConfigRequest_1_2ToLegacy(
-    const NanConfigRequest& hidl_request1,
-    const V1_2::NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanConfigRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanConfigRequest_1_2ToLegacy: legacy_request "
-                      "is null";
-        return false;
-    }
-
-    *legacy_request = {};
-    if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
-        return false;
-    }
-
-    legacy_request->config_discovery_beacon_int = 1;
-    legacy_request->discovery_beacon_interval =
-        hidl_request2.discoveryBeaconIntervalMs;
-    legacy_request->config_nss = 1;
-    legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
-    legacy_request->config_dw_early_termination = 1;
-    legacy_request->enable_dw_termination =
-        hidl_request2.enableDiscoveryWindowEarlyTermination;
-    legacy_request->config_enable_ranging = 1;
-    legacy_request->enable_ranging = hidl_request2.enableRanging;
-
-    return true;
-}
-
-bool convertHidlNanDataPathInitiatorRequestToLegacy(
-    const NanInitiateDataPathRequest& hidl_request,
-    legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->requestor_instance_id = hidl_request.peerId;
-    memcpy(legacy_request->peer_disc_mac_addr,
-           hidl_request.peerDiscMacAddr.data(), 6);
-    legacy_request->channel_request_type =
-        convertHidlNanDataPathChannelCfgToLegacy(
-            hidl_request.channelRequestType);
-    legacy_request->channel = hidl_request.channel;
-    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "ifaceName too long";
-        return false;
-    }
-    strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(),
-            IFNAMSIZ + 1);
-    legacy_request->ndp_cfg.security_cfg =
-        (hidl_request.securityConfig.securityType !=
-         NanDataPathSecurityType::OPEN)
-            ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
-    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "ndp_app_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
-           legacy_request->app_info.ndp_app_info_len);
-    legacy_request->cipher_type =
-        (unsigned int)hidl_request.securityConfig.cipherType;
-    if (hidl_request.securityConfig.securityType ==
-        NanDataPathSecurityType::PMK) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-        legacy_request->key_info.body.pmk_info.pmk_len =
-            hidl_request.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len !=
-            NAN_PMK_INFO_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                          "invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk,
-               hidl_request.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_request.securityConfig.securityType ==
-        NanDataPathSecurityType::PASSPHRASE) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-        legacy_request->key_info.body.passphrase_info.passphrase_len =
-            hidl_request.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name,
-           hidl_request.serviceNameOutOfBand.data(),
-           legacy_request->service_name_len);
-
-    return true;
-}
-
-bool convertHidlNanDataPathIndicationResponseToLegacy(
-    const NanRespondToDataPathIndicationRequest& hidl_request,
-    legacy_hal::NanDataPathIndicationResponse* legacy_request) {
-    if (!legacy_request) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "legacy_request is null";
-        return false;
-    }
-    *legacy_request = {};
-
-    legacy_request->rsp_code = hidl_request.acceptRequest
-                                   ? legacy_hal::NAN_DP_REQUEST_ACCEPT
-                                   : legacy_hal::NAN_DP_REQUEST_REJECT;
-    legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
-    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "ifaceName too long";
-        return false;
-    }
-    strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(),
-            IFNAMSIZ + 1);
-    legacy_request->ndp_cfg.security_cfg =
-        (hidl_request.securityConfig.securityType !=
-         NanDataPathSecurityType::OPEN)
-            ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
-    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "ndp_app_info_len too large";
-        return false;
-    }
-    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
-           legacy_request->app_info.ndp_app_info_len);
-    legacy_request->cipher_type =
-        (unsigned int)hidl_request.securityConfig.cipherType;
-    if (hidl_request.securityConfig.securityType ==
-        NanDataPathSecurityType::PMK) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-        legacy_request->key_info.body.pmk_info.pmk_len =
-            hidl_request.securityConfig.pmk.size();
-        if (legacy_request->key_info.body.pmk_info.pmk_len !=
-            NAN_PMK_INFO_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                          "invalid pmk_len";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.pmk_info.pmk,
-               hidl_request.securityConfig.pmk.data(),
-               legacy_request->key_info.body.pmk_info.pmk_len);
-    }
-    if (hidl_request.securityConfig.securityType ==
-        NanDataPathSecurityType::PASSPHRASE) {
-        legacy_request->key_info.key_type =
-            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-        legacy_request->key_info.body.passphrase_info.passphrase_len =
-            hidl_request.securityConfig.passphrase.size();
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
-            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                          "passphrase_len too small";
-            return false;
-        }
-        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
-            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                          "passphrase_len too large";
-            return false;
-        }
-        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-               hidl_request.securityConfig.passphrase.data(),
-               legacy_request->key_info.body.passphrase_info.passphrase_len);
-    }
-    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
-    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
-                      "service_name_len too large";
-        return false;
-    }
-    memcpy(legacy_request->service_name,
-           hidl_request.serviceNameOutOfBand.data(),
-           legacy_request->service_name_len);
-
-    return true;
-}
-
-bool convertLegacyNanResponseHeaderToHidl(
-    const legacy_hal::NanResponseMsg& legacy_response,
-    WifiNanStatus* wifiNanStatus) {
-    if (!wifiNanStatus) {
-        LOG(ERROR)
-            << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
-        return false;
-    }
-    *wifiNanStatus = {};
-
-    convertToWifiNanStatus(legacy_response.status, legacy_response.nan_error,
-                           sizeof(legacy_response.nan_error), wifiNanStatus);
-    return true;
-}
-
-bool convertLegacyNanCapabilitiesResponseToHidl(
-    const legacy_hal::NanCapabilities& legacy_response,
-    NanCapabilities* hidl_response) {
-    if (!hidl_response) {
-        LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: "
-                      "hidl_response is null";
-        return false;
-    }
-    *hidl_response = {};
-
-    hidl_response->maxConcurrentClusters =
-        legacy_response.max_concurrent_nan_clusters;
-    hidl_response->maxPublishes = legacy_response.max_publishes;
-    hidl_response->maxSubscribes = legacy_response.max_subscribes;
-    hidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
-    hidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
-    hidl_response->maxTotalMatchFilterLen =
-        legacy_response.max_total_match_filter_len;
-    hidl_response->maxServiceSpecificInfoLen =
-        legacy_response.max_service_specific_info_len;
-    hidl_response->maxExtendedServiceSpecificInfoLen =
-        legacy_response.max_sdea_service_specific_info_len;
-    hidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
-    hidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
-    hidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
-    hidl_response->maxQueuedTransmitFollowupMsgs =
-        legacy_response.max_queued_transmit_followup_msgs;
-    hidl_response->maxSubscribeInterfaceAddresses =
-        legacy_response.max_subscribe_address;
-    hidl_response->supportedCipherSuites =
-        legacy_response.cipher_suites_supported;
-
-    return true;
-}
-
-bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
-                                    NanMatchInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
-    hidl_ind->peerId = legacy_ind.requestor_instance_id;
-    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
-    hidl_ind->serviceSpecificInfo =
-        std::vector<uint8_t>(legacy_ind.service_specific_info,
-                             legacy_ind.service_specific_info +
-                                 legacy_ind.service_specific_info_len);
-    hidl_ind->extendedServiceSpecificInfo =
-        std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
-                             legacy_ind.sdea_service_specific_info +
-                                 legacy_ind.sdea_service_specific_info_len);
-    hidl_ind->matchFilter = std::vector<uint8_t>(
-        legacy_ind.sdf_match_filter,
-        legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
-    hidl_ind->matchOccuredInBeaconFlag = legacy_ind.match_occured_flag == 1;
-    hidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
-    hidl_ind->rssiValue = legacy_ind.rssi_value;
-    hidl_ind->peerCipherType = (NanCipherSuiteType)legacy_ind.peer_cipher_type;
-    hidl_ind->peerRequiresSecurityEnabledInNdp =
-        legacy_ind.peer_sdea_params.security_cfg ==
-        legacy_hal::NAN_DP_CONFIG_SECURITY;
-    hidl_ind->peerRequiresRanging = legacy_ind.peer_sdea_params.ranging_state ==
-                                    legacy_hal::NAN_RANGING_ENABLE;
-    hidl_ind->rangingMeasurementInCm =
-        legacy_ind.range_info.range_measurement_mm / 10;
-    hidl_ind->rangingIndicationType = legacy_ind.range_info.ranging_event_type;
-
-    return true;
-}
-
-bool convertLegacyNanFollowupIndToHidl(
-    const legacy_hal::NanFollowupInd& legacy_ind,
-    NanFollowupReceivedInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
-    hidl_ind->peerId = legacy_ind.requestor_instance_id;
-    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
-    hidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
-    hidl_ind->serviceSpecificInfo =
-        std::vector<uint8_t>(legacy_ind.service_specific_info,
-                             legacy_ind.service_specific_info +
-                                 legacy_ind.service_specific_info_len);
-    hidl_ind->extendedServiceSpecificInfo =
-        std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
-                             legacy_ind.sdea_service_specific_info +
-                                 legacy_ind.sdea_service_specific_info_len);
-
-    return true;
-}
-
-bool convertLegacyNanDataPathRequestIndToHidl(
-    const legacy_hal::NanDataPathRequestInd& legacy_ind,
-    NanDataPathRequestInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR)
-            << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
-    hidl_ind->peerDiscMacAddr =
-        hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
-    hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
-    hidl_ind->securityRequired =
-        legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
-    hidl_ind->appInfo =
-        std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
-                             legacy_ind.app_info.ndp_app_info +
-                                 legacy_ind.app_info.ndp_app_info_len);
-
-    return true;
-}
-
-bool convertLegacyNdpChannelInfoToHidl(
-    const legacy_hal::NanChannelInfo& legacy_struct,
-    V1_2::NanDataPathChannelInfo* hidl_struct) {
-    if (!hidl_struct) {
-        LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
-        return false;
-    }
-    *hidl_struct = {};
-
-    hidl_struct->channelFreq = legacy_struct.channel;
-    hidl_struct->channelBandwidth = convertLegacyWifiChannelWidthToHidl(
-        (legacy_hal::wifi_channel_width)legacy_struct.bandwidth);
-    hidl_struct->numSpatialStreams = legacy_struct.nss;
-
-    return true;
-}
-
-bool convertLegacyNanDataPathConfirmIndToHidl(
-    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
-    V1_2::NanDataPathConfirmInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR)
-            << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
-    hidl_ind->V1_0.dataPathSetupSuccess =
-        legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
-    hidl_ind->V1_0.peerNdiMacAddr =
-        hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
-    hidl_ind->V1_0.appInfo =
-        std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
-                             legacy_ind.app_info.ndp_app_info +
-                                 legacy_ind.app_info.ndp_app_info_len);
-    hidl_ind->V1_0.status.status =
-        convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
-    hidl_ind->V1_0.status.description = "";  // TODO: b/34059183
-
-    std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
-    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
-        V1_2::NanDataPathChannelInfo hidl_struct;
-        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
-                                               &hidl_struct)) {
-            return false;
-        }
-        channelInfo.push_back(hidl_struct);
-    }
-    hidl_ind->channelInfo = channelInfo;
-
-    return true;
-}
-
-bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
-    const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
-    V1_2::NanDataPathScheduleUpdateInd* hidl_ind) {
-    if (!hidl_ind) {
-        LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
-                      "hidl_ind is null";
-        return false;
-    }
-    *hidl_ind = {};
-
-    hidl_ind->peerDiscoveryAddress =
-        hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
-    std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
-    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
-        V1_2::NanDataPathChannelInfo hidl_struct;
-        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
-                                               &hidl_struct)) {
-            return false;
-        }
-        channelInfo.push_back(hidl_struct);
-    }
-    hidl_ind->channelInfo = channelInfo;
-    std::vector<uint32_t> ndpInstanceIds;
-    for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
-        ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
-    }
-    hidl_ind->ndpInstanceIds = ndpInstanceIds;
-
-    return true;
-}
-
-legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(RttType type) {
-    switch (type) {
-        case RttType::ONE_SIDED:
-            return legacy_hal::RTT_TYPE_1_SIDED;
-        case RttType::TWO_SIDED:
-            return legacy_hal::RTT_TYPE_2_SIDED;
-    };
-    CHECK(false);
-}
-
-RttType convertLegacyRttTypeToHidl(legacy_hal::wifi_rtt_type type) {
-    switch (type) {
-        case legacy_hal::RTT_TYPE_1_SIDED:
-            return RttType::ONE_SIDED;
-        case legacy_hal::RTT_TYPE_2_SIDED:
-            return RttType::TWO_SIDED;
-    };
-    CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::rtt_peer_type convertHidlRttPeerTypeToLegacy(RttPeerType type) {
-    switch (type) {
-        case RttPeerType::AP:
-            return legacy_hal::RTT_PEER_AP;
-        case RttPeerType::STA:
-            return legacy_hal::RTT_PEER_STA;
-        case RttPeerType::P2P_GO:
-            return legacy_hal::RTT_PEER_P2P_GO;
-        case RttPeerType::P2P_CLIENT:
-            return legacy_hal::RTT_PEER_P2P_CLIENT;
-        case RttPeerType::NAN:
-            return legacy_hal::RTT_PEER_NAN;
-    };
-    CHECK(false);
-}
-
-legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(
-    WifiChannelWidthInMhz type) {
-    switch (type) {
-        case WifiChannelWidthInMhz::WIDTH_20:
-            return legacy_hal::WIFI_CHAN_WIDTH_20;
-        case WifiChannelWidthInMhz::WIDTH_40:
-            return legacy_hal::WIFI_CHAN_WIDTH_40;
-        case WifiChannelWidthInMhz::WIDTH_80:
-            return legacy_hal::WIFI_CHAN_WIDTH_80;
-        case WifiChannelWidthInMhz::WIDTH_160:
-            return legacy_hal::WIFI_CHAN_WIDTH_160;
-        case WifiChannelWidthInMhz::WIDTH_80P80:
-            return legacy_hal::WIFI_CHAN_WIDTH_80P80;
-        case WifiChannelWidthInMhz::WIDTH_5:
-            return legacy_hal::WIFI_CHAN_WIDTH_5;
-        case WifiChannelWidthInMhz::WIDTH_10:
-            return legacy_hal::WIFI_CHAN_WIDTH_10;
-        case WifiChannelWidthInMhz::WIDTH_INVALID:
-            return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
-    };
-    CHECK(false);
-}
-
-WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
-    legacy_hal::wifi_channel_width type) {
-    switch (type) {
-        case legacy_hal::WIFI_CHAN_WIDTH_20:
-            return WifiChannelWidthInMhz::WIDTH_20;
-        case legacy_hal::WIFI_CHAN_WIDTH_40:
-            return WifiChannelWidthInMhz::WIDTH_40;
-        case legacy_hal::WIFI_CHAN_WIDTH_80:
-            return WifiChannelWidthInMhz::WIDTH_80;
-        case legacy_hal::WIFI_CHAN_WIDTH_160:
-            return WifiChannelWidthInMhz::WIDTH_160;
-        case legacy_hal::WIFI_CHAN_WIDTH_80P80:
-            return WifiChannelWidthInMhz::WIDTH_80P80;
-        case legacy_hal::WIFI_CHAN_WIDTH_5:
-            return WifiChannelWidthInMhz::WIDTH_5;
-        case legacy_hal::WIFI_CHAN_WIDTH_10:
-            return WifiChannelWidthInMhz::WIDTH_10;
-        case legacy_hal::WIFI_CHAN_WIDTH_INVALID:
-            return WifiChannelWidthInMhz::WIDTH_INVALID;
-    };
-    CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(RttPreamble type) {
-    switch (type) {
-        case RttPreamble::LEGACY:
-            return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
-        case RttPreamble::HT:
-            return legacy_hal::WIFI_RTT_PREAMBLE_HT;
-        case RttPreamble::VHT:
-            return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
-    };
-    CHECK(false);
-}
-
-RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
-    switch (type) {
-        case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
-            return RttPreamble::LEGACY;
-        case legacy_hal::WIFI_RTT_PREAMBLE_HT:
-            return RttPreamble::HT;
-        case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
-            return RttPreamble::VHT;
-    };
-    CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(RttBw type) {
-    switch (type) {
-        case RttBw::BW_5MHZ:
-            return legacy_hal::WIFI_RTT_BW_5;
-        case RttBw::BW_10MHZ:
-            return legacy_hal::WIFI_RTT_BW_10;
-        case RttBw::BW_20MHZ:
-            return legacy_hal::WIFI_RTT_BW_20;
-        case RttBw::BW_40MHZ:
-            return legacy_hal::WIFI_RTT_BW_40;
-        case RttBw::BW_80MHZ:
-            return legacy_hal::WIFI_RTT_BW_80;
-        case RttBw::BW_160MHZ:
-            return legacy_hal::WIFI_RTT_BW_160;
-    };
-    CHECK(false);
-}
-
-RttBw convertLegacyRttBwToHidl(legacy_hal::wifi_rtt_bw type) {
-    switch (type) {
-        case legacy_hal::WIFI_RTT_BW_5:
-            return RttBw::BW_5MHZ;
-        case legacy_hal::WIFI_RTT_BW_10:
-            return RttBw::BW_10MHZ;
-        case legacy_hal::WIFI_RTT_BW_20:
-            return RttBw::BW_20MHZ;
-        case legacy_hal::WIFI_RTT_BW_40:
-            return RttBw::BW_40MHZ;
-        case legacy_hal::WIFI_RTT_BW_80:
-            return RttBw::BW_80MHZ;
-        case legacy_hal::WIFI_RTT_BW_160:
-            return RttBw::BW_160MHZ;
-    };
-    CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(
-    RttMotionPattern type) {
-    switch (type) {
-        case RttMotionPattern::NOT_EXPECTED:
-            return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
-        case RttMotionPattern::EXPECTED:
-            return legacy_hal::WIFI_MOTION_EXPECTED;
-        case RttMotionPattern::UNKNOWN:
-            return legacy_hal::WIFI_MOTION_UNKNOWN;
-    };
-    CHECK(false);
-}
-
-WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
-    switch (preamble) {
-        case 0:
-            return WifiRatePreamble::OFDM;
-        case 1:
-            return WifiRatePreamble::CCK;
-        case 2:
-            return WifiRatePreamble::HT;
-        case 3:
-            return WifiRatePreamble::VHT;
-        default:
-            return WifiRatePreamble::RESERVED;
-    };
-    CHECK(false) << "Unknown legacy preamble: " << preamble;
-}
-
-WifiRateNss convertLegacyWifiRateNssToHidl(uint8_t nss) {
-    switch (nss) {
-        case 0:
-            return WifiRateNss::NSS_1x1;
-        case 1:
-            return WifiRateNss::NSS_2x2;
-        case 2:
-            return WifiRateNss::NSS_3x3;
-        case 3:
-            return WifiRateNss::NSS_4x4;
-    };
-    CHECK(false) << "Unknown legacy nss: " << nss;
-    return {};
-}
-
-RttStatus convertLegacyRttStatusToHidl(legacy_hal::wifi_rtt_status status) {
-    switch (status) {
-        case legacy_hal::RTT_STATUS_SUCCESS:
-            return RttStatus::SUCCESS;
-        case legacy_hal::RTT_STATUS_FAILURE:
-            return RttStatus::FAILURE;
-        case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
-            return RttStatus::FAIL_NO_RSP;
-        case legacy_hal::RTT_STATUS_FAIL_REJECTED:
-            return RttStatus::FAIL_REJECTED;
-        case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
-            return RttStatus::FAIL_NOT_SCHEDULED_YET;
-        case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
-            return RttStatus::FAIL_TM_TIMEOUT;
-        case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
-            return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
-        case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
-            return RttStatus::FAIL_NO_CAPABILITY;
-        case legacy_hal::RTT_STATUS_ABORTED:
-            return RttStatus::ABORTED;
-        case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
-            return RttStatus::FAIL_INVALID_TS;
-        case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
-            return RttStatus::FAIL_PROTOCOL;
-        case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
-            return RttStatus::FAIL_SCHEDULE;
-        case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
-            return RttStatus::FAIL_BUSY_TRY_LATER;
-        case legacy_hal::RTT_STATUS_INVALID_REQ:
-            return RttStatus::INVALID_REQ;
-        case legacy_hal::RTT_STATUS_NO_WIFI:
-            return RttStatus::NO_WIFI;
-        case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
-            return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
-        case legacy_hal::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE:
-            return RttStatus::FAILURE;  // TODO: add HIDL enumeration
-        case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED:
-            return RttStatus::FAILURE;  // TODO: add HIDL enumeration
-    };
-    CHECK(false) << "Unknown legacy status: " << status;
-}
-
-bool convertHidlWifiChannelInfoToLegacy(
-    const WifiChannelInfo& hidl_info,
-    legacy_hal::wifi_channel_info* legacy_info) {
-    if (!legacy_info) {
-        return false;
-    }
-    *legacy_info = {};
-    legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
-    legacy_info->center_freq = hidl_info.centerFreq;
-    legacy_info->center_freq0 = hidl_info.centerFreq0;
-    legacy_info->center_freq1 = hidl_info.centerFreq1;
-    return true;
-}
-
-bool convertLegacyWifiChannelInfoToHidl(
-    const legacy_hal::wifi_channel_info& legacy_info,
-    WifiChannelInfo* hidl_info) {
-    if (!hidl_info) {
-        return false;
-    }
-    *hidl_info = {};
-    hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
-    hidl_info->centerFreq = legacy_info.center_freq;
-    hidl_info->centerFreq0 = legacy_info.center_freq0;
-    hidl_info->centerFreq1 = legacy_info.center_freq1;
-    return true;
-}
-
-bool convertHidlRttConfigToLegacy(const RttConfig& hidl_config,
-                                  legacy_hal::wifi_rtt_config* legacy_config) {
-    if (!legacy_config) {
-        return false;
-    }
-    *legacy_config = {};
-    CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
-    memcpy(legacy_config->addr, hidl_config.addr.data(),
-           hidl_config.addr.size());
-    legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
-    legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
-    if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel,
-                                            &legacy_config->channel)) {
-        return false;
-    }
-    legacy_config->burst_period = hidl_config.burstPeriod;
-    legacy_config->num_burst = hidl_config.numBurst;
-    legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
-    legacy_config->num_retries_per_rtt_frame =
-        hidl_config.numRetriesPerRttFrame;
-    legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
-    legacy_config->LCI_request = hidl_config.mustRequestLci;
-    legacy_config->LCR_request = hidl_config.mustRequestLcr;
-    legacy_config->burst_duration = hidl_config.burstDuration;
-    legacy_config->preamble =
-        convertHidlRttPreambleToLegacy(hidl_config.preamble);
-    legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
-    return true;
-}
-
-bool convertHidlVectorOfRttConfigToLegacy(
-    const std::vector<RttConfig>& hidl_configs,
-    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
-    if (!legacy_configs) {
-        return false;
-    }
-    *legacy_configs = {};
-    for (const auto& hidl_config : hidl_configs) {
-        legacy_hal::wifi_rtt_config legacy_config;
-        if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
-            return false;
-        }
-        legacy_configs->push_back(legacy_config);
-    }
-    return true;
-}
-
-bool convertHidlRttLciInformationToLegacy(
-    const RttLciInformation& hidl_info,
-    legacy_hal::wifi_lci_information* legacy_info) {
-    if (!legacy_info) {
-        return false;
-    }
-    *legacy_info = {};
-    legacy_info->latitude = hidl_info.latitude;
-    legacy_info->longitude = hidl_info.longitude;
-    legacy_info->altitude = hidl_info.altitude;
-    legacy_info->latitude_unc = hidl_info.latitudeUnc;
-    legacy_info->longitude_unc = hidl_info.longitudeUnc;
-    legacy_info->altitude_unc = hidl_info.altitudeUnc;
-    legacy_info->motion_pattern =
-        convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
-    legacy_info->floor = hidl_info.floor;
-    legacy_info->height_above_floor = hidl_info.heightAboveFloor;
-    legacy_info->height_unc = hidl_info.heightUnc;
-    return true;
-}
-
-bool convertHidlRttLcrInformationToLegacy(
-    const RttLcrInformation& hidl_info,
-    legacy_hal::wifi_lcr_information* legacy_info) {
-    if (!legacy_info) {
-        return false;
-    }
-    *legacy_info = {};
-    CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
-    memcpy(legacy_info->country_code, hidl_info.countryCode.data(),
-           hidl_info.countryCode.size());
-    if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
-        return false;
-    }
-    legacy_info->length = hidl_info.civicInfo.size();
-    memcpy(legacy_info->civic_info, hidl_info.civicInfo.c_str(),
-           hidl_info.civicInfo.size());
-    return true;
-}
-
-bool convertHidlRttResponderToLegacy(
-    const RttResponder& hidl_responder,
-    legacy_hal::wifi_rtt_responder* legacy_responder) {
-    if (!legacy_responder) {
-        return false;
-    }
-    *legacy_responder = {};
-    if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel,
-                                            &legacy_responder->channel)) {
-        return false;
-    }
-    legacy_responder->preamble =
-        convertHidlRttPreambleToLegacy(hidl_responder.preamble);
-    return true;
-}
-
-bool convertLegacyRttResponderToHidl(
-    const legacy_hal::wifi_rtt_responder& legacy_responder,
-    RttResponder* hidl_responder) {
-    if (!hidl_responder) {
-        return false;
-    }
-    *hidl_responder = {};
-    if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel,
-                                            &hidl_responder->channel)) {
-        return false;
-    }
-    hidl_responder->preamble =
-        convertLegacyRttPreambleToHidl(legacy_responder.preamble);
-    return true;
-}
-
-bool convertLegacyRttCapabilitiesToHidl(
-    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
-    RttCapabilities* hidl_capabilities) {
-    if (!hidl_capabilities) {
-        return false;
-    }
-    *hidl_capabilities = {};
-    hidl_capabilities->rttOneSidedSupported =
-        legacy_capabilities.rtt_one_sided_supported;
-    hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
-    hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
-    hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
-    hidl_capabilities->responderSupported =
-        legacy_capabilities.responder_supported;
-    hidl_capabilities->preambleSupport = 0;
-    for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY,
-                            legacy_hal::WIFI_RTT_PREAMBLE_HT,
-                            legacy_hal::WIFI_RTT_PREAMBLE_VHT}) {
-        if (legacy_capabilities.preamble_support & flag) {
-            hidl_capabilities->preambleSupport |=
-                static_cast<std::underlying_type<RttPreamble>::type>(
-                    convertLegacyRttPreambleToHidl(flag));
-        }
-    }
-    hidl_capabilities->bwSupport = 0;
-    for (const auto flag :
-         {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10,
-          legacy_hal::WIFI_RTT_BW_20, legacy_hal::WIFI_RTT_BW_40,
-          legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160}) {
-        if (legacy_capabilities.bw_support & flag) {
-            hidl_capabilities->bwSupport |=
-                static_cast<std::underlying_type<RttBw>::type>(
-                    convertLegacyRttBwToHidl(flag));
-        }
-    }
-    hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
-    return true;
-}
-
-bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
-                                     WifiRateInfo* hidl_rate) {
-    if (!hidl_rate) {
-        return false;
-    }
-    *hidl_rate = {};
-    hidl_rate->preamble =
-        convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
-    hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
-    hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
-        static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
-    hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
-    hidl_rate->bitRateInKbps = legacy_rate.bitrate;
-    return true;
-}
-
-bool convertLegacyRttResultToHidl(
-    const legacy_hal::wifi_rtt_result& legacy_result, RttResult* hidl_result) {
-    if (!hidl_result) {
-        return false;
-    }
-    *hidl_result = {};
-    CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
-    memcpy(hidl_result->addr.data(), legacy_result.addr,
-           sizeof(legacy_result.addr));
-    hidl_result->burstNum = legacy_result.burst_num;
-    hidl_result->measurementNumber = legacy_result.measurement_number;
-    hidl_result->successNumber = legacy_result.success_number;
-    hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
-    hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
-    hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
-    hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
-    hidl_result->rssi = legacy_result.rssi;
-    hidl_result->rssiSpread = legacy_result.rssi_spread;
-    if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate,
-                                         &hidl_result->txRate)) {
-        return false;
-    }
-    if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate,
-                                         &hidl_result->rxRate)) {
-        return false;
-    }
-    hidl_result->rtt = legacy_result.rtt;
-    hidl_result->rttSd = legacy_result.rtt_sd;
-    hidl_result->rttSpread = legacy_result.rtt_spread;
-    hidl_result->distanceInMm = legacy_result.distance_mm;
-    hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
-    hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
-    hidl_result->timeStampInUs = legacy_result.ts;
-    hidl_result->burstDurationInMs = legacy_result.burst_duration;
-    hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
-    if (legacy_result.LCI &&
-        !convertLegacyIeToHidl(*legacy_result.LCI, &hidl_result->lci)) {
-        return false;
-    }
-    if (legacy_result.LCR &&
-        !convertLegacyIeToHidl(*legacy_result.LCR, &hidl_result->lcr)) {
-        return false;
-    }
-    return true;
-}
-
-bool convertLegacyVectorOfRttResultToHidl(
-    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
-    std::vector<RttResult>* hidl_results) {
-    if (!hidl_results) {
-        return false;
-    }
-    *hidl_results = {};
-    for (const auto legacy_result : legacy_results) {
-        RttResult hidl_result;
-        if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
-            return false;
-        }
-        hidl_results->push_back(hidl_result);
-    }
-    return true;
-}
-}  // namespace hidl_struct_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/hidl_struct_util.h b/wifi/1.3/default/hidl_struct_util.h
deleted file mode 100644
index 3eefd95..0000000
--- a/wifi/1.3/default/hidl_struct_util.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 HIDL_STRUCT_UTIL_H_
-#define HIDL_STRUCT_UTIL_H_
-
-#include <vector>
-
-#include <android/hardware/wifi/1.0/IWifiChip.h>
-#include <android/hardware/wifi/1.0/types.h>
-#include <android/hardware/wifi/1.2/IWifiChipEventCallback.h>
-#include <android/hardware/wifi/1.2/types.h>
-#include <android/hardware/wifi/1.3/IWifiChip.h>
-#include <android/hardware/wifi/1.3/types.h>
-
-#include "wifi_legacy_hal.h"
-
-/**
- * This file contains a bunch of functions to convert structs from the legacy
- * HAL to HIDL and vice versa.
- * TODO(b/32093047): Add unit tests for these conversion methods in the VTS test
- * suite.
- */
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_struct_util {
-using namespace android::hardware::wifi::V1_0;
-
-// Chip conversion methods.
-bool convertLegacyFeaturesToHidlChipCapabilities(
-    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps);
-bool convertLegacyDebugRingBufferStatusToHidl(
-    const legacy_hal::wifi_ring_buffer_status& legacy_status,
-    WifiDebugRingBufferStatus* hidl_status);
-bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
-    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
-    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
-bool convertLegacyWakeReasonStatsToHidl(
-    const legacy_hal::WakeReasonStats& legacy_stats,
-    WifiDebugHostWakeReasonStats* hidl_stats);
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
-    V1_1::IWifiChip::TxPowerScenario hidl_scenario);
-legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
-    V1_3::IWifiChip::LatencyMode hidl_latency_mode);
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
-    V1_2::IWifiChip::TxPowerScenario hidl_scenario);
-bool convertLegacyWifiMacInfosToHidl(
-    const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-    std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>*
-        hidl_radio_mode_infos);
-
-// STA iface conversion methods.
-bool convertLegacyFeaturesToHidlStaCapabilities(
-    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps);
-bool convertLegacyApfCapabilitiesToHidl(
-    const legacy_hal::PacketFilterCapabilities& legacy_caps,
-    StaApfPacketFilterCapabilities* hidl_caps);
-bool convertLegacyGscanCapabilitiesToHidl(
-    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
-    StaBackgroundScanCapabilities* hidl_caps);
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band);
-bool convertHidlGscanParamsToLegacy(
-    const StaBackgroundScanParameters& hidl_scan_params,
-    legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
-// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
-// Information Elements (IEs)
-bool convertLegacyGscanResultToHidl(
-    const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
-    StaScanResult* hidl_scan_result);
-// |cached_results| is assumed to not include IEs.
-bool convertLegacyVectorOfCachedGscanResultsToHidl(
-    const std::vector<legacy_hal::wifi_cached_scan_results>&
-        legacy_cached_scan_results,
-    std::vector<StaScanData>* hidl_scan_datas);
-bool convertLegacyLinkLayerStatsToHidl(
-    const legacy_hal::LinkLayerStats& legacy_stats,
-    V1_3::StaLinkLayerStats* hidl_stats);
-bool convertLegacyRoamingCapabilitiesToHidl(
-    const legacy_hal::wifi_roaming_capabilities& legacy_caps,
-    StaRoamingCapabilities* hidl_caps);
-bool convertHidlRoamingConfigToLegacy(
-    const StaRoamingConfig& hidl_config,
-    legacy_hal::wifi_roaming_config* legacy_config);
-legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
-    StaRoamingState state);
-bool convertLegacyVectorOfDebugTxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
-    std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
-bool convertLegacyVectorOfDebugRxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
-    std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
-
-// NAN iface conversion methods.
-void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
-                            size_t max_len, WifiNanStatus* wifiNanStatus);
-bool convertHidlNanEnableRequestToLegacy(
-    const NanEnableRequest& hidl_request,
-    legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequestToLegacy(
-    const NanConfigRequest& hidl_request,
-    legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanEnableRequest_1_2ToLegacy(
-    const NanEnableRequest& hidl_request1,
-    const V1_2::NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequest_1_2ToLegacy(
-    const NanConfigRequest& hidl_request1,
-    const V1_2::NanConfigRequestSupplemental& hidl_request2,
-    legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanPublishRequestToLegacy(
-    const NanPublishRequest& hidl_request,
-    legacy_hal::NanPublishRequest* legacy_request);
-bool convertHidlNanSubscribeRequestToLegacy(
-    const NanSubscribeRequest& hidl_request,
-    legacy_hal::NanSubscribeRequest* legacy_request);
-bool convertHidlNanTransmitFollowupRequestToLegacy(
-    const NanTransmitFollowupRequest& hidl_request,
-    legacy_hal::NanTransmitFollowupRequest* legacy_request);
-bool convertHidlNanDataPathInitiatorRequestToLegacy(
-    const NanInitiateDataPathRequest& hidl_request,
-    legacy_hal::NanDataPathInitiatorRequest* legacy_request);
-bool convertHidlNanDataPathIndicationResponseToLegacy(
-    const NanRespondToDataPathIndicationRequest& hidl_response,
-    legacy_hal::NanDataPathIndicationResponse* legacy_response);
-bool convertLegacyNanResponseHeaderToHidl(
-    const legacy_hal::NanResponseMsg& legacy_response,
-    WifiNanStatus* wifiNanStatus);
-bool convertLegacyNanCapabilitiesResponseToHidl(
-    const legacy_hal::NanCapabilities& legacy_response,
-    NanCapabilities* hidl_response);
-bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
-                                    NanMatchInd* hidl_ind);
-bool convertLegacyNanFollowupIndToHidl(
-    const legacy_hal::NanFollowupInd& legacy_ind,
-    NanFollowupReceivedInd* hidl_ind);
-bool convertLegacyNanDataPathRequestIndToHidl(
-    const legacy_hal::NanDataPathRequestInd& legacy_ind,
-    NanDataPathRequestInd* hidl_ind);
-bool convertLegacyNanDataPathConfirmIndToHidl(
-    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
-    V1_2::NanDataPathConfirmInd* hidl_ind);
-bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
-    const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
-    V1_2::NanDataPathScheduleUpdateInd* hidl_ind);
-
-// RTT controller conversion methods.
-bool convertHidlVectorOfRttConfigToLegacy(
-    const std::vector<RttConfig>& hidl_configs,
-    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
-bool convertHidlRttLciInformationToLegacy(
-    const RttLciInformation& hidl_info,
-    legacy_hal::wifi_lci_information* legacy_info);
-bool convertHidlRttLcrInformationToLegacy(
-    const RttLcrInformation& hidl_info,
-    legacy_hal::wifi_lcr_information* legacy_info);
-bool convertHidlRttResponderToLegacy(
-    const RttResponder& hidl_responder,
-    legacy_hal::wifi_rtt_responder* legacy_responder);
-bool convertHidlWifiChannelInfoToLegacy(
-    const WifiChannelInfo& hidl_info,
-    legacy_hal::wifi_channel_info* legacy_info);
-bool convertLegacyRttResponderToHidl(
-    const legacy_hal::wifi_rtt_responder& legacy_responder,
-    RttResponder* hidl_responder);
-bool convertLegacyRttCapabilitiesToHidl(
-    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
-    RttCapabilities* hidl_capabilities);
-bool convertLegacyVectorOfRttResultToHidl(
-    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
-    std::vector<RttResult>* hidl_results);
-}  // namespace hidl_struct_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // HIDL_STRUCT_UTIL_H_
diff --git a/wifi/1.3/default/hidl_sync_util.cpp b/wifi/1.3/default/hidl_sync_util.cpp
deleted file mode 100644
index 160727f..0000000
--- a/wifi/1.3/default/hidl_sync_util.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "hidl_sync_util.h"
-
-namespace {
-std::recursive_mutex g_mutex;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_sync_util {
-
-std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
-    return std::unique_lock<std::recursive_mutex>{g_mutex};
-}
-
-}  // namespace hidl_sync_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/hidl_sync_util.h b/wifi/1.3/default/hidl_sync_util.h
deleted file mode 100644
index ebfb051..0000000
--- a/wifi/1.3/default/hidl_sync_util.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 HIDL_SYNC_UTIL_H_
-#define HIDL_SYNC_UTIL_H_
-
-#include <mutex>
-
-// Utility that provides a global lock to synchronize access between
-// the HIDL thread and the legacy HAL's event loop.
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace hidl_sync_util {
-std::unique_lock<std::recursive_mutex> acquireGlobalLock();
-}  // namespace hidl_sync_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_SYNC_UTIL_H_
diff --git a/wifi/1.3/default/ringbuffer.cpp b/wifi/1.3/default/ringbuffer.cpp
deleted file mode 100644
index 1294c52..0000000
--- a/wifi/1.3/default/ringbuffer.cpp
+++ /dev/null
@@ -1,54 +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 <android-base/logging.h>
-
-#include "ringbuffer.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
-
-void Ringbuffer::append(const std::vector<uint8_t>& input) {
-    if (input.size() == 0) {
-        return;
-    }
-    if (input.size() > maxSize_) {
-        LOG(INFO) << "Oversized message of " << input.size()
-                  << " bytes is dropped";
-        return;
-    }
-    data_.push_back(input);
-    size_ += input.size() * sizeof(input[0]);
-    while (size_ > maxSize_) {
-        size_ -= data_.front().size() * sizeof(data_.front()[0]);
-        data_.pop_front();
-    }
-}
-
-const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
-    return data_;
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/ringbuffer.h b/wifi/1.3/default/ringbuffer.h
deleted file mode 100644
index d9f8df6..0000000
--- a/wifi/1.3/default/ringbuffer.h
+++ /dev/null
@@ -1,53 +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 RINGBUFFER_H_
-#define RINGBUFFER_H_
-
-#include <list>
-#include <vector>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-/**
- * Ringbuffer object used to store debug data.
- */
-class Ringbuffer {
-   public:
-    explicit Ringbuffer(size_t maxSize);
-
-    // Appends the data buffer and deletes from the front until buffer is
-    // within |maxSize_|.
-    void append(const std::vector<uint8_t>& input);
-    const std::list<std::vector<uint8_t>>& getData() const;
-
-   private:
-    std::list<std::vector<uint8_t>> data_;
-    size_t size_;
-    size_t maxSize_;
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // RINGBUFFER_H_
diff --git a/wifi/1.3/default/service.cpp b/wifi/1.3/default/service.cpp
deleted file mode 100644
index 0b41d28..0000000
--- a/wifi/1.3/default/service.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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/HidlLazyUtils.h>
-#include <hidl/HidlTransportSupport.h>
-#include <utils/Looper.h>
-#include <utils/StrongPointer.h>
-
-#include "wifi.h"
-#include "wifi_feature_flags.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_mode_controller.h"
-
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-using android::hardware::LazyServiceRegistrar;
-using android::hardware::wifi::V1_3::implementation::feature_flags::
-    WifiFeatureFlags;
-using android::hardware::wifi::V1_3::implementation::iface_util::WifiIfaceUtil;
-using android::hardware::wifi::V1_3::implementation::legacy_hal::WifiLegacyHal;
-using android::hardware::wifi::V1_3::implementation::mode_controller::
-    WifiModeController;
-
-#ifdef LAZY_SERVICE
-const bool kLazyService = true;
-#else
-const bool kLazyService = false;
-#endif
-
-int main(int /*argc*/, char** argv) {
-    android::base::InitLogging(
-        argv, android::base::LogdLogger(android::base::SYSTEM));
-    LOG(INFO) << "Wifi Hal is booting up...";
-
-    configureRpcThreadpool(1, true /* callerWillJoin */);
-
-    const auto iface_tool =
-        std::make_shared<android::wifi_system::InterfaceTool>();
-    // Setup hwbinder service
-    android::sp<android::hardware::wifi::V1_3::IWifi> service =
-        new android::hardware::wifi::V1_3::implementation::Wifi(
-            iface_tool, std::make_shared<WifiLegacyHal>(iface_tool),
-            std::make_shared<WifiModeController>(),
-            std::make_shared<WifiIfaceUtil>(iface_tool),
-            std::make_shared<WifiFeatureFlags>());
-    if (kLazyService) {
-        auto registrar = LazyServiceRegistrar::getInstance();
-        CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
-            << "Failed to register wifi HAL";
-    } else {
-        CHECK_EQ(service->registerAsService(), android::NO_ERROR)
-            << "Failed to register wifi HAL";
-    }
-
-    joinRpcThreadpool();
-
-    LOG(INFO) << "Wifi Hal is terminating...";
-    return 0;
-}
diff --git a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
deleted file mode 100644
index 4e9ebde..0000000
--- a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN
-#include "hidl_struct_util.h"
-
-using testing::Test;
-
-namespace {
-constexpr uint32_t kMacId1 = 1;
-constexpr uint32_t kMacId2 = 2;
-constexpr uint32_t kIfaceChannel1 = 3;
-constexpr uint32_t kIfaceChannel2 = 5;
-constexpr char kIfaceName1[] = "wlan0";
-constexpr char kIfaceName2[] = "wlan1";
-}  // namespace
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
-
-class HidlStructUtilTest : public Test {};
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
-    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
-    legacy_hal::WifiMacInfo legacy_mac_info1 = {
-        .wlan_mac_id = kMacId1,
-        .mac_band =
-            legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
-                                                    .channel = kIfaceChannel1};
-    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
-                                                    .channel = kIfaceChannel2};
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
-    legacy_mac_infos.push_back(legacy_mac_info1);
-
-    std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>
-        hidl_radio_mode_infos;
-    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
-        legacy_mac_infos, &hidl_radio_mode_infos));
-
-    ASSERT_EQ(1u, hidl_radio_mode_infos.size());
-    auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
-    EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
-    EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
-    ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
-    auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
-              hidl_iface_info1.channel);
-    auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
-    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
-              hidl_iface_info2.channel);
-}
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
-    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
-    legacy_hal::WifiMacInfo legacy_mac_info1 = {
-        .wlan_mac_id = kMacId1, .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
-                                                    .channel = kIfaceChannel1};
-    legacy_hal::WifiMacInfo legacy_mac_info2 = {
-        .wlan_mac_id = kMacId2, .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
-                                                    .channel = kIfaceChannel2};
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
-    legacy_mac_infos.push_back(legacy_mac_info1);
-    legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
-    legacy_mac_infos.push_back(legacy_mac_info2);
-
-    std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>
-        hidl_radio_mode_infos;
-    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
-        legacy_mac_infos, &hidl_radio_mode_infos));
-
-    ASSERT_EQ(2u, hidl_radio_mode_infos.size());
-
-    // Find mac info 1.
-    const auto hidl_radio_mode_info1 =
-        std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
-                     [&legacy_mac_info1](
-                         const V1_2::IWifiChipEventCallback::RadioModeInfo& x) {
-                         return x.radioId == legacy_mac_info1.wlan_mac_id;
-                     });
-    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
-    EXPECT_EQ(WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
-    ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
-    auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
-              hidl_iface_info1.channel);
-
-    // Find mac info 2.
-    const auto hidl_radio_mode_info2 =
-        std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
-                     [&legacy_mac_info2](
-                         const V1_2::IWifiChipEventCallback::RadioModeInfo& x) {
-                         return x.radioId == legacy_mac_info2.wlan_mac_id;
-                     });
-    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
-    EXPECT_EQ(WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
-    ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
-    auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
-              hidl_iface_info2.channel);
-}
-
-TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) {
-    legacy_hal::LinkLayerStats legacy_stats{};
-    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
-    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
-    legacy_stats.iface.beacon_rx = rand();
-    legacy_stats.iface.rssi_mgmt = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
-
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
-
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
-
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
-    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
-
-    for (auto& radio : legacy_stats.radios) {
-        radio.stats.on_time = rand();
-        radio.stats.tx_time = rand();
-        radio.stats.rx_time = rand();
-        radio.stats.on_time_scan = rand();
-        radio.stats.on_time_nbd = rand();
-        radio.stats.on_time_gscan = rand();
-        radio.stats.on_time_roam_scan = rand();
-        radio.stats.on_time_pno_scan = rand();
-        radio.stats.on_time_hs20 = rand();
-        for (int i = 0; i < 4; i++) {
-            radio.tx_time_per_levels.push_back(rand());
-        }
-
-        legacy_hal::wifi_channel_stat channel_stat1 = {
-            .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
-            .on_time = 0x1111,
-            .cca_busy_time = 0x55,
-        };
-        legacy_hal::wifi_channel_stat channel_stat2 = {
-            .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
-            .on_time = 0x2222,
-            .cca_busy_time = 0x66,
-        };
-        radio.channel_stats.push_back(channel_stat1);
-        radio.channel_stats.push_back(channel_stat2);
-    }
-
-    V1_3::StaLinkLayerStats converted{};
-    hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
-                                                        &converted);
-    EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.beaconRx);
-    EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
-              converted.iface.wmeBePktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
-              converted.iface.wmeBePktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
-              converted.iface.wmeBePktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
-              converted.iface.wmeBePktStats.retries);
-
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
-              converted.iface.wmeBkPktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
-              converted.iface.wmeBkPktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
-              converted.iface.wmeBkPktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
-              converted.iface.wmeBkPktStats.retries);
-
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
-              converted.iface.wmeViPktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
-              converted.iface.wmeViPktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
-              converted.iface.wmeViPktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
-              converted.iface.wmeViPktStats.retries);
-
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
-              converted.iface.wmeVoPktStats.rxMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
-              converted.iface.wmeVoPktStats.txMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
-              converted.iface.wmeVoPktStats.lostMpdu);
-    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
-              converted.iface.wmeVoPktStats.retries);
-
-    EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
-    for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time,
-                  converted.radios[i].V1_0.onTimeInMs);
-        EXPECT_EQ(legacy_stats.radios[i].stats.tx_time,
-                  converted.radios[i].V1_0.txTimeInMs);
-        EXPECT_EQ(legacy_stats.radios[i].stats.rx_time,
-                  converted.radios[i].V1_0.rxTimeInMs);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
-                  converted.radios[i].V1_0.onTimeInMsForScan);
-        EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
-                  converted.radios[i].V1_0.txTimeInMsPerLevel.size());
-        for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size();
-             j++) {
-            EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
-                      converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
-        }
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
-                  converted.radios[i].onTimeInMsForNanScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
-                  converted.radios[i].onTimeInMsForBgScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
-                  converted.radios[i].onTimeInMsForRoamScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
-                  converted.radios[i].onTimeInMsForPnoScan);
-        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
-                  converted.radios[i].onTimeInMsForHs20Scan);
-        EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
-                  converted.radios[i].channelStats.size());
-        for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size();
-             k++) {
-            auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
-            EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
-                      converted.radios[i].channelStats[k].channel.width);
-            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq),
-                      converted.radios[i].channelStats[k].channel.centerFreq);
-            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
-                      converted.radios[i].channelStats[k].channel.centerFreq0);
-            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
-                      converted.radios[i].channelStats[k].channel.centerFreq1);
-            EXPECT_EQ(legacy_channel_st.cca_busy_time,
-                      converted.radios[i].channelStats[k].ccaBusyTimeInMs);
-            EXPECT_EQ(legacy_channel_st.on_time,
-                      converted.radios[i].channelStats[k].onTimeInMs);
-        }
-    }
-}
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) {
-    using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
-
-    uint32_t hidle_caps;
-
-    uint32_t legacy_feature_set =
-            WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
-    uint32_t legacy_logger_feature_set =
-            legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
-
-    ASSERT_TRUE(hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
-        legacy_feature_set, legacy_logger_feature_set, &hidle_caps));
-
-    EXPECT_EQ(HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA |
-                  HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS |
-                  HidlChipCaps::DEBUG_ERROR_ALERTS | HidlChipCaps::D2D_RTT |
-                  HidlChipCaps::SET_LATENCY_MODE |
-                  HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP,
-              hidle_caps);
-}
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp
deleted file mode 100644
index a393fdc..0000000
--- a/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gmock/gmock.h>
-
-#include "mock_wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace feature_flags {
-
-MockWifiFeatureFlags::MockWifiFeatureFlags() {}
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_feature_flags.h b/wifi/1.3/default/tests/mock_wifi_feature_flags.h
deleted file mode 100644
index ee12b54..0000000
--- a/wifi/1.3/default/tests/mock_wifi_feature_flags.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_FEATURE_FLAGS_H_
-#define MOCK_WIFI_FEATURE_FLAGS_H_
-
-#include <gmock/gmock.h>
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-
-#include "wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace feature_flags {
-
-class MockWifiFeatureFlags : public WifiFeatureFlags {
-   public:
-    MockWifiFeatureFlags();
-
-    MOCK_METHOD0(getChipModes, std::vector<V1_0::IWifiChip::ChipMode>());
-    MOCK_METHOD0(isApMacRandomizationDisabled, bool());
-};
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.3/default/tests/mock_wifi_iface_util.cpp b/wifi/1.3/default/tests/mock_wifi_iface_util.cpp
deleted file mode 100644
index 3d877c0..0000000
--- a/wifi/1.3/default/tests/mock_wifi_iface_util.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_wifi_iface_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace iface_util {
-
-MockWifiIfaceUtil::MockWifiIfaceUtil(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : WifiIfaceUtil(iface_tool) {}
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_iface_util.h b/wifi/1.3/default/tests/mock_wifi_iface_util.h
deleted file mode 100644
index 8ec93eb..0000000
--- a/wifi/1.3/default/tests/mock_wifi_iface_util.h
+++ /dev/null
@@ -1,51 +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 MOCK_WIFI_IFACE_UTIL_H_
-#define MOCK_WIFI_IFACE_UTIL_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_iface_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace iface_util {
-
-class MockWifiIfaceUtil : public WifiIfaceUtil {
-   public:
-    MockWifiIfaceUtil(
-        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
-    MOCK_METHOD1(getFactoryMacAddress,
-                 std::array<uint8_t, 6>(const std::string&));
-    MOCK_METHOD2(setMacAddress,
-                 bool(const std::string&, const std::array<uint8_t, 6>&));
-    MOCK_METHOD0(getOrCreateRandomMacAddress, std::array<uint8_t, 6>());
-    MOCK_METHOD2(registerIfaceEventHandlers,
-                 void(const std::string&, IfaceEventHandlers));
-    MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&));
-};
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp
deleted file mode 100644
index 0a202c4..0000000
--- a/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace legacy_hal {
-
-MockWifiLegacyHal::MockWifiLegacyHal(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : WifiLegacyHal(iface_tool) {}
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_legacy_hal.h b/wifi/1.3/default/tests/mock_wifi_legacy_hal.h
deleted file mode 100644
index 81cb1de..0000000
--- a/wifi/1.3/default/tests/mock_wifi_legacy_hal.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_LEGACY_HAL_H_
-#define MOCK_WIFI_LEGACY_HAL_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace legacy_hal {
-
-class MockWifiLegacyHal : public WifiLegacyHal {
-   public:
-    MockWifiLegacyHal(
-        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
-    MOCK_METHOD0(initialize, wifi_error());
-    MOCK_METHOD0(start, wifi_error());
-    MOCK_METHOD2(stop, wifi_error(std::unique_lock<std::recursive_mutex>*,
-                                  const std::function<void()>&));
-    MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool));
-    MOCK_METHOD2(registerRadioModeChangeCallbackHandler,
-                 wifi_error(const std::string&,
-                            const on_radio_mode_change_callback&));
-    MOCK_METHOD1(getFirmwareVersion, std::pair<wifi_error, std::string>(
-                 const std::string& iface_name));
-    MOCK_METHOD1(getDriverVersion, std::pair<wifi_error, std::string>(
-                 const std::string& iface_name));
-
-    MOCK_METHOD2(selectTxPowerScenario,
-                 wifi_error(const std::string& iface_name,
-                            wifi_power_scenario scenario));
-    MOCK_METHOD1(resetTxPowerScenario,
-                 wifi_error(const std::string& iface_name));
-    MOCK_METHOD2(nanRegisterCallbackHandlers,
-                 wifi_error(const std::string&, const NanCallbackHandlers&));
-    MOCK_METHOD2(nanDisableRequest,
-                 wifi_error(const std::string&, transaction_id));
-    MOCK_METHOD3(nanDataInterfaceDelete,
-                 wifi_error(const std::string&, transaction_id,
-                            const std::string&));
-};
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp
deleted file mode 100644
index 2b0ea36..0000000
--- a/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "mock_wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace mode_controller {
-
-MockWifiModeController::MockWifiModeController() : WifiModeController() {}
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_mode_controller.h b/wifi/1.3/default/tests/mock_wifi_mode_controller.h
deleted file mode 100644
index c204059..0000000
--- a/wifi/1.3/default/tests/mock_wifi_mode_controller.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MOCK_WIFI_MODE_CONTROLLER_H_
-#define MOCK_WIFI_MODE_CONTROLLER_H_
-
-#include <gmock/gmock.h>
-
-#include "wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace mode_controller {
-
-class MockWifiModeController : public WifiModeController {
-   public:
-    MockWifiModeController();
-    MOCK_METHOD0(initialize, bool());
-    MOCK_METHOD1(changeFirmwareMode, bool(IfaceType));
-    MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType));
-    MOCK_METHOD0(deinitialize, bool());
-};
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // MOCK_WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp
deleted file mode 100644
index 0cf1e4f..0000000
--- a/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp
+++ /dev/null
@@ -1,97 +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 <gmock/gmock.h>
-
-#include "ringbuffer.h"
-
-using testing::Return;
-using testing::Test;
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-class RingbufferTest : public Test {
-   public:
-    const uint32_t maxBufferSize_ = 10;
-    Ringbuffer buffer_{maxBufferSize_};
-};
-
-TEST_F(RingbufferTest, CreateEmptyBuffer) {
-    ASSERT_TRUE(buffer_.getData().empty());
-}
-
-TEST_F(RingbufferTest, CanUseFullBufferCapacity) {
-    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
-    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
-    buffer_.append(input);
-    buffer_.append(input2);
-    ASSERT_EQ(2u, buffer_.getData().size());
-    EXPECT_EQ(input, buffer_.getData().front());
-    EXPECT_EQ(input2, buffer_.getData().back());
-}
-
-TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) {
-    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
-    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
-    const std::vector<uint8_t> input3 = {'G'};
-    buffer_.append(input);
-    buffer_.append(input2);
-    buffer_.append(input3);
-    ASSERT_EQ(2u, buffer_.getData().size());
-    EXPECT_EQ(input2, buffer_.getData().front());
-    EXPECT_EQ(input3, buffer_.getData().back());
-}
-
-TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) {
-    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
-    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
-    const std::vector<uint8_t> input3(maxBufferSize_, '2');
-    buffer_.append(input);
-    buffer_.append(input2);
-    buffer_.append(input3);
-    ASSERT_EQ(1u, buffer_.getData().size());
-    EXPECT_EQ(input3, buffer_.getData().front());
-}
-
-TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) {
-    const std::vector<uint8_t> input = {};
-    buffer_.append(input);
-    ASSERT_TRUE(buffer_.getData().empty());
-}
-
-TEST_F(RingbufferTest, OversizedAppendIsDropped) {
-    const std::vector<uint8_t> input(maxBufferSize_ + 1, '0');
-    buffer_.append(input);
-    ASSERT_TRUE(buffer_.getData().empty());
-}
-
-TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) {
-    const std::vector<uint8_t> input(maxBufferSize_, '0');
-    const std::vector<uint8_t> input2(maxBufferSize_ + 1, '1');
-    buffer_.append(input);
-    buffer_.append(input2);
-    ASSERT_EQ(1u, buffer_.getData().size());
-    EXPECT_EQ(input, buffer_.getData().front());
-}
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp b/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp
deleted file mode 100644
index 680f534..0000000
--- a/wifi/1.3/default/tests/wifi_ap_iface_unit_tests.cpp
+++ /dev/null
@@ -1,79 +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 <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_ap_iface.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_feature_flags.h"
-#include "mock_wifi_iface_util.h"
-#include "mock_wifi_legacy_hal.h"
-
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-
-namespace {
-constexpr char kIfaceName[] = "mockWlan0";
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-class WifiApIfaceTest : public Test {
-   protected:
-    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
-        new NiceMock<wifi_system::MockInterfaceTool>};
-    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
-    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
-        new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
-    std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
-        feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
-};
-
-TEST_F(WifiApIfaceTest, SetRandomMacAddressIfFeatureEnabled) {
-    EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled())
-        .WillOnce(testing::Return(false));
-    EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress())
-        .WillOnce(testing::Return(std::array<uint8_t, 6>{0, 0, 0, 0, 0, 0}));
-    EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_))
-        .WillOnce(testing::Return(true));
-    sp<WifiApIface> ap_iface =
-        new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_);
-}
-
-TEST_F(WifiApIfaceTest, DontSetRandomMacAddressIfFeatureDisabled) {
-    EXPECT_CALL(*feature_flags_, isApMacRandomizationDisabled())
-        .WillOnce(testing::Return(true));
-    EXPECT_CALL(*iface_util_, getOrCreateRandomMacAddress()).Times(0);
-    EXPECT_CALL(*iface_util_, setMacAddress(testing::_, testing::_)).Times(0);
-    sp<WifiApIface> ap_iface =
-        new WifiApIface(kIfaceName, legacy_hal_, iface_util_, feature_flags_);
-}
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
deleted file mode 100644
index d8ce278..0000000
--- a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
+++ /dev/null
@@ -1,871 +0,0 @@
-/*
- * Copyright (C) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_chip.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_feature_flags.h"
-#include "mock_wifi_iface_util.h"
-#include "mock_wifi_legacy_hal.h"
-#include "mock_wifi_mode_controller.h"
-
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-
-namespace {
-using android::hardware::wifi::V1_0::ChipId;
-
-constexpr ChipId kFakeChipId = 5;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-class WifiChipTest : public Test {
-   protected:
-    void setupV1IfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
-            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P}, 1}}}
-        };
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
-            {{{{IfaceType::AP}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
-            {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void setupV1_AwareIfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
-            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
-        };
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
-            {{{{IfaceType::AP}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
-            {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void setupV1_AwareDisabledApIfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
-            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void setupV2_AwareIfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
-            {{{{IfaceType::STA}, 1}, {{IfaceType::AP}, 1}}},
-            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV3, combinations}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void setupV2_AwareDisabledApIfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
-            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV3, combinations}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void setup_MultiIfaceCombination() {
-        // clang-format off
-        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
-            {{{{IfaceType::STA}, 3}, {{IfaceType::AP}, 1}}}
-        };
-        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
-            {feature_flags::chip_mode_ids::kV3, combinations}
-        };
-        // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
-            .WillRepeatedly(testing::Return(modes));
-    }
-
-    void assertNumberOfModes(uint32_t num_modes) {
-        chip_->getAvailableModes(
-            [num_modes](const WifiStatus& status,
-                        const std::vector<WifiChip::ChipMode>& modes) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                // V2_Aware has 1 mode of operation.
-                ASSERT_EQ(num_modes, modes.size());
-            });
-    }
-
-    void findModeAndConfigureForIfaceType(const IfaceType& type) {
-        // This should be aligned with kInvalidModeId in wifi_chip.cpp.
-        ChipModeId mode_id = UINT32_MAX;
-        chip_->getAvailableModes(
-            [&mode_id, &type](const WifiStatus& status,
-                              const std::vector<WifiChip::ChipMode>& modes) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                for (const auto& mode : modes) {
-                    for (const auto& combination : mode.availableCombinations) {
-                        for (const auto& limit : combination.limits) {
-                            if (limit.types.end() !=
-                                std::find(limit.types.begin(),
-                                          limit.types.end(), type)) {
-                                mode_id = mode.id;
-                            }
-                        }
-                    }
-                }
-            });
-        ASSERT_NE(UINT32_MAX, mode_id);
-
-        chip_->configureChip(mode_id, [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-    }
-
-    // Returns an empty string on error.
-    std::string createIface(const IfaceType& type) {
-        std::string iface_name;
-        if (type == IfaceType::AP) {
-            chip_->createApIface([&iface_name](const WifiStatus& status,
-                                               const sp<IWifiApIface>& iface) {
-                if (WifiStatusCode::SUCCESS == status.code) {
-                    ASSERT_NE(iface.get(), nullptr);
-                    iface->getName([&iface_name](const WifiStatus& status,
-                                                 const hidl_string& name) {
-                        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                        iface_name = name.c_str();
-                    });
-                }
-            });
-        } else if (type == IfaceType::NAN) {
-            chip_->createNanIface(
-                [&iface_name](
-                    const WifiStatus& status,
-                    const sp<android::hardware::wifi::V1_0::IWifiNanIface>&
-                        iface) {
-                    if (WifiStatusCode::SUCCESS == status.code) {
-                        ASSERT_NE(iface.get(), nullptr);
-                        iface->getName([&iface_name](const WifiStatus& status,
-                                                     const hidl_string& name) {
-                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                            iface_name = name.c_str();
-                        });
-                    }
-                });
-        } else if (type == IfaceType::P2P) {
-            chip_->createP2pIface(
-                [&iface_name](const WifiStatus& status,
-                              const sp<IWifiP2pIface>& iface) {
-                    if (WifiStatusCode::SUCCESS == status.code) {
-                        ASSERT_NE(iface.get(), nullptr);
-                        iface->getName([&iface_name](const WifiStatus& status,
-                                                     const hidl_string& name) {
-                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                            iface_name = name.c_str();
-                        });
-                    }
-                });
-        } else if (type == IfaceType::STA) {
-            chip_->createStaIface(
-                [&iface_name](const WifiStatus& status,
-                              const sp<V1_0::IWifiStaIface>& iface) {
-                    if (WifiStatusCode::SUCCESS == status.code) {
-                        ASSERT_NE(iface.get(), nullptr);
-                        iface->getName([&iface_name](const WifiStatus& status,
-                                                     const hidl_string& name) {
-                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                            iface_name = name.c_str();
-                        });
-                    }
-                });
-        }
-        return iface_name;
-    }
-
-    void removeIface(const IfaceType& type, const std::string& iface_name) {
-        if (type == IfaceType::AP) {
-            chip_->removeApIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        } else if (type == IfaceType::NAN) {
-            chip_->removeNanIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        } else if (type == IfaceType::P2P) {
-            chip_->removeP2pIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        } else if (type == IfaceType::STA) {
-            chip_->removeStaIface(iface_name, [](const WifiStatus& status) {
-                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            });
-        }
-    }
-
-    bool createRttController() {
-        bool success = false;
-        chip_->createRttController(
-            NULL, [&success](const WifiStatus& status,
-                             const sp<IWifiRttController>& rtt) {
-                if (WifiStatusCode::SUCCESS == status.code) {
-                    ASSERT_NE(rtt.get(), nullptr);
-                    success = true;
-                }
-            });
-        return success;
-    }
-
-    sp<WifiChip> chip_;
-    ChipId chip_id_ = kFakeChipId;
-    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
-        new NiceMock<wifi_system::MockInterfaceTool>};
-    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
-    std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
-        mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
-    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
-        new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
-    std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
-        feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
-
-   public:
-    void SetUp() override {
-        chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_,
-                             iface_util_, feature_flags_);
-
-        EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
-            .WillRepeatedly(testing::Return(true));
-        EXPECT_CALL(*legacy_hal_, start())
-            .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
-    }
-
-    void TearDown() override {
-        // Restore default system iface names (This should ideally be using a
-        // mock).
-        property_set("wifi.interface", "wlan0");
-        property_set("wifi.concurrent.interface", "wlan1");
-    }
-};
-
-////////// V1 Iface Combinations ////////////
-// Mode 1 - STA + P2P
-// Mode 2 - AP
-class WifiChipV1IfaceCombinationTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setupV1IfaceCombination();
-        WifiChipTest::SetUp();
-        // V1 has 2 modes of operation.
-        assertNumberOfModes(2u);
-    }
-};
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-////////// V1 + Aware Iface Combinations ////////////
-// Mode 1 - STA + P2P/NAN
-// Mode 2 - AP
-class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setupV1_AwareIfaceCombination();
-        WifiChipTest::SetUp();
-        // V1_Aware has 2 modes of operation.
-        assertNumberOfModes(2u);
-    }
-};
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
-       StaMode_CreateStaP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
-       StaMode_CreateStaNan_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
-       StaMode_CreateStaP2PNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
-       StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto p2p_iface_name = createIface(IfaceType::P2P);
-    ASSERT_FALSE(p2p_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
-    // After removing P2P iface, NAN iface creation should succeed.
-    removeIface(IfaceType::P2P, p2p_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest,
-       StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto nan_iface_name = createIface(IfaceType::NAN);
-    ASSERT_FALSE(nan_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
-    // After removing NAN iface, P2P iface creation should succeed.
-    removeIface(IfaceType::NAN, nan_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    const auto ap_iface_name = createIface(IfaceType::AP);
-    ASSERT_FALSE(ap_iface_name.empty());
-    ASSERT_FALSE(createRttController());
-
-    removeIface(IfaceType::AP, ap_iface_name);
-
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
-        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
-    chip_->selectTxPowerScenario_1_2(
-        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-        [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-}
-
-TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
-    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
-        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
-    chip_->selectTxPowerScenario_1_2(
-        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-        [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-}
-
-////////// V2 + Aware Iface Combinations ////////////
-// Mode 1 - STA + STA/AP
-//        - STA + P2P/NAN
-class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setupV2_AwareIfaceCombination();
-        WifiChipTest::SetUp();
-        // V2_Aware has 1 mode of operation.
-        assertNumberOfModes(1u);
-    }
-};
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       CreateSta_AfterStaApRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    const auto sta_iface_name = createIface(IfaceType::STA);
-    ASSERT_FALSE(sta_iface_name.empty());
-    const auto ap_iface_name = createIface(IfaceType::AP);
-    ASSERT_FALSE(ap_iface_name.empty());
-
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-
-    // After removing AP & STA iface, STA iface creation should succeed.
-    removeIface(IfaceType::STA, sta_iface_name);
-    removeIface(IfaceType::AP, ap_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       CreateStaNan_AfterP2pRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto p2p_iface_name = createIface(IfaceType::P2P);
-    ASSERT_FALSE(p2p_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
-    // After removing P2P iface, NAN iface creation should succeed.
-    removeIface(IfaceType::P2P, p2p_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       CreateStaP2p_AfterNanRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto nan_iface_name = createIface(IfaceType::NAN);
-    ASSERT_FALSE(nan_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
-    // After removing NAN iface, P2P iface creation should succeed.
-    removeIface(IfaceType::NAN, nan_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto p2p_iface_name = createIface(IfaceType::P2P);
-    ASSERT_FALSE(p2p_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
-
-    // After removing P2P iface, NAN iface creation should succeed.
-    removeIface(IfaceType::P2P, p2p_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    const auto nan_iface_name = createIface(IfaceType::NAN);
-    ASSERT_FALSE(nan_iface_name.empty());
-    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
-
-    // After removing NAN iface, P2P iface creation should succeed.
-    removeIface(IfaceType::NAN, nan_iface_name);
-    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       CreateStaAp_EnsureDifferentIfaceNames) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    const auto sta_iface_name = createIface(IfaceType::STA);
-    const auto ap_iface_name = createIface(IfaceType::AP);
-    ASSERT_FALSE(sta_iface_name.empty());
-    ASSERT_FALSE(ap_iface_name.empty());
-    ASSERT_NE(sta_iface_name, ap_iface_name);
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::AP).empty());
-    ASSERT_TRUE(createRttController());
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
-        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
-    chip_->selectTxPowerScenario_1_2(
-        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-        [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
-    findModeAndConfigureForIfaceType(IfaceType::AP);
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_))
-        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
-    chip_->selectTxPowerScenario_1_2(
-        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
-        [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       InvalidateAndRemoveNanOnStaRemove) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-
-    // Create NAN iface
-    ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
-
-    // We should have 1 nan iface.
-    chip_->getNanIfaceNames(
-        [](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            ASSERT_EQ(iface_names.size(), 1u);
-            ASSERT_EQ(iface_names[0], "wlan0");
-        });
-    // Retrieve the exact iface object.
-    sp<IWifiNanIface> nan_iface;
-    chip_->getNanIface("wlan0", [&nan_iface](const WifiStatus& status,
-                                             const sp<IWifiNanIface>& iface) {
-        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        ASSERT_NE(iface.get(), nullptr);
-        nan_iface = iface;
-    });
-
-    // Remove the STA iface.
-    removeIface(IfaceType::STA, "wlan0");
-    // We should have 0 nan iface now.
-    chip_->getNanIfaceNames(
-        [](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-            ASSERT_EQ(iface_names.size(), 0u);
-        });
-    // Any operation on the nan iface object should return error now.
-    nan_iface->getName(
-        [](const WifiStatus& status, const std::string& /* iface_name */) {
-            ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, status.code);
-        });
-}
-
-TEST_F(WifiChipV2_AwareIfaceCombinationTest,
-       InvalidateAndRemoveRttControllerOnStaRemove) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-
-    // Create RTT controller
-    sp<IWifiRttController> rtt_controller;
-    chip_->createRttController(
-        NULL, [&rtt_controller](const WifiStatus& status,
-                                const sp<IWifiRttController>& rtt) {
-            if (WifiStatusCode::SUCCESS == status.code) {
-                ASSERT_NE(rtt.get(), nullptr);
-                rtt_controller = rtt;
-            }
-        });
-
-    // Remove the STA iface.
-    removeIface(IfaceType::STA, "wlan0");
-
-    // Any operation on the rtt controller object should return error now.
-    rtt_controller->getBoundIface(
-        [](const WifiStatus& status, const sp<IWifiIface>& /* iface */) {
-            ASSERT_EQ(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                      status.code);
-        });
-}
-
-////////// V1 Iface Combinations when AP creation is disabled //////////
-class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setupV1_AwareDisabledApIfaceCombination();
-        WifiChipTest::SetUp();
-    }
-};
-
-TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest,
-       StaMode_CreateSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-////////// V2 Iface Combinations when AP creation is disabled //////////
-class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setupV2_AwareDisabledApIfaceCombination();
-        WifiChipTest::SetUp();
-    }
-};
-
-TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest,
-       CreateSta_ShouldSucceed) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_TRUE(createIface(IfaceType::AP).empty());
-}
-
-////////// Hypothetical Iface Combination with multiple ifaces //////////
-class WifiChip_MultiIfaceTest : public WifiChipTest {
-   public:
-    void SetUp() override {
-        setup_MultiIfaceCombination();
-        WifiChipTest::SetUp();
-    }
-};
-
-TEST_F(WifiChip_MultiIfaceTest, Create3Sta) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_FALSE(createIface(IfaceType::STA).empty());
-    ASSERT_TRUE(createIface(IfaceType::STA).empty());
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateStaWithDefaultNames) {
-    property_set("wifi.interface.0", "");
-    property_set("wifi.interface.1", "");
-    property_set("wifi.interface.2", "");
-    property_set("wifi.interface", "");
-    property_set("wifi.concurrent.interface", "");
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomNames) {
-    property_set("wifi.interface.0", "test0");
-    property_set("wifi.interface.1", "test1");
-    property_set("wifi.interface.2", "test2");
-    property_set("wifi.interface", "bad0");
-    property_set("wifi.concurrent.interface", "bad1");
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "bad0");
-    ASSERT_EQ(createIface(IfaceType::STA), "bad1");
-    ASSERT_EQ(createIface(IfaceType::STA), "test2");
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomAltNames) {
-    property_set("wifi.interface.0", "");
-    property_set("wifi.interface.1", "");
-    property_set("wifi.interface.2", "");
-    property_set("wifi.interface", "testA0");
-    property_set("wifi.concurrent.interface", "testA1");
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    ASSERT_EQ(createIface(IfaceType::STA), "testA0");
-    ASSERT_EQ(createIface(IfaceType::STA), "testA1");
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
-}
-
-TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
-    findModeAndConfigureForIfaceType(IfaceType::STA);
-    // First AP will be slotted to wlan1.
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
-    // First STA will be slotted to wlan0.
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
-    // All further STA will be slotted to the remaining free indices.
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
-}
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp
deleted file mode 100644
index 28d23ff..0000000
--- a/wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp
+++ /dev/null
@@ -1,96 +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 <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN
-#include "wifi_iface_util.h"
-
-#include "mock_interface_tool.h"
-
-using testing::NiceMock;
-using testing::Test;
-
-namespace {
-constexpr uint8_t kValidUnicastLocallyAssignedMacAddressMask = 0x02;
-constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
-constexpr char kIfaceName[] = "test-wlan0";
-
-bool isValidUnicastLocallyAssignedMacAddress(
-    const std::array<uint8_t, 6>& mac_address) {
-    uint8_t first_byte = mac_address[0];
-    return (first_byte & 0x3) == kValidUnicastLocallyAssignedMacAddressMask;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace iface_util {
-class WifiIfaceUtilTest : public Test {
-   protected:
-    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
-        new NiceMock<wifi_system::MockInterfaceTool>};
-    WifiIfaceUtil* iface_util_ = new WifiIfaceUtil(iface_tool_);
-};
-
-TEST_F(WifiIfaceUtilTest, GetOrCreateRandomMacAddress) {
-    auto mac_address = iface_util_->getOrCreateRandomMacAddress();
-    ASSERT_TRUE(isValidUnicastLocallyAssignedMacAddress(mac_address));
-
-    // All further calls should return the same MAC address.
-    ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
-    ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
-}
-
-TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) {
-    std::array<uint8_t, 6> mac_address = {};
-    std::copy(std::begin(kMacAddress), std::end(kMacAddress),
-              std::begin(mac_address));
-    EXPECT_CALL(*iface_tool_, SetMacAddress(testing::_, testing::_))
-        .WillRepeatedly(testing::Return(true));
-    EXPECT_CALL(*iface_tool_, SetUpState(testing::_, testing::_))
-        .WillRepeatedly(testing::Return(true));
-
-    // Register for iface state toggle events.
-    bool callback_invoked = false;
-    iface_util::IfaceEventHandlers event_handlers = {};
-    event_handlers.on_state_toggle_off_on =
-        [&callback_invoked](const std::string& /* iface_name */) {
-            callback_invoked = true;
-        };
-    iface_util_->registerIfaceEventHandlers(kIfaceName, event_handlers);
-    // Invoke setMacAddress and ensure that the cb is invoked.
-    ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
-    ASSERT_TRUE(callback_invoked);
-
-    // Unregister for iface state toggle events.
-    callback_invoked = false;
-    iface_util_->unregisterIfaceEventHandlers(kIfaceName);
-    // Invoke setMacAddress and ensure that the cb is not invoked.
-    ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
-    ASSERT_FALSE(callback_invoked);
-}
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp
deleted file mode 100644
index eb6c610..0000000
--- a/wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp
+++ /dev/null
@@ -1,148 +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 <android-base/macros.h>
-#include <cutils/properties.h>
-#include <gmock/gmock.h>
-
-#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
-#include "wifi_nan_iface.h"
-
-#include "mock_interface_tool.h"
-#include "mock_wifi_feature_flags.h"
-#include "mock_wifi_iface_util.h"
-#include "mock_wifi_legacy_hal.h"
-
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-
-namespace {
-constexpr char kIfaceName[] = "mockWlan0";
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-bool CaptureIfaceEventHandlers(
-    const std::string& /* iface_name*/,
-    iface_util::IfaceEventHandlers in_iface_event_handlers,
-    iface_util::IfaceEventHandlers* out_iface_event_handlers) {
-    *out_iface_event_handlers = in_iface_event_handlers;
-    return true;
-}
-
-class MockNanIfaceEventCallback : public IWifiNanIfaceEventCallback {
-   public:
-    MockNanIfaceEventCallback() = default;
-
-    MOCK_METHOD3(notifyCapabilitiesResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&,
-                              const NanCapabilities&));
-    MOCK_METHOD2(notifyEnableResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyConfigResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyDisableResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD3(notifyStartPublishResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
-    MOCK_METHOD2(notifyStopPublishResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD3(notifyStartSubscribeResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
-    MOCK_METHOD2(notifyStopSubscribeResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyTransmitFollowupResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyCreateDataInterfaceResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyDeleteDataInterfaceResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD3(notifyInitiateDataPathResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&, uint32_t));
-    MOCK_METHOD2(notifyRespondToDataPathIndicationResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD2(notifyTerminateDataPathResponse,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD1(eventClusterEvent, Return<void>(const NanClusterEventInd&));
-    MOCK_METHOD1(eventDisabled, Return<void>(const WifiNanStatus&));
-    MOCK_METHOD2(eventPublishTerminated,
-                 Return<void>(uint8_t, const WifiNanStatus&));
-    MOCK_METHOD2(eventSubscribeTerminated,
-                 Return<void>(uint8_t, const WifiNanStatus&));
-    MOCK_METHOD1(eventMatch, Return<void>(const NanMatchInd&));
-    MOCK_METHOD2(eventMatchExpired, Return<void>(uint8_t, uint32_t));
-    MOCK_METHOD1(eventFollowupReceived,
-                 Return<void>(const NanFollowupReceivedInd&));
-    MOCK_METHOD2(eventTransmitFollowup,
-                 Return<void>(uint16_t, const WifiNanStatus&));
-    MOCK_METHOD1(eventDataPathRequest,
-                 Return<void>(const NanDataPathRequestInd&));
-    MOCK_METHOD1(eventDataPathConfirm,
-                 Return<void>(const NanDataPathConfirmInd&));
-    MOCK_METHOD1(eventDataPathTerminated, Return<void>(uint32_t));
-};
-
-class WifiNanIfaceTest : public Test {
-   protected:
-    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
-        new NiceMock<wifi_system::MockInterfaceTool>};
-    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
-    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
-        new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
-};
-
-TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) {
-    iface_util::IfaceEventHandlers captured_iface_event_handlers = {};
-    EXPECT_CALL(*legacy_hal_,
-                nanRegisterCallbackHandlers(testing::_, testing::_))
-        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
-    EXPECT_CALL(*iface_util_,
-                registerIfaceEventHandlers(testing::_, testing::_))
-        .WillOnce(testing::Invoke(
-            bind(CaptureIfaceEventHandlers, std::placeholders::_1,
-                 std::placeholders::_2, &captured_iface_event_handlers)));
-    sp<WifiNanIface> nan_iface =
-        new WifiNanIface(kIfaceName, legacy_hal_, iface_util_);
-
-    // Register a mock nan event callback.
-    sp<NiceMock<MockNanIfaceEventCallback>> mock_event_callback{
-        new NiceMock<MockNanIfaceEventCallback>};
-    nan_iface->registerEventCallback(
-        mock_event_callback, [](const WifiStatus& status) {
-            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-        });
-    // Ensure that the eventDisabled() function in mock callback will be
-    // invoked.
-    WifiNanStatus expected_nan_status = {
-        NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
-    EXPECT_CALL(*mock_event_callback, eventDisabled(expected_nan_status))
-        .Times(1);
-
-    // Trigger the iface state toggle callback.
-    captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
-}
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi.cpp b/wifi/1.3/default/wifi.cpp
deleted file mode 100644
index 4229d35..0000000
--- a/wifi/1.3/default/wifi.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_return_util.h"
-#include "wifi.h"
-#include "wifi_status_util.h"
-
-namespace {
-// Chip ID to use for the only supported chip.
-static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-using hidl_return_util::validateAndCallWithLock;
-
-Wifi::Wifi(
-    const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
-    const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-    const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
-    const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
-    const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
-    : iface_tool_(iface_tool),
-      legacy_hal_(legacy_hal),
-      mode_controller_(mode_controller),
-      iface_util_(iface_util),
-      feature_flags_(feature_flags),
-      run_state_(RunState::STOPPED) {}
-
-bool Wifi::isValid() {
-    // This object is always valid.
-    return true;
-}
-
-Return<void> Wifi::registerEventCallback(
-    const sp<IWifiEventCallback>& event_callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::registerEventCallbackInternal, hidl_status_cb,
-                           event_callback);
-}
-
-Return<bool> Wifi::isStarted() { return run_state_ != RunState::STOPPED; }
-
-Return<void> Wifi::start(start_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::startInternal, hidl_status_cb);
-}
-
-Return<void> Wifi::stop(stop_cb hidl_status_cb) {
-    return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN,
-                                   &Wifi::stopInternal, hidl_status_cb);
-}
-
-Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::getChipIdsInternal, hidl_status_cb);
-}
-
-Return<void> Wifi::getChip(ChipId chip_id, getChip_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
-                           &Wifi::getChipInternal, hidl_status_cb, chip_id);
-}
-
-Return<void> Wifi::debug(const hidl_handle& handle,
-                         const hidl_vec<hidl_string>&) {
-    LOG(INFO) << "-----------Debug is called----------------";
-    if (!chip_.get()) {
-        return Void();
-    }
-    return chip_->debug(handle, {});
-}
-
-WifiStatus Wifi::registerEventCallbackInternal(
-    const sp<IWifiEventCallback>& event_callback) {
-    if (!event_cb_handler_.addCallback(event_callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus Wifi::startInternal() {
-    if (run_state_ == RunState::STARTED) {
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    } else if (run_state_ == RunState::STOPPING) {
-        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
-                                "HAL is stopping");
-    }
-    WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
-    if (wifi_status.code == WifiStatusCode::SUCCESS) {
-        // Create the chip instance once the HAL is started.
-        chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
-                             iface_util_, feature_flags_);
-        run_state_ = RunState::STARTED;
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onStart().isOk()) {
-                LOG(ERROR) << "Failed to invoke onStart callback";
-            };
-        }
-        LOG(INFO) << "Wifi HAL started";
-    } else {
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onFailure(wifi_status).isOk()) {
-                LOG(ERROR) << "Failed to invoke onFailure callback";
-            }
-        }
-        LOG(ERROR) << "Wifi HAL start failed";
-        // Clear the event callback objects since the HAL start failed.
-        event_cb_handler_.invalidate();
-    }
-    return wifi_status;
-}
-
-WifiStatus Wifi::stopInternal(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
-    if (run_state_ == RunState::STOPPED) {
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    } else if (run_state_ == RunState::STOPPING) {
-        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
-                                "HAL is stopping");
-    }
-    // Clear the chip object and its child objects since the HAL is now
-    // stopped.
-    if (chip_.get()) {
-        chip_->invalidate();
-        chip_.clear();
-    }
-    WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
-    if (wifi_status.code == WifiStatusCode::SUCCESS) {
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onStop().isOk()) {
-                LOG(ERROR) << "Failed to invoke onStop callback";
-            };
-        }
-        LOG(INFO) << "Wifi HAL stopped";
-    } else {
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onFailure(wifi_status).isOk()) {
-                LOG(ERROR) << "Failed to invoke onFailure callback";
-            }
-        }
-        LOG(ERROR) << "Wifi HAL stop failed";
-    }
-    // Clear the event callback objects since the HAL is now stopped.
-    event_cb_handler_.invalidate();
-    return wifi_status;
-}
-
-std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
-    std::vector<ChipId> chip_ids;
-    if (chip_.get()) {
-        chip_ids.emplace_back(kChipId);
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
-}
-
-std::pair<WifiStatus, sp<IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
-    if (!chip_.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_STARTED), nullptr};
-    }
-    if (chip_id != kChipId) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
-}
-
-WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
-    if (!mode_controller_->initialize()) {
-        LOG(ERROR) << "Failed to initialize firmware mode controller";
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to initialize legacy HAL: "
-                   << legacyErrorToString(legacy_status);
-        return createWifiStatusFromLegacyError(legacy_status);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
-    run_state_ = RunState::STOPPING;
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; });
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to stop legacy HAL: "
-                   << legacyErrorToString(legacy_status);
-        return createWifiStatusFromLegacyError(legacy_status);
-    }
-    if (!mode_controller_->deinitialize()) {
-        LOG(ERROR) << "Failed to deinitialize firmware mode controller";
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi.h b/wifi/1.3/default/wifi.h
deleted file mode 100644
index 1c2a154..0000000
--- a/wifi/1.3/default/wifi.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_H_
-#define WIFI_H_
-
-#include <functional>
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.3/IWifi.h>
-#include <utils/Looper.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_chip.h"
-#include "wifi_feature_flags.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-/**
- * Root HIDL interface object used to control the Wifi HAL.
- */
-class Wifi : public V1_3::IWifi {
-   public:
-    Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
-         const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-         const std::shared_ptr<mode_controller::WifiModeController>
-             mode_controller,
-         const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
-         const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags);
-
-    bool isValid();
-
-    // HIDL methods exposed.
-    Return<void> registerEventCallback(
-        const sp<IWifiEventCallback>& event_callback,
-        registerEventCallback_cb hidl_status_cb) override;
-    Return<bool> isStarted() override;
-    Return<void> start(start_cb hidl_status_cb) override;
-    Return<void> stop(stop_cb hidl_status_cb) override;
-    Return<void> getChipIds(getChipIds_cb hidl_status_cb) override;
-    Return<void> getChip(ChipId chip_id, getChip_cb hidl_status_cb) override;
-    Return<void> debug(const hidl_handle& handle,
-                       const hidl_vec<hidl_string>& options) override;
-
-   private:
-    enum class RunState { STOPPED, STARTED, STOPPING };
-
-    // Corresponding worker functions for the HIDL methods.
-    WifiStatus registerEventCallbackInternal(
-        const sp<IWifiEventCallback>& event_callback);
-    WifiStatus startInternal();
-    WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
-    std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
-    std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
-
-    WifiStatus initializeModeControllerAndLegacyHal();
-    WifiStatus stopLegacyHalAndDeinitializeModeController(
-        std::unique_lock<std::recursive_mutex>* lock);
-
-    // Instance is created in this root level |IWifi| HIDL interface object
-    // and shared with all the child HIDL interface objects.
-    std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
-    std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
-    std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
-    std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
-    RunState run_state_;
-    sp<WifiChip> chip_;
-    hidl_callback_util::HidlCallbackHandler<IWifiEventCallback>
-        event_cb_handler_;
-
-    DISALLOW_COPY_AND_ASSIGN(Wifi);
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_H_
diff --git a/wifi/1.3/default/wifi_ap_iface.cpp b/wifi/1.3/default/wifi_ap_iface.cpp
deleted file mode 100644
index 9a8681a..0000000
--- a/wifi/1.3/default/wifi_ap_iface.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_ap_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiApIface::WifiApIface(
-    const std::string& ifname,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
-    const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
-    : ifname_(ifname),
-      legacy_hal_(legacy_hal),
-      iface_util_(iface_util),
-      feature_flags_(feature_flags),
-      is_valid_(true) {
-    if (feature_flags_.lock()->isApMacRandomizationDisabled()) {
-        LOG(INFO) << "AP MAC randomization disabled";
-        return;
-    }
-    LOG(INFO) << "AP MAC randomization enabled";
-    // Set random MAC address
-    std::array<uint8_t, 6> randomized_mac =
-        iface_util_.lock()->getOrCreateRandomMacAddress();
-    bool status = iface_util_.lock()->setMacAddress(ifname_, randomized_mac);
-    if (!status) {
-        LOG(ERROR) << "Failed to set random mac address";
-    }
-}
-
-void WifiApIface::invalidate() {
-    legacy_hal_.reset();
-    is_valid_ = false;
-}
-
-bool WifiApIface::isValid() { return is_valid_; }
-
-std::string WifiApIface::getName() { return ifname_; }
-
-Return<void> WifiApIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiApIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiApIface::setCountryCode(const hidl_array<int8_t, 2>& code,
-                                         setCountryCode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::setCountryCodeInternal, hidl_status_cb,
-                           code);
-}
-
-Return<void> WifiApIface::getValidFrequenciesForBand(
-    WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiApIface::getValidFrequenciesForBandInternal,
-                           hidl_status_cb, band);
-}
-
-std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiApIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::AP};
-}
-
-WifiStatus WifiApIface::setCountryCodeInternal(
-    const std::array<int8_t, 2>& code) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->setCountryCode(ifname_, code);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiApIface::getValidFrequenciesForBandInternal(WifiBand band) {
-    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
-                  "Size mismatch");
-    legacy_hal::wifi_error legacy_status;
-    std::vector<uint32_t> valid_frequencies;
-    std::tie(legacy_status, valid_frequencies) =
-        legacy_hal_.lock()->getValidFrequenciesForBand(
-            ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
-    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
-}
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_ap_iface.h b/wifi/1.3/default/wifi_ap_iface.h
deleted file mode 100644
index 98c5c9c..0000000
--- a/wifi/1.3/default/wifi_ap_iface.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_AP_IFACE_H_
-#define WIFI_AP_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiApIface.h>
-
-#include "wifi_feature_flags.h"
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a AP Iface instance.
- */
-class WifiApIface : public V1_0::IWifiApIface {
-   public:
-    WifiApIface(
-        const std::string& ifname,
-        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-        const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
-        const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::string getName();
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-    Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
-                                setCountryCode_cb hidl_status_cb) override;
-    Return<void> getValidFrequenciesForBand(
-        WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override;
-
-   private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-    WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
-    std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-    getValidFrequenciesForBandInternal(WifiBand band);
-
-    std::string ifname_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
-    std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
-    bool is_valid_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiApIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_AP_IFACE_H_
diff --git a/wifi/1.3/default/wifi_chip.cpp b/wifi/1.3/default/wifi_chip.cpp
deleted file mode 100644
index e9991dc..0000000
--- a/wifi/1.3/default/wifi_chip.cpp
+++ /dev/null
@@ -1,1545 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <fcntl.h>
-
-#include <android-base/logging.h>
-#include <android-base/unique_fd.h>
-#include <cutils/properties.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_chip.h"
-#include "wifi_status_util.h"
-
-namespace {
-using android::sp;
-using android::base::unique_fd;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
-using android::hardware::wifi::V1_0::ChipModeId;
-using android::hardware::wifi::V1_0::IfaceType;
-using android::hardware::wifi::V1_0::IWifiChip;
-
-constexpr char kCpioMagic[] = "070701";
-constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3;
-constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
-constexpr uint32_t kMaxRingBufferFileNum = 20;
-constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
-constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
-constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
-constexpr unsigned kMaxWlanIfaces = 5;
-
-template <typename Iface>
-void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
-    iface->invalidate();
-    ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface),
-                 ifaces.end());
-}
-
-template <typename Iface>
-void invalidateAndClearAll(std::vector<sp<Iface>>& ifaces) {
-    for (const auto& iface : ifaces) {
-        iface->invalidate();
-    }
-    ifaces.clear();
-}
-
-template <typename Iface>
-std::vector<hidl_string> getNames(std::vector<sp<Iface>>& ifaces) {
-    std::vector<hidl_string> names;
-    for (const auto& iface : ifaces) {
-        names.emplace_back(iface->getName());
-    }
-    return names;
-}
-
-template <typename Iface>
-sp<Iface> findUsingName(std::vector<sp<Iface>>& ifaces,
-                        const std::string& name) {
-    std::vector<hidl_string> names;
-    for (const auto& iface : ifaces) {
-        if (name == iface->getName()) {
-            return iface;
-        }
-    }
-    return nullptr;
-}
-
-std::string getWlanIfaceName(unsigned idx) {
-    if (idx >= kMaxWlanIfaces) {
-        CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces;
-        return {};
-    }
-
-    std::array<char, PROPERTY_VALUE_MAX> buffer;
-    if (idx == 0 || idx == 1) {
-        const char* altPropName =
-            (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface";
-        auto res = property_get(altPropName, buffer.data(), nullptr);
-        if (res > 0) return buffer.data();
-    }
-    std::string propName = "wifi.interface." + std::to_string(idx);
-    auto res = property_get(propName.c_str(), buffer.data(), nullptr);
-    if (res > 0) return buffer.data();
-
-    return "wlan" + std::to_string(idx);
-}
-
-std::string getP2pIfaceName() {
-    std::array<char, PROPERTY_VALUE_MAX> buffer;
-    property_get("wifi.direct.interface", buffer.data(), "p2p0");
-    return buffer.data();
-}
-
-void setActiveWlanIfaceNameProperty(const std::string& ifname) {
-    auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data());
-    if (res != 0) {
-        PLOG(ERROR) << "Failed to set active wlan iface name property";
-    }
-}
-
-// delete files that meet either conditions:
-// 1. older than a predefined time in the wifi tombstone dir.
-// 2. Files in excess to a predefined amount, starting from the oldest ones
-bool removeOldFilesInternal() {
-    time_t now = time(0);
-    const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
-    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(
-        opendir(kTombstoneFolderPath), closedir);
-    if (!dir_dump) {
-        PLOG(ERROR) << "Failed to open directory";
-        return false;
-    }
-    struct dirent* dp;
-    bool success = true;
-    std::list<std::pair<const time_t, std::string>> valid_files;
-    while ((dp = readdir(dir_dump.get()))) {
-        if (dp->d_type != DT_REG) {
-            continue;
-        }
-        std::string cur_file_name(dp->d_name);
-        struct stat cur_file_stat;
-        std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
-        if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
-            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
-            success = false;
-            continue;
-        }
-        const time_t cur_file_time = cur_file_stat.st_mtime;
-        valid_files.push_back(
-            std::pair<const time_t, std::string>(cur_file_time, cur_file_path));
-    }
-    valid_files.sort();  // sort the list of files by last modified time from
-                         // small to big.
-    uint32_t cur_file_count = valid_files.size();
-    for (auto cur_file : valid_files) {
-        if (cur_file_count > kMaxRingBufferFileNum ||
-            cur_file.first < delete_files_before) {
-            if (unlink(cur_file.second.c_str()) != 0) {
-                PLOG(ERROR) << "Error deleting file";
-                success = false;
-            }
-            cur_file_count--;
-        } else {
-            break;
-        }
-    }
-    return success;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name,
-                     size_t file_name_len) {
-    std::array<char, 32 * 1024> read_buf;
-    ssize_t llen =
-        sprintf(read_buf.data(),
-                "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
-                kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid,
-                st.st_gid, static_cast<int>(st.st_nlink),
-                static_cast<int>(st.st_mtime), static_cast<int>(st.st_size),
-                major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
-                minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
-    if (write(out_fd, read_buf.data(), llen) == -1) {
-        PLOG(ERROR) << "Error writing cpio header to file " << file_name;
-        return false;
-    }
-    if (write(out_fd, file_name, file_name_len) == -1) {
-        PLOG(ERROR) << "Error writing filename to file " << file_name;
-        return false;
-    }
-
-    // NUL Pad header up to 4 multiple bytes.
-    llen = (llen + file_name_len) % 4;
-    if (llen != 0) {
-        const uint32_t zero = 0;
-        if (write(out_fd, &zero, 4 - llen) == -1) {
-            PLOG(ERROR) << "Error padding 0s to file " << file_name;
-            return false;
-        }
-    }
-    return true;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
-    // writing content of file
-    std::array<char, 32 * 1024> read_buf;
-    ssize_t llen = st.st_size;
-    size_t n_error = 0;
-    while (llen > 0) {
-        ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
-        if (bytes_read == -1) {
-            PLOG(ERROR) << "Error reading file";
-            return ++n_error;
-        }
-        llen -= bytes_read;
-        if (write(out_fd, read_buf.data(), bytes_read) == -1) {
-            PLOG(ERROR) << "Error writing data to file";
-            return ++n_error;
-        }
-        if (bytes_read == 0) {  // this should never happen, but just in case
-                                // to unstuck from while loop
-            PLOG(ERROR) << "Unexpected read result";
-            n_error++;
-            break;
-        }
-    }
-    llen = st.st_size % 4;
-    if (llen != 0) {
-        const uint32_t zero = 0;
-        if (write(out_fd, &zero, 4 - llen) == -1) {
-            PLOG(ERROR) << "Error padding 0s to file";
-            return ++n_error;
-        }
-    }
-    return n_error;
-}
-
-// Helper function for |cpioArchiveFilesInDir|
-bool cpioWriteFileTrailer(int out_fd) {
-    std::array<char, 4096> read_buf;
-    read_buf.fill(0);
-    if (write(out_fd, read_buf.data(),
-              sprintf(read_buf.data(), "070701%040X%056X%08XTRAILER!!!", 1,
-                      0x0b, 0) +
-                  4) == -1) {
-        PLOG(ERROR) << "Error writing trailing bytes";
-        return false;
-    }
-    return true;
-}
-
-// Archives all files in |input_dir| and writes result into |out_fd|
-// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
-// portion
-size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
-    struct dirent* dp;
-    size_t n_error = 0;
-    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir),
-                                                       closedir);
-    if (!dir_dump) {
-        PLOG(ERROR) << "Failed to open directory";
-        return ++n_error;
-    }
-    while ((dp = readdir(dir_dump.get()))) {
-        if (dp->d_type != DT_REG) {
-            continue;
-        }
-        std::string cur_file_name(dp->d_name);
-        // string.size() does not include the null terminator. The cpio FreeBSD
-        // file header expects the null character to be included in the length.
-        const size_t file_name_len = cur_file_name.size() + 1;
-        struct stat st;
-        const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
-        if (stat(cur_file_path.c_str(), &st) == -1) {
-            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
-            n_error++;
-            continue;
-        }
-        const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
-        if (fd_read == -1) {
-            PLOG(ERROR) << "Failed to open file " << cur_file_path;
-            n_error++;
-            continue;
-        }
-        unique_fd file_auto_closer(fd_read);
-        if (!cpioWriteHeader(out_fd, st, cur_file_name.c_str(),
-                             file_name_len)) {
-            return ++n_error;
-        }
-        size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
-        if (write_error) {
-            return n_error + write_error;
-        }
-    }
-    if (!cpioWriteFileTrailer(out_fd)) {
-        return ++n_error;
-    }
-    return n_error;
-}
-
-// Helper function to create a non-const char*.
-std::vector<char> makeCharVec(const std::string& str) {
-    std::vector<char> vec(str.size() + 1);
-    vec.assign(str.begin(), str.end());
-    vec.push_back('\0');
-    return vec;
-}
-
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-using hidl_return_util::validateAndCallWithLock;
-
-WifiChip::WifiChip(
-    ChipId chip_id, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-    const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
-    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
-    const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
-    : chip_id_(chip_id),
-      legacy_hal_(legacy_hal),
-      mode_controller_(mode_controller),
-      iface_util_(iface_util),
-      feature_flags_(feature_flags),
-      is_valid_(true),
-      current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
-      modes_(feature_flags.lock()->getChipModes()),
-      debug_ring_buffer_cb_registered_(false) {
-    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
-}
-
-void WifiChip::invalidate() {
-    if (!writeRingbufferFilesInternal()) {
-        LOG(ERROR) << "Error writing files to flash";
-    }
-    invalidateAndRemoveAllIfaces();
-    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
-    legacy_hal_.reset();
-    event_cb_handler_.invalidate();
-    is_valid_ = false;
-}
-
-bool WifiChip::isValid() { return is_valid_; }
-
-std::set<sp<V1_2::IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
-    return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getIdInternal, hidl_status_cb);
-}
-
-// Deprecated support for this callback
-Return<void> WifiChip::registerEventCallback(
-    const sp<V1_0::IWifiChipEventCallback>& event_callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::registerEventCallbackInternal,
-                           hidl_status_cb, event_callback);
-}
-
-Return<void> WifiChip::getCapabilities(getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getAvailableModes(getAvailableModes_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getAvailableModesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::configureChip(ChipModeId mode_id,
-                                     configureChip_cb hidl_status_cb) {
-    return validateAndCallWithLock(
-        this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-        &WifiChip::configureChipInternal, hidl_status_cb, mode_id);
-}
-
-Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getModeInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::requestChipDebugInfo(
-    requestChipDebugInfo_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::requestChipDebugInfoInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::requestDriverDebugDump(
-    requestDriverDebugDump_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::requestDriverDebugDumpInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::requestFirmwareDebugDump(
-    requestFirmwareDebugDump_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::requestFirmwareDebugDumpInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::createApIface(createApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createApIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getApIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getApIface(const hidl_string& ifname,
-                                  getApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getApIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::removeApIface(const hidl_string& ifname,
-                                     removeApIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeApIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createNanIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getNanIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getNanIface(const hidl_string& ifname,
-                                   getNanIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getNanIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::removeNanIface(const hidl_string& ifname,
-                                      removeNanIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeNanIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::createP2pIface(createP2pIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createP2pIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getP2pIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getP2pIface(const hidl_string& ifname,
-                                   getP2pIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getP2pIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::removeP2pIface(const hidl_string& ifname,
-                                      removeP2pIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeP2pIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createStaIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getStaIfaceNamesInternal, hidl_status_cb);
-}
-
-Return<void> WifiChip::getStaIface(const hidl_string& ifname,
-                                   getStaIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getStaIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::removeStaIface(const hidl_string& ifname,
-                                      removeStaIface_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::removeStaIfaceInternal, hidl_status_cb,
-                           ifname);
-}
-
-Return<void> WifiChip::createRttController(
-    const sp<IWifiIface>& bound_iface, createRttController_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::createRttControllerInternal,
-                           hidl_status_cb, bound_iface);
-}
-
-Return<void> WifiChip::getDebugRingBuffersStatus(
-    getDebugRingBuffersStatus_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getDebugRingBuffersStatusInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::startLoggingToDebugRingBuffer(
-    const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
-    uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
-    startLoggingToDebugRingBuffer_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::startLoggingToDebugRingBufferInternal,
-                           hidl_status_cb, ring_name, verbose_level,
-                           max_interval_in_sec, min_data_size_in_bytes);
-}
-
-Return<void> WifiChip::forceDumpToDebugRingBuffer(
-    const hidl_string& ring_name,
-    forceDumpToDebugRingBuffer_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::forceDumpToDebugRingBufferInternal,
-                           hidl_status_cb, ring_name);
-}
-
-Return<void> WifiChip::flushRingBufferToFile(
-    flushRingBufferToFile_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::flushRingBufferToFileInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::stopLoggingToDebugRingBuffer(
-    stopLoggingToDebugRingBuffer_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::stopLoggingToDebugRingBufferInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::getDebugHostWakeReasonStats(
-    getDebugHostWakeReasonStats_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getDebugHostWakeReasonStatsInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::enableDebugErrorAlerts(
-    bool enable, enableDebugErrorAlerts_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::enableDebugErrorAlertsInternal,
-                           hidl_status_cb, enable);
-}
-
-Return<void> WifiChip::selectTxPowerScenario(
-    V1_1::IWifiChip::TxPowerScenario scenario,
-    selectTxPowerScenario_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::selectTxPowerScenarioInternal,
-                           hidl_status_cb, scenario);
-}
-
-Return<void> WifiChip::resetTxPowerScenario(
-    resetTxPowerScenario_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::resetTxPowerScenarioInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::setLatencyMode(LatencyMode mode,
-                                      setLatencyMode_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::setLatencyModeInternal, hidl_status_cb,
-                           mode);
-}
-
-Return<void> WifiChip::registerEventCallback_1_2(
-    const sp<V1_2::IWifiChipEventCallback>& event_callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::registerEventCallbackInternal_1_2,
-                           hidl_status_cb, event_callback);
-}
-
-Return<void> WifiChip::selectTxPowerScenario_1_2(
-    TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::selectTxPowerScenarioInternal_1_2,
-                           hidl_status_cb, scenario);
-}
-
-Return<void> WifiChip::getCapabilities_1_3(getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                           &WifiChip::getCapabilitiesInternal_1_3,
-                           hidl_status_cb);
-}
-
-Return<void> WifiChip::debug(const hidl_handle& handle,
-                             const hidl_vec<hidl_string>&) {
-    if (handle != nullptr && handle->numFds >= 1) {
-        int fd = handle->data[0];
-        if (!writeRingbufferFilesInternal()) {
-            LOG(ERROR) << "Error writing files to flash";
-        }
-        uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
-        if (n_error != 0) {
-            LOG(ERROR) << n_error << " errors occured in cpio function";
-        }
-        fsync(fd);
-    } else {
-        LOG(ERROR) << "File handle error";
-    }
-    return Void();
-}
-
-void WifiChip::invalidateAndRemoveAllIfaces() {
-    invalidateAndClearAll(ap_ifaces_);
-    invalidateAndClearAll(nan_ifaces_);
-    invalidateAndClearAll(p2p_ifaces_);
-    invalidateAndClearAll(sta_ifaces_);
-    // Since all the ifaces are invalid now, all RTT controller objects
-    // using those ifaces also need to be invalidated.
-    for (const auto& rtt : rtt_controllers_) {
-        rtt->invalidate();
-    }
-    rtt_controllers_.clear();
-}
-
-void WifiChip::invalidateAndRemoveDependencies(
-    const std::string& removed_iface_name) {
-    for (const auto& nan_iface : nan_ifaces_) {
-        if (nan_iface->getName() == removed_iface_name) {
-            invalidateAndClear(nan_ifaces_, nan_iface);
-            for (const auto& callback : event_cb_handler_.getCallbacks()) {
-                if (!callback
-                         ->onIfaceRemoved(IfaceType::NAN, removed_iface_name)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-                }
-            }
-        }
-    }
-    for (const auto& rtt : rtt_controllers_) {
-        if (rtt->getIfaceName() == removed_iface_name) {
-            invalidateAndClear(rtt_controllers_, rtt);
-        }
-    }
-}
-
-std::pair<WifiStatus, ChipId> WifiChip::getIdInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_};
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal(
-    const sp<V1_0::IWifiChipEventCallback>& /* event_callback */) {
-    // Deprecated support for this callback.
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
-    // Deprecated support for this callback.
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() {
-    legacy_hal::wifi_error legacy_status;
-    uint32_t legacy_feature_set;
-    uint32_t legacy_logger_feature_set;
-    const auto ifname = getFirstActiveWlanIfaceName();
-    std::tie(legacy_status, legacy_feature_set) =
-        legacy_hal_.lock()->getSupportedFeatureSet(ifname);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), 0};
-    }
-    std::tie(legacy_status, legacy_logger_feature_set) =
-        legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        // some devices don't support querying logger feature set
-        legacy_logger_feature_set = 0;
-    }
-    uint32_t hidl_caps;
-    if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
-            legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
-WifiChip::getAvailableModesInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
-}
-
-WifiStatus WifiChip::configureChipInternal(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
-    ChipModeId mode_id) {
-    if (!isValidModeId(mode_id)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    if (mode_id == current_mode_id_) {
-        LOG(DEBUG) << "Already in the specified mode " << mode_id;
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    }
-    WifiStatus status = handleChipConfiguration(lock, mode_id);
-    if (status.code != WifiStatusCode::SUCCESS) {
-        for (const auto& callback : event_cb_handler_.getCallbacks()) {
-            if (!callback->onChipReconfigureFailure(status).isOk()) {
-                LOG(ERROR)
-                    << "Failed to invoke onChipReconfigureFailure callback";
-            }
-        }
-        return status;
-    }
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onChipReconfigured(mode_id).isOk()) {
-            LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
-        }
-    }
-    current_mode_id_ = mode_id;
-    LOG(INFO) << "Configured chip in mode " << mode_id;
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-    return status;
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
-    if (!isValidModeId(current_mode_id_)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
-                current_mode_id_};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
-}
-
-std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
-WifiChip::requestChipDebugInfoInternal() {
-    IWifiChip::ChipDebugInfo result;
-    legacy_hal::wifi_error legacy_status;
-    std::string driver_desc;
-    const auto ifname = getFirstActiveWlanIfaceName();
-    std::tie(legacy_status, driver_desc) =
-        legacy_hal_.lock()->getDriverVersion(ifname);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to get driver version: "
-                   << legacyErrorToString(legacy_status);
-        WifiStatus status = createWifiStatusFromLegacyError(
-            legacy_status, "failed to get driver version");
-        return {status, result};
-    }
-    result.driverDescription = driver_desc.c_str();
-
-    std::string firmware_desc;
-    std::tie(legacy_status, firmware_desc) =
-        legacy_hal_.lock()->getFirmwareVersion(ifname);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to get firmware version: "
-                   << legacyErrorToString(legacy_status);
-        WifiStatus status = createWifiStatusFromLegacyError(
-            legacy_status, "failed to get firmware version");
-        return {status, result};
-    }
-    result.firmwareDescription = firmware_desc.c_str();
-
-    return {createWifiStatus(WifiStatusCode::SUCCESS), result};
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiChip::requestDriverDebugDumpInternal() {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<uint8_t> driver_dump;
-    std::tie(legacy_status, driver_dump) =
-        legacy_hal_.lock()->requestDriverMemoryDump(
-            getFirstActiveWlanIfaceName());
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to get driver debug dump: "
-                   << legacyErrorToString(legacy_status);
-        return {createWifiStatusFromLegacyError(legacy_status),
-                std::vector<uint8_t>()};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), driver_dump};
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiChip::requestFirmwareDebugDumpInternal() {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<uint8_t> firmware_dump;
-    std::tie(legacy_status, firmware_dump) =
-        legacy_hal_.lock()->requestFirmwareMemoryDump(
-            getFirstActiveWlanIfaceName());
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to get firmware debug dump: "
-                   << legacyErrorToString(legacy_status);
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
-}
-
-std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string ifname = allocateApIfaceName();
-    sp<WifiApIface> iface =
-        new WifiApIface(ifname, legacy_hal_, iface_util_, feature_flags_);
-    ap_ifaces_.push_back(iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getApIfaceNamesInternal() {
-    if (ap_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::getApIfaceInternal(
-    const std::string& ifname) {
-    const auto iface = findUsingName(ap_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
-    const auto iface = findUsingName(ap_ifaces_, ifname);
-    if (!iface.get()) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    // Invalidate & remove any dependent objects first.
-    // Note: This is probably not required because we never create
-    // nan/rtt objects over AP iface. But, there is no harm to do it
-    // here and not make that assumption all over the place.
-    invalidateAndRemoveDependencies(ifname);
-    invalidateAndClear(ap_ifaces_, iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-        }
-    }
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    // These are still assumed to be based on wlan0.
-    std::string ifname = getFirstActiveWlanIfaceName();
-    sp<WifiNanIface> iface = new WifiNanIface(ifname, legacy_hal_, iface_util_);
-    nan_ifaces_.push_back(iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getNanIfaceNamesInternal() {
-    if (nan_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::getNanIfaceInternal(
-    const std::string& ifname) {
-    const auto iface = findUsingName(nan_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
-    const auto iface = findUsingName(nan_ifaces_, ifname);
-    if (!iface.get()) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    invalidateAndClear(nan_ifaces_, iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::P2P)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string ifname = getP2pIfaceName();
-    sp<WifiP2pIface> iface = new WifiP2pIface(ifname, legacy_hal_);
-    p2p_ifaces_.push_back(iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getP2pIfaceNamesInternal() {
-    if (p2p_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::getP2pIfaceInternal(
-    const std::string& ifname) {
-    const auto iface = findUsingName(p2p_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
-    const auto iface = findUsingName(p2p_ifaces_, ifname);
-    if (!iface.get()) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    invalidateAndClear(p2p_ifaces_, iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-        }
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {
-    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string ifname = allocateStaIfaceName();
-    sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
-    sta_ifaces_.push_back(iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-        }
-    }
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getStaIfaceNamesInternal() {
-    if (sta_ifaces_.empty()) {
-        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
-}
-
-std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::getStaIfaceInternal(
-    const std::string& ifname) {
-    const auto iface = findUsingName(sta_ifaces_, ifname);
-    if (!iface.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
-}
-
-WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
-    const auto iface = findUsingName(sta_ifaces_, ifname);
-    if (!iface.get()) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    // Invalidate & remove any dependent objects first.
-    invalidateAndRemoveDependencies(ifname);
-    invalidateAndClear(sta_ifaces_, iface);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-        if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
-            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-        }
-    }
-    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiRttController>>
-WifiChip::createRttControllerInternal(const sp<IWifiIface>& bound_iface) {
-    if (sta_ifaces_.size() == 0 &&
-        !canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
-        LOG(ERROR) << "createRttControllerInternal: Chip cannot support STAs "
-                      "(and RTT by extension)";
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    sp<WifiRttController> rtt = new WifiRttController(
-        getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
-    rtt_controllers_.emplace_back(rtt);
-    return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
-WifiChip::getDebugRingBuffersStatusInternal() {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<legacy_hal::wifi_ring_buffer_status>
-        legacy_ring_buffer_status_vec;
-    std::tie(legacy_status, legacy_ring_buffer_status_vec) =
-        legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName());
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
-    if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
-            legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS),
-            hidl_ring_buffer_status_vec};
-}
-
-WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
-    const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
-    uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
-    WifiStatus status = registerDebugRingBufferCallback();
-    if (status.code != WifiStatusCode::SUCCESS) {
-        return status;
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->startRingBufferLogging(
-            getFirstActiveWlanIfaceName(), ring_name,
-            static_cast<
-                std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(
-                verbose_level),
-            max_interval_in_sec, min_data_size_in_bytes);
-    ringbuffer_map_.insert(std::pair<std::string, Ringbuffer>(
-        ring_name, Ringbuffer(kMaxBufferSizeBytes)));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(
-    const hidl_string& ring_name) {
-    WifiStatus status = registerDebugRingBufferCallback();
-    if (status.code != WifiStatusCode::SUCCESS) {
-        return status;
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(),
-                                              ring_name);
-
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::flushRingBufferToFileInternal() {
-    if (!writeRingbufferFilesInternal()) {
-        LOG(ERROR) << "Error writing files to flash";
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->deregisterRingBufferCallbackHandler(
-            getFirstActiveWlanIfaceName());
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
-WifiChip::getDebugHostWakeReasonStatsInternal() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::WakeReasonStats legacy_stats;
-    std::tie(legacy_status, legacy_stats) =
-        legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName());
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    WifiDebugHostWakeReasonStats hidl_stats;
-    if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats,
-                                                              &hidl_stats)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
-}
-
-WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
-    legacy_hal::wifi_error legacy_status;
-    if (enable) {
-        android::wp<WifiChip> weak_ptr_this(this);
-        const auto& on_alert_callback = [weak_ptr_this](
-                                            int32_t error_code,
-                                            std::vector<uint8_t> debug_data) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onDebugErrorAlert(error_code, debug_data)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
-                }
-            }
-        };
-        legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
-            getFirstActiveWlanIfaceName(), on_alert_callback);
-    } else {
-        legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
-            getFirstActiveWlanIfaceName());
-    }
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::selectTxPowerScenarioInternal(
-    V1_1::IWifiChip::TxPowerScenario scenario) {
-    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
-        getFirstActiveWlanIfaceName(),
-        hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::resetTxPowerScenarioInternal() {
-    auto legacy_status =
-        legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) {
-    auto legacy_status = legacy_hal_.lock()->setLatencyMode(
-        getFirstActiveWlanIfaceName(),
-        hidl_struct_util::convertHidlLatencyModeToLegacy(mode));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal_1_2(
-    const sp<V1_2::IWifiChipEventCallback>& event_callback) {
-    if (!event_cb_handler_.addCallback(event_callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(
-    TxPowerScenario scenario) {
-    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
-        getFirstActiveWlanIfaceName(),
-        hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::handleChipConfiguration(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
-    ChipModeId mode_id) {
-    // If the chip is already configured in a different mode, stop
-    // the legacy HAL and then start it after firmware mode change.
-    if (isValidModeId(current_mode_id_)) {
-        LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_
-                  << " to mode " << mode_id;
-        invalidateAndRemoveAllIfaces();
-        legacy_hal::wifi_error legacy_status =
-            legacy_hal_.lock()->stop(lock, []() {});
-        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-            LOG(ERROR) << "Failed to stop legacy HAL: "
-                       << legacyErrorToString(legacy_status);
-            return createWifiStatusFromLegacyError(legacy_status);
-        }
-    }
-    // Firmware mode change not needed for V2 devices.
-    bool success = true;
-    if (mode_id == feature_flags::chip_mode_ids::kV1Sta) {
-        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
-    } else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) {
-        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
-    }
-    if (!success) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to start legacy HAL: "
-                   << legacyErrorToString(legacy_status);
-        return createWifiStatusFromLegacyError(legacy_status);
-    }
-    // Every time the HAL is restarted, we need to register the
-    // radio mode change callback.
-    WifiStatus status = registerRadioModeChangeCallback();
-    if (status.code != WifiStatusCode::SUCCESS) {
-        // This probably is not a critical failure?
-        LOG(ERROR) << "Failed to register radio mode change callback";
-    }
-    // Extract and save the version information into property.
-    std::pair<WifiStatus, IWifiChip::ChipDebugInfo> version_info;
-    version_info = WifiChip::requestChipDebugInfoInternal();
-    if (WifiStatusCode::SUCCESS == version_info.first.code) {
-        property_set("vendor.wlan.firmware.version",
-                     version_info.second.firmwareDescription.c_str());
-        property_set("vendor.wlan.driver.version",
-                     version_info.second.driverDescription.c_str());
-    }
-
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::registerDebugRingBufferCallback() {
-    if (debug_ring_buffer_cb_registered_) {
-        return createWifiStatus(WifiStatusCode::SUCCESS);
-    }
-
-    android::wp<WifiChip> weak_ptr_this(this);
-    const auto& on_ring_buffer_data_callback =
-        [weak_ptr_this](const std::string& name,
-                        const std::vector<uint8_t>& data,
-                        const legacy_hal::wifi_ring_buffer_status& status) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            WifiDebugRingBufferStatus hidl_status;
-            if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(
-                    status, &hidl_status)) {
-                LOG(ERROR) << "Error converting ring buffer status";
-                return;
-            }
-            const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
-            if (target != shared_ptr_this->ringbuffer_map_.end()) {
-                Ringbuffer& cur_buffer = target->second;
-                cur_buffer.append(data);
-            } else {
-                LOG(ERROR) << "Ringname " << name << " not found";
-                return;
-            }
-        };
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->registerRingBufferCallbackHandler(
-            getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
-
-    if (legacy_status == legacy_hal::WIFI_SUCCESS) {
-        debug_ring_buffer_cb_registered_ = true;
-    }
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::registerRadioModeChangeCallback() {
-    android::wp<WifiChip> weak_ptr_this(this);
-    const auto& on_radio_mode_change_callback =
-        [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>
-                hidl_radio_mode_infos;
-            if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
-                    mac_infos, &hidl_radio_mode_infos)) {
-                LOG(ERROR) << "Error converting wifi mac info";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onRadioModeChange(hidl_radio_mode_infos)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke onRadioModeChange"
-                               << " callback on: " << toString(callback);
-                }
-            }
-        };
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
-            getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::vector<IWifiChip::ChipIfaceCombination>
-WifiChip::getCurrentModeIfaceCombinations() {
-    if (!isValidModeId(current_mode_id_)) {
-        LOG(ERROR) << "Chip not configured in a mode yet";
-        return {};
-    }
-    for (const auto& mode : modes_) {
-        if (mode.id == current_mode_id_) {
-            return mode.availableCombinations;
-        }
-    }
-    CHECK(0) << "Expected to find iface combinations for current mode!";
-    return {};
-}
-
-// Returns a map indexed by IfaceType with the number of ifaces currently
-// created of the corresponding type.
-std::map<IfaceType, size_t> WifiChip::getCurrentIfaceCombination() {
-    std::map<IfaceType, size_t> iface_counts;
-    iface_counts[IfaceType::AP] = ap_ifaces_.size();
-    iface_counts[IfaceType::NAN] = nan_ifaces_.size();
-    iface_counts[IfaceType::P2P] = p2p_ifaces_.size();
-    iface_counts[IfaceType::STA] = sta_ifaces_.size();
-    return iface_counts;
-}
-
-// This expands the provided iface combinations to a more parseable
-// form. Returns a vector of available combinations possible with the number
-// of ifaces of each type in the combination.
-// This method is a port of HalDeviceManager.expandIfaceCombos() from framework.
-std::vector<std::map<IfaceType, size_t>> WifiChip::expandIfaceCombinations(
-    const IWifiChip::ChipIfaceCombination& combination) {
-    uint32_t num_expanded_combos = 1;
-    for (const auto& limit : combination.limits) {
-        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
-            num_expanded_combos *= limit.types.size();
-        }
-    }
-
-    // Allocate the vector of expanded combos and reset all iface counts to 0
-    // in each combo.
-    std::vector<std::map<IfaceType, size_t>> expanded_combos;
-    expanded_combos.resize(num_expanded_combos);
-    for (auto& expanded_combo : expanded_combos) {
-        for (const auto type :
-             {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
-            expanded_combo[type] = 0;
-        }
-    }
-    uint32_t span = num_expanded_combos;
-    for (const auto& limit : combination.limits) {
-        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
-            span /= limit.types.size();
-            for (uint32_t k = 0; k < num_expanded_combos; ++k) {
-                const auto iface_type =
-                    limit.types[(k / span) % limit.types.size()];
-                expanded_combos[k][iface_type]++;
-            }
-        }
-    }
-    return expanded_combos;
-}
-
-bool WifiChip::canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
-    const std::map<IfaceType, size_t>& expanded_combo,
-    IfaceType requested_type) {
-    const auto current_combo = getCurrentIfaceCombination();
-
-    // Check if we have space for 1 more iface of |type| in this combo
-    for (const auto type :
-         {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
-        size_t num_ifaces_needed = current_combo.at(type);
-        if (type == requested_type) {
-            num_ifaces_needed++;
-        }
-        size_t num_ifaces_allowed = expanded_combo.at(type);
-        if (num_ifaces_needed > num_ifaces_allowed) {
-            return false;
-        }
-    }
-    return true;
-}
-
-// This method does the following:
-// a) Enumerate all possible iface combos by expanding the current
-//    ChipIfaceCombination.
-// b) Check if the requested iface type can be added to the current mode
-//    with the iface combination that is already active.
-bool WifiChip::canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
-    IfaceType requested_type) {
-    if (!isValidModeId(current_mode_id_)) {
-        LOG(ERROR) << "Chip not configured in a mode yet";
-        return false;
-    }
-    const auto combinations = getCurrentModeIfaceCombinations();
-    for (const auto& combination : combinations) {
-        const auto expanded_combos = expandIfaceCombinations(combination);
-        for (const auto& expanded_combo : expanded_combos) {
-            if (canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
-                    expanded_combo, requested_type)) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-// Note: This does not consider ifaces already active. It only checks if the
-// provided expanded iface combination can support the requested combo.
-bool WifiChip::canExpandedIfaceComboSupportIfaceCombo(
-    const std::map<IfaceType, size_t>& expanded_combo,
-    const std::map<IfaceType, size_t>& req_combo) {
-    // Check if we have space for 1 more iface of |type| in this combo
-    for (const auto type :
-         {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
-        if (req_combo.count(type) == 0) {
-            // Iface of "type" not in the req_combo.
-            continue;
-        }
-        size_t num_ifaces_needed = req_combo.at(type);
-        size_t num_ifaces_allowed = expanded_combo.at(type);
-        if (num_ifaces_needed > num_ifaces_allowed) {
-            return false;
-        }
-    }
-    return true;
-}
-// This method does the following:
-// a) Enumerate all possible iface combos by expanding the current
-//    ChipIfaceCombination.
-// b) Check if the requested iface combo can be added to the current mode.
-// Note: This does not consider ifaces already active. It only checks if the
-// current mode can support the requested combo.
-bool WifiChip::canCurrentModeSupportIfaceCombo(
-    const std::map<IfaceType, size_t>& req_combo) {
-    if (!isValidModeId(current_mode_id_)) {
-        LOG(ERROR) << "Chip not configured in a mode yet";
-        return false;
-    }
-    const auto combinations = getCurrentModeIfaceCombinations();
-    for (const auto& combination : combinations) {
-        const auto expanded_combos = expandIfaceCombinations(combination);
-        for (const auto& expanded_combo : expanded_combos) {
-            if (canExpandedIfaceComboSupportIfaceCombo(expanded_combo,
-                                                       req_combo)) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-// This method does the following:
-// a) Enumerate all possible iface combos by expanding the current
-//    ChipIfaceCombination.
-// b) Check if the requested iface type can be added to the current mode.
-bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType requested_type) {
-    // Check if we can support atleast 1 iface of type.
-    std::map<IfaceType, size_t> req_iface_combo;
-    req_iface_combo[requested_type] = 1;
-    return canCurrentModeSupportIfaceCombo(req_iface_combo);
-}
-
-bool WifiChip::isValidModeId(ChipModeId mode_id) {
-    for (const auto& mode : modes_) {
-        if (mode.id == mode_id) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
-    // Check if we can support atleast 1 STA & 1 AP concurrently.
-    std::map<IfaceType, size_t> req_iface_combo;
-    req_iface_combo[IfaceType::AP] = 1;
-    req_iface_combo[IfaceType::STA] = 1;
-    return canCurrentModeSupportIfaceCombo(req_iface_combo);
-}
-
-bool WifiChip::isDualApAllowedInCurrentMode() {
-    // Check if we can support atleast 1 STA & 1 AP concurrently.
-    std::map<IfaceType, size_t> req_iface_combo;
-    req_iface_combo[IfaceType::AP] = 2;
-    return canCurrentModeSupportIfaceCombo(req_iface_combo);
-}
-
-std::string WifiChip::getFirstActiveWlanIfaceName() {
-    if (sta_ifaces_.size() > 0) return sta_ifaces_[0]->getName();
-    if (ap_ifaces_.size() > 0) return ap_ifaces_[0]->getName();
-    // This could happen if the chip call is made before any STA/AP
-    // iface is created. Default to wlan0 for such cases.
-    LOG(WARNING) << "No active wlan interfaces in use! Using default";
-    return getWlanIfaceName(0);
-}
-
-// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
-// not already in use.
-// Note: This doesn't check the actual presence of these interfaces.
-std::string WifiChip::allocateApOrStaIfaceName(uint32_t start_idx) {
-    for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
-        const auto ifname = getWlanIfaceName(idx);
-        if (findUsingName(ap_ifaces_, ifname)) continue;
-        if (findUsingName(sta_ifaces_, ifname)) continue;
-        return ifname;
-    }
-    // This should never happen. We screwed up somewhere if it did.
-    CHECK(false) << "All wlan interfaces in use already!";
-    return {};
-}
-
-// AP iface names start with idx 1 for modes supporting
-// concurrent STA and not dual AP, else start with idx 0.
-std::string WifiChip::allocateApIfaceName() {
-    return allocateApOrStaIfaceName((isStaApConcurrencyAllowedInCurrentMode() &&
-                                     !isDualApAllowedInCurrentMode())
-                                        ? 1
-                                        : 0);
-}
-
-// STA iface names start with idx 0.
-// Primary STA iface will always be 0.
-std::string WifiChip::allocateStaIfaceName() {
-    return allocateApOrStaIfaceName(0);
-}
-
-bool WifiChip::writeRingbufferFilesInternal() {
-    if (!removeOldFilesInternal()) {
-        LOG(ERROR) << "Error occurred while deleting old tombstone files";
-        return false;
-    }
-    // write ringbuffers to file
-    for (const auto& item : ringbuffer_map_) {
-        const Ringbuffer& cur_buffer = item.second;
-        if (cur_buffer.getData().empty()) {
-            continue;
-        }
-        const std::string file_path_raw =
-            kTombstoneFolderPath + item.first + "XXXXXXXXXX";
-        const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
-        if (dump_fd == -1) {
-            PLOG(ERROR) << "create file failed";
-            return false;
-        }
-        unique_fd file_auto_closer(dump_fd);
-        for (const auto& cur_block : cur_buffer.getData()) {
-            if (write(dump_fd, cur_block.data(),
-                      sizeof(cur_block[0]) * cur_block.size()) == -1) {
-                PLOG(ERROR) << "Error writing to file";
-            }
-        }
-    }
-    return true;
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_chip.h b/wifi/1.3/default/wifi_chip.h
deleted file mode 100644
index 153ca6a..0000000
--- a/wifi/1.3/default/wifi_chip.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_CHIP_H_
-#define WIFI_CHIP_H_
-
-#include <list>
-#include <map>
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include "hidl_callback_util.h"
-#include "ringbuffer.h"
-#include "wifi_ap_iface.h"
-#include "wifi_feature_flags.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_mode_controller.h"
-#include "wifi_nan_iface.h"
-#include "wifi_p2p_iface.h"
-#include "wifi_rtt_controller.h"
-#include "wifi_sta_iface.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a Wifi HAL chip instance.
- * Since there is only a single chip instance used today, there is no
- * identifying handle information stored here.
- */
-class WifiChip : public V1_3::IWifiChip {
-   public:
-    WifiChip(
-        ChipId chip_id,
-        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-        const std::weak_ptr<mode_controller::WifiModeController>
-            mode_controller,
-        const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
-        const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
-    // HIDL does not provide a built-in mechanism to let the server invalidate
-    // a HIDL interface object after creation. If any client process holds onto
-    // a reference to the object in their context, any method calls on that
-    // reference will continue to be directed to the server.
-    //
-    // However Wifi HAL needs to control the lifetime of these objects. So, add
-    // a public |invalidate| method to |WifiChip| and it's child objects. This
-    // will be used to mark an object invalid when either:
-    // a) Wifi HAL is stopped, or
-    // b) Wifi Chip is reconfigured.
-    //
-    // All HIDL method implementations should check if the object is still
-    // marked valid before processing them.
-    void invalidate();
-    bool isValid();
-    std::set<sp<V1_2::IWifiChipEventCallback>> getEventCallbacks();
-
-    // HIDL methods exposed.
-    Return<void> getId(getId_cb hidl_status_cb) override;
-    // Deprecated support for this callback
-    Return<void> registerEventCallback(
-        const sp<V1_0::IWifiChipEventCallback>& event_callback,
-        registerEventCallback_cb hidl_status_cb) override;
-    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-    Return<void> getAvailableModes(
-        getAvailableModes_cb hidl_status_cb) override;
-    Return<void> configureChip(ChipModeId mode_id,
-                               configureChip_cb hidl_status_cb) override;
-    Return<void> getMode(getMode_cb hidl_status_cb) override;
-    Return<void> requestChipDebugInfo(
-        requestChipDebugInfo_cb hidl_status_cb) override;
-    Return<void> requestDriverDebugDump(
-        requestDriverDebugDump_cb hidl_status_cb) override;
-    Return<void> requestFirmwareDebugDump(
-        requestFirmwareDebugDump_cb hidl_status_cb) override;
-    Return<void> createApIface(createApIface_cb hidl_status_cb) override;
-    Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
-    Return<void> getApIface(const hidl_string& ifname,
-                            getApIface_cb hidl_status_cb) override;
-    Return<void> removeApIface(const hidl_string& ifname,
-                               removeApIface_cb hidl_status_cb) override;
-    Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
-    Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
-    Return<void> getNanIface(const hidl_string& ifname,
-                             getNanIface_cb hidl_status_cb) override;
-    Return<void> removeNanIface(const hidl_string& ifname,
-                                removeNanIface_cb hidl_status_cb) override;
-    Return<void> createP2pIface(createP2pIface_cb hidl_status_cb) override;
-    Return<void> getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) override;
-    Return<void> getP2pIface(const hidl_string& ifname,
-                             getP2pIface_cb hidl_status_cb) override;
-    Return<void> removeP2pIface(const hidl_string& ifname,
-                                removeP2pIface_cb hidl_status_cb) override;
-    Return<void> createStaIface(createStaIface_cb hidl_status_cb) override;
-    Return<void> getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) override;
-    Return<void> getStaIface(const hidl_string& ifname,
-                             getStaIface_cb hidl_status_cb) override;
-    Return<void> removeStaIface(const hidl_string& ifname,
-                                removeStaIface_cb hidl_status_cb) override;
-    Return<void> createRttController(
-        const sp<IWifiIface>& bound_iface,
-        createRttController_cb hidl_status_cb) override;
-    Return<void> getDebugRingBuffersStatus(
-        getDebugRingBuffersStatus_cb hidl_status_cb) override;
-    Return<void> startLoggingToDebugRingBuffer(
-        const hidl_string& ring_name,
-        WifiDebugRingBufferVerboseLevel verbose_level,
-        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
-        startLoggingToDebugRingBuffer_cb hidl_status_cb) override;
-    Return<void> forceDumpToDebugRingBuffer(
-        const hidl_string& ring_name,
-        forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
-    Return<void> flushRingBufferToFile(
-        flushRingBufferToFile_cb hidl_status_cb) override;
-    Return<void> stopLoggingToDebugRingBuffer(
-        stopLoggingToDebugRingBuffer_cb hidl_status_cb) override;
-    Return<void> getDebugHostWakeReasonStats(
-        getDebugHostWakeReasonStats_cb hidl_status_cb) override;
-    Return<void> enableDebugErrorAlerts(
-        bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
-    Return<void> selectTxPowerScenario(
-        V1_1::IWifiChip::TxPowerScenario scenario,
-        selectTxPowerScenario_cb hidl_status_cb) override;
-    Return<void> resetTxPowerScenario(
-        resetTxPowerScenario_cb hidl_status_cb) override;
-    Return<void> setLatencyMode(LatencyMode mode,
-                                setLatencyMode_cb hidl_status_cb) override;
-    Return<void> registerEventCallback_1_2(
-        const sp<V1_2::IWifiChipEventCallback>& event_callback,
-        registerEventCallback_1_2_cb hidl_status_cb) override;
-    Return<void> selectTxPowerScenario_1_2(
-        TxPowerScenario scenario,
-        selectTxPowerScenario_cb hidl_status_cb) override;
-    Return<void> getCapabilities_1_3(
-        getCapabilities_cb hidl_status_cb) override;
-    Return<void> debug(const hidl_handle& handle,
-                       const hidl_vec<hidl_string>& options) override;
-
-   private:
-    void invalidateAndRemoveAllIfaces();
-    // When a STA iface is removed any dependent NAN-ifaces/RTT-controllers are
-    // invalidated & removed.
-    void invalidateAndRemoveDependencies(const std::string& removed_iface_name);
-
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, ChipId> getIdInternal();
-    // Deprecated support for this callback
-    WifiStatus registerEventCallbackInternal(
-        const sp<V1_0::IWifiChipEventCallback>& event_callback);
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
-    std::pair<WifiStatus, std::vector<ChipMode>> getAvailableModesInternal();
-    WifiStatus configureChipInternal(
-        std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
-    std::pair<WifiStatus, uint32_t> getModeInternal();
-    std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
-    requestChipDebugInfoInternal();
-    std::pair<WifiStatus, std::vector<uint8_t>>
-    requestDriverDebugDumpInternal();
-    std::pair<WifiStatus, std::vector<uint8_t>>
-    requestFirmwareDebugDumpInternal();
-    std::pair<WifiStatus, sp<IWifiApIface>> createApIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
-    std::pair<WifiStatus, sp<IWifiApIface>> getApIfaceInternal(
-        const std::string& ifname);
-    WifiStatus removeApIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<IWifiNanIface>> createNanIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
-    std::pair<WifiStatus, sp<IWifiNanIface>> getNanIfaceInternal(
-        const std::string& ifname);
-    WifiStatus removeNanIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
-    std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(
-        const std::string& ifname);
-    WifiStatus removeP2pIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<IWifiStaIface>> createStaIfaceInternal();
-    std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
-    std::pair<WifiStatus, sp<IWifiStaIface>> getStaIfaceInternal(
-        const std::string& ifname);
-    WifiStatus removeStaIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<IWifiRttController>> createRttControllerInternal(
-        const sp<IWifiIface>& bound_iface);
-    std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
-    getDebugRingBuffersStatusInternal();
-    WifiStatus startLoggingToDebugRingBufferInternal(
-        const hidl_string& ring_name,
-        WifiDebugRingBufferVerboseLevel verbose_level,
-        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes);
-    WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
-    WifiStatus flushRingBufferToFileInternal();
-    WifiStatus stopLoggingToDebugRingBufferInternal();
-    std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
-    getDebugHostWakeReasonStatsInternal();
-    WifiStatus enableDebugErrorAlertsInternal(bool enable);
-    WifiStatus selectTxPowerScenarioInternal(
-        V1_1::IWifiChip::TxPowerScenario scenario);
-    WifiStatus resetTxPowerScenarioInternal();
-    WifiStatus setLatencyModeInternal(LatencyMode mode);
-    WifiStatus registerEventCallbackInternal_1_2(
-        const sp<V1_2::IWifiChipEventCallback>& event_callback);
-    WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3();
-    WifiStatus handleChipConfiguration(
-        std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
-    WifiStatus registerDebugRingBufferCallback();
-    WifiStatus registerRadioModeChangeCallback();
-
-    std::vector<IWifiChip::ChipIfaceCombination>
-    getCurrentModeIfaceCombinations();
-    std::map<IfaceType, size_t> getCurrentIfaceCombination();
-    std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
-        const IWifiChip::ChipIfaceCombination& combination);
-    bool canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
-        const std::map<IfaceType, size_t>& expanded_combo,
-        IfaceType requested_type);
-    bool canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
-        IfaceType requested_type);
-    bool canExpandedIfaceComboSupportIfaceCombo(
-        const std::map<IfaceType, size_t>& expanded_combo,
-        const std::map<IfaceType, size_t>& req_combo);
-    bool canCurrentModeSupportIfaceCombo(
-        const std::map<IfaceType, size_t>& req_combo);
-    bool canCurrentModeSupportIfaceOfType(IfaceType requested_type);
-    bool isValidModeId(ChipModeId mode_id);
-    bool isStaApConcurrencyAllowedInCurrentMode();
-    bool isDualApAllowedInCurrentMode();
-    std::string getFirstActiveWlanIfaceName();
-    std::string allocateApOrStaIfaceName(uint32_t start_idx);
-    std::string allocateApIfaceName();
-    std::string allocateStaIfaceName();
-    bool writeRingbufferFilesInternal();
-
-    ChipId chip_id_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
-    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
-    std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
-    std::vector<sp<WifiApIface>> ap_ifaces_;
-    std::vector<sp<WifiNanIface>> nan_ifaces_;
-    std::vector<sp<WifiP2pIface>> p2p_ifaces_;
-    std::vector<sp<WifiStaIface>> sta_ifaces_;
-    std::vector<sp<WifiRttController>> rtt_controllers_;
-    std::map<std::string, Ringbuffer> ringbuffer_map_;
-    bool is_valid_;
-    // Members pertaining to chip configuration.
-    uint32_t current_mode_id_;
-    std::vector<IWifiChip::ChipMode> modes_;
-    // The legacy ring buffer callback API has only a global callback
-    // registration mechanism. Use this to check if we have already
-    // registered a callback.
-    bool debug_ring_buffer_cb_registered_;
-    hidl_callback_util::HidlCallbackHandler<V1_2::IWifiChipEventCallback>
-        event_cb_handler_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiChip);
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_CHIP_H_
diff --git a/wifi/1.3/default/wifi_feature_flags.cpp b/wifi/1.3/default/wifi_feature_flags.cpp
deleted file mode 100644
index 7212cfa..0000000
--- a/wifi/1.3/default/wifi_feature_flags.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "wifi_feature_flags.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace feature_flags {
-
-using V1_0::ChipModeId;
-using V1_0::IfaceType;
-using V1_0::IWifiChip;
-
-/* The chip may either have a single mode supporting any number of combinations,
- * or a fixed dual-mode (so it involves firmware loading to switch between
- * modes) setting. If there is a need to support more modes, it needs to be
- * implemented manually in WiFi HAL (see changeFirmwareMode in
- * WifiChip::handleChipConfiguration).
- *
- * Supported combinations are defined in device's makefile, for example:
- *    WIFI_HAL_INTERFACE_COMBINATIONS := {{{STA, AP}, 1}, {{P2P, NAN}, 1}},
- *    WIFI_HAL_INTERFACE_COMBINATIONS += {{{STA}, 1}, {{AP}, 2}}
- * What means:
- *    Interface combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface
- *                             operations.
- *    Interface combination 2: 1 STA and 2 AP concurrent iface operations.
- *
- * For backward compatibility, the following makefile flags can be used to
- * generate combinations list:
- *  - WIFI_HIDL_FEATURE_DUAL_INTERFACE
- *  - WIFI_HIDL_FEATURE_DISABLE_AP
- *  - WIFI_HIDL_FEATURE_AWARE
- * However, they are ignored if WIFI_HAL_INTERFACE_COMBINATIONS was provided.
- * With WIFI_HIDL_FEATURE_DUAL_INTERFACE flag set, there is a single mode with
- * two interface combinations:
- *    Interface Combination 1: Will support 1 STA and 1 P2P or NAN (optional)
- *                             concurrent iface operations.
- *    Interface Combination 2: Will support 1 STA and 1 AP concurrent
- *                             iface operations.
- *
- * The only dual-mode configuration supported is for alternating STA and AP
- * mode, that may involve firmware reloading. In such case, there are 2 separate
- * modes of operation with 1 interface combination each:
- *    Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN (optional)
- *                       concurrent iface operations.
- *    Mode 2 (AP mode): Will support 1 AP iface operation.
- *
- * If Aware is enabled, the iface combination will be modified to support either
- * P2P or NAN in place of just P2P.
- */
-// clang-format off
-#ifdef WIFI_HAL_INTERFACE_COMBINATIONS
-constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
-#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE)
-// former V2 (fixed dual interface) setup expressed as V3
-constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
-#  ifdef WIFI_HIDL_FEATURE_DISABLE_AP
-#    ifdef WIFI_HIDL_FEATURE_AWARE
-//     1 STA + 1 of (P2P or NAN)
-#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
-#    else
-//     1 STA + 1 P2P
-#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
-#    endif
-#  else
-#    ifdef WIFI_HIDL_FEATURE_AWARE
-//     (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
-#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
-                                              {{{STA}, 1}, {{P2P, NAN}, 1}}
-#    else
-//     (1 STA + 1 AP) or (1 STA + 1 P2P)
-#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
-                                              {{{STA}, 1}, {{P2P}, 1}}
-#    endif
-#  endif
-#else
-// V1 (fixed single interface, dual-mode chip)
-constexpr ChipModeId kMainModeId = chip_mode_ids::kV1Sta;
-#  ifdef WIFI_HIDL_FEATURE_AWARE
-//   1 STA + 1 of (P2P or NAN)
-#    define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
-#  else
-//   1 STA + 1 P2P
-#    define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
-#  endif
-
-#  ifndef WIFI_HIDL_FEATURE_DISABLE_AP
-#    define WIFI_HAL_INTERFACE_COMBINATIONS_AP {{{AP}, 1}}
-#  endif
-#endif
-// clang-format on
-
-/**
- * Helper class to convert a collection of combination limits to a combination.
- *
- * The main point here is to simplify the syntax required by
- * WIFI_HAL_INTERFACE_COMBINATIONS.
- */
-struct ChipIfaceCombination
-    : public hidl_vec<IWifiChip::ChipIfaceCombinationLimit> {
-    ChipIfaceCombination(
-        const std::initializer_list<IWifiChip::ChipIfaceCombinationLimit> list)
-        : hidl_vec(list) {}
-
-    operator IWifiChip::ChipIfaceCombination() const { return {*this}; }
-
-    static hidl_vec<IWifiChip::ChipIfaceCombination> make_vec(
-        const std::initializer_list<ChipIfaceCombination> list) {
-        return hidl_vec<IWifiChip::ChipIfaceCombination>(  //
-            std::begin(list), std::end(list));
-    }
-};
-
-#define STA IfaceType::STA
-#define AP IfaceType::AP
-#define P2P IfaceType::P2P
-#define NAN IfaceType::NAN
-static const std::vector<IWifiChip::ChipMode> kChipModes{
-    {kMainModeId,
-     ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS})},
-#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
-    {chip_mode_ids::kV1Ap,
-     ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
-#endif
-};
-#undef STA
-#undef AP
-#undef P2P
-#undef NAN
-
-#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
-static const bool wifiHidlFeatureDisableApMacRandomization = true;
-#else
-static const bool wifiHidlFeatureDisableApMacRandomization = false;
-#endif  // WIFI_HIDL_FEATURE_DISABLE_AP
-
-WifiFeatureFlags::WifiFeatureFlags() {}
-
-std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes() {
-    return kChipModes;
-}
-
-bool WifiFeatureFlags::isApMacRandomizationDisabled() {
-    return wifiHidlFeatureDisableApMacRandomization;
-}
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_feature_flags.h b/wifi/1.3/default/wifi_feature_flags.h
deleted file mode 100644
index 3ae6920..0000000
--- a/wifi/1.3/default/wifi_feature_flags.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_FEATURE_FLAGS_H_
-#define WIFI_FEATURE_FLAGS_H_
-
-#include <android/hardware/wifi/1.2/IWifiChip.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace feature_flags {
-
-namespace chip_mode_ids {
-// These mode ID's should be unique (even across combo versions). Refer to
-// handleChipConfiguration() for it's usage.
-constexpr V1_0::ChipModeId kInvalid = UINT32_MAX;
-// Mode ID's for V1
-constexpr V1_0::ChipModeId kV1Sta = 0;
-constexpr V1_0::ChipModeId kV1Ap = 1;
-// Mode ID for V3
-constexpr V1_0::ChipModeId kV3 = 3;
-}  // namespace chip_mode_ids
-
-class WifiFeatureFlags {
-   public:
-    WifiFeatureFlags();
-    virtual ~WifiFeatureFlags() = default;
-
-    virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
-    virtual bool isApMacRandomizationDisabled();
-};
-
-}  // namespace feature_flags
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.3/default/wifi_iface_util.cpp b/wifi/1.3/default/wifi_iface_util.cpp
deleted file mode 100644
index 34bc02d..0000000
--- a/wifi/1.3/default/wifi_iface_util.cpp
+++ /dev/null
@@ -1,118 +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 <cstddef>
-#include <iostream>
-#include <limits>
-#include <random>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-
-#undef NAN
-#include "wifi_iface_util.h"
-
-namespace {
-// Constants to set the local bit & clear the multicast bit.
-constexpr uint8_t kMacAddressMulticastMask = 0x01;
-constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace iface_util {
-
-WifiIfaceUtil::WifiIfaceUtil(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : iface_tool_(iface_tool),
-      random_mac_address_(nullptr),
-      event_handlers_map_() {}
-
-std::array<uint8_t, 6> WifiIfaceUtil::getFactoryMacAddress(
-    const std::string& iface_name) {
-    return iface_tool_.lock()->GetFactoryMacAddress(iface_name.c_str());
-}
-
-bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
-                                  const std::array<uint8_t, 6>& mac) {
-    if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
-        LOG(ERROR) << "SetUpState(false) failed.";
-        return false;
-    }
-    if (!iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac)) {
-        LOG(ERROR) << "SetMacAddress failed.";
-        return false;
-    }
-    if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
-        LOG(ERROR) << "SetUpState(true) failed.";
-        return false;
-    }
-    IfaceEventHandlers event_handlers = {};
-    const auto it = event_handlers_map_.find(iface_name);
-    if (it != event_handlers_map_.end()) {
-        event_handlers = it->second;
-    }
-    if (event_handlers.on_state_toggle_off_on != nullptr) {
-        event_handlers.on_state_toggle_off_on(iface_name);
-    }
-    LOG(DEBUG) << "Successfully SetMacAddress.";
-    return true;
-}
-
-std::array<uint8_t, 6> WifiIfaceUtil::getOrCreateRandomMacAddress() {
-    if (random_mac_address_) {
-        return *random_mac_address_.get();
-    }
-    random_mac_address_ =
-        std::make_unique<std::array<uint8_t, 6>>(createRandomMacAddress());
-    return *random_mac_address_.get();
-}
-
-void WifiIfaceUtil::registerIfaceEventHandlers(const std::string& iface_name,
-                                               IfaceEventHandlers handlers) {
-    event_handlers_map_[iface_name] = handlers;
-}
-
-void WifiIfaceUtil::unregisterIfaceEventHandlers(
-    const std::string& iface_name) {
-    event_handlers_map_.erase(iface_name);
-}
-
-std::array<uint8_t, 6> WifiIfaceUtil::createRandomMacAddress() {
-    std::array<uint8_t, 6> address = {};
-    std::random_device rd;
-    std::default_random_engine engine(rd());
-    std::uniform_int_distribution<uint8_t> dist(
-        std::numeric_limits<uint8_t>::min(),
-        std::numeric_limits<uint8_t>::max());
-    for (size_t i = 0; i < address.size(); i++) {
-        address[i] = dist(engine);
-    }
-    // Set the local bit and clear the multicast bit.
-    address[0] |= kMacAddressLocallyAssignedMask;
-    address[0] &= ~kMacAddressMulticastMask;
-    return address;
-}
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_iface_util.h b/wifi/1.3/default/wifi_iface_util.h
deleted file mode 100644
index 98073e0..0000000
--- a/wifi/1.3/default/wifi_iface_util.h
+++ /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.
- */
-
-#ifndef WIFI_IFACE_UTIL_H_
-#define WIFI_IFACE_UTIL_H_
-
-#include <wifi_system/interface_tool.h>
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace iface_util {
-
-// Iface event handlers.
-struct IfaceEventHandlers {
-    // Callback to be invoked when the iface is set down & up for MAC address
-    // change.
-    std::function<void(const std::string& iface_name)> on_state_toggle_off_on;
-};
-
-/**
- * Util class for common iface operations.
- */
-class WifiIfaceUtil {
-   public:
-    WifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
-    virtual ~WifiIfaceUtil() = default;
-
-    virtual std::array<uint8_t, 6> getFactoryMacAddress(
-        const std::string& iface_name);
-    virtual bool setMacAddress(const std::string& iface_name,
-                               const std::array<uint8_t, 6>& mac);
-    // Get or create a random MAC address. The MAC address returned from
-    // this method will remain the same throughout the lifetime of the HAL
-    // daemon. (So, changes on every reboot)
-    virtual std::array<uint8_t, 6> getOrCreateRandomMacAddress();
-
-    // Register for any iface event callbacks for the provided interface.
-    virtual void registerIfaceEventHandlers(const std::string& iface_name,
-                                            IfaceEventHandlers handlers);
-    virtual void unregisterIfaceEventHandlers(const std::string& iface_name);
-
-   private:
-    std::array<uint8_t, 6> createRandomMacAddress();
-
-    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
-    std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;
-    std::map<std::string, IfaceEventHandlers> event_handlers_map_;
-};
-
-}  // namespace iface_util
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.3/default/wifi_legacy_hal.cpp b/wifi/1.3/default/wifi_legacy_hal.cpp
deleted file mode 100644
index 485bd16..0000000
--- a/wifi/1.3/default/wifi_legacy_hal.cpp
+++ /dev/null
@@ -1,1455 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <array>
-#include <chrono>
-
-#include <android-base/logging.h>
-#include <cutils/properties.h>
-
-#include "hidl_sync_util.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_legacy_hal_stubs.h"
-
-namespace {
-// Constants ported over from the legacy HAL calling code
-// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
-// away when this shim layer is replaced by the real vendor
-// implementation.
-static constexpr uint32_t kMaxVersionStringLength = 256;
-static constexpr uint32_t kMaxCachedGscanResults = 64;
-static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
-static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
-static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
-static constexpr uint32_t kMaxRingBuffers = 10;
-static constexpr uint32_t kMaxStopCompleteWaitMs = 100;
-static constexpr char kDriverPropName[] = "wlan.driver.status";
-
-// Helper function to create a non-const char* for legacy Hal API's.
-std::vector<char> makeCharVec(const std::string& str) {
-    std::vector<char> vec(str.size() + 1);
-    vec.assign(str.begin(), str.end());
-    vec.push_back('\0');
-    return vec;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace legacy_hal {
-// Legacy HAL functions accept "C" style function pointers, so use global
-// functions to pass to the legacy HAL function and store the corresponding
-// std::function methods to be invoked.
-//
-// Callback to be invoked once |stop| is complete
-std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
-void onAsyncStopComplete(wifi_handle handle) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_stop_complete_internal_callback) {
-        on_stop_complete_internal_callback(handle);
-        // Invalidate this callback since we don't want this firing again.
-        on_stop_complete_internal_callback = nullptr;
-    }
-}
-
-// Callback to be invoked for driver dump.
-std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
-void onSyncDriverMemoryDump(char* buffer, int buffer_size) {
-    if (on_driver_memory_dump_internal_callback) {
-        on_driver_memory_dump_internal_callback(buffer, buffer_size);
-    }
-}
-
-// Callback to be invoked for firmware dump.
-std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
-void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) {
-    if (on_firmware_memory_dump_internal_callback) {
-        on_firmware_memory_dump_internal_callback(buffer, buffer_size);
-    }
-}
-
-// Callback to be invoked for Gscan events.
-std::function<void(wifi_request_id, wifi_scan_event)>
-    on_gscan_event_internal_callback;
-void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_gscan_event_internal_callback) {
-        on_gscan_event_internal_callback(id, event);
-    }
-}
-
-// Callback to be invoked for Gscan full results.
-std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
-    on_gscan_full_result_internal_callback;
-void onAsyncGscanFullResult(wifi_request_id id, wifi_scan_result* result,
-                            uint32_t buckets_scanned) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_gscan_full_result_internal_callback) {
-        on_gscan_full_result_internal_callback(id, result, buckets_scanned);
-    }
-}
-
-// Callback to be invoked for link layer stats results.
-std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
-    on_link_layer_stats_result_internal_callback;
-void onSyncLinkLayerStatsResult(wifi_request_id id, wifi_iface_stat* iface_stat,
-                                int num_radios, wifi_radio_stat* radio_stat) {
-    if (on_link_layer_stats_result_internal_callback) {
-        on_link_layer_stats_result_internal_callback(id, iface_stat, num_radios,
-                                                     radio_stat);
-    }
-}
-
-// Callback to be invoked for rssi threshold breach.
-std::function<void((wifi_request_id, uint8_t*, int8_t))>
-    on_rssi_threshold_breached_internal_callback;
-void onAsyncRssiThresholdBreached(wifi_request_id id, uint8_t* bssid,
-                                  int8_t rssi) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_rssi_threshold_breached_internal_callback) {
-        on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
-    }
-}
-
-// Callback to be invoked for ring buffer data indication.
-std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
-    on_ring_buffer_data_internal_callback;
-void onAsyncRingBufferData(char* ring_name, char* buffer, int buffer_size,
-                           wifi_ring_buffer_status* status) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_ring_buffer_data_internal_callback) {
-        on_ring_buffer_data_internal_callback(ring_name, buffer, buffer_size,
-                                              status);
-    }
-}
-
-// Callback to be invoked for error alert indication.
-std::function<void(wifi_request_id, char*, int, int)>
-    on_error_alert_internal_callback;
-void onAsyncErrorAlert(wifi_request_id id, char* buffer, int buffer_size,
-                       int err_code) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_error_alert_internal_callback) {
-        on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
-    }
-}
-
-// Callback to be invoked for radio mode change indication.
-std::function<void(wifi_request_id, uint32_t, wifi_mac_info*)>
-    on_radio_mode_change_internal_callback;
-void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs,
-                            wifi_mac_info* mac_infos) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_radio_mode_change_internal_callback) {
-        on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
-    }
-}
-
-// Callback to be invoked for rtt results results.
-std::function<void(wifi_request_id, unsigned num_results,
-                   wifi_rtt_result* rtt_results[])>
-    on_rtt_results_internal_callback;
-void onAsyncRttResults(wifi_request_id id, unsigned num_results,
-                       wifi_rtt_result* rtt_results[]) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_rtt_results_internal_callback) {
-        on_rtt_results_internal_callback(id, num_results, rtt_results);
-        on_rtt_results_internal_callback = nullptr;
-    }
-}
-
-// Callbacks for the various NAN operations.
-// NOTE: These have very little conversions to perform before invoking the user
-// callbacks.
-// So, handle all of them here directly to avoid adding an unnecessary layer.
-std::function<void(transaction_id, const NanResponseMsg&)>
-    on_nan_notify_response_user_callback;
-void onAysncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_notify_response_user_callback && msg) {
-        on_nan_notify_response_user_callback(id, *msg);
-    }
-}
-
-std::function<void(const NanPublishRepliedInd&)>
-    on_nan_event_publish_replied_user_callback;
-void onAysncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
-    LOG(ERROR) << "onAysncNanEventPublishReplied triggered";
-}
-
-std::function<void(const NanPublishTerminatedInd&)>
-    on_nan_event_publish_terminated_user_callback;
-void onAysncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_publish_terminated_user_callback && event) {
-        on_nan_event_publish_terminated_user_callback(*event);
-    }
-}
-
-std::function<void(const NanMatchInd&)> on_nan_event_match_user_callback;
-void onAysncNanEventMatch(NanMatchInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_match_user_callback && event) {
-        on_nan_event_match_user_callback(*event);
-    }
-}
-
-std::function<void(const NanMatchExpiredInd&)>
-    on_nan_event_match_expired_user_callback;
-void onAysncNanEventMatchExpired(NanMatchExpiredInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_match_expired_user_callback && event) {
-        on_nan_event_match_expired_user_callback(*event);
-    }
-}
-
-std::function<void(const NanSubscribeTerminatedInd&)>
-    on_nan_event_subscribe_terminated_user_callback;
-void onAysncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_subscribe_terminated_user_callback && event) {
-        on_nan_event_subscribe_terminated_user_callback(*event);
-    }
-}
-
-std::function<void(const NanFollowupInd&)> on_nan_event_followup_user_callback;
-void onAysncNanEventFollowup(NanFollowupInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_followup_user_callback && event) {
-        on_nan_event_followup_user_callback(*event);
-    }
-}
-
-std::function<void(const NanDiscEngEventInd&)>
-    on_nan_event_disc_eng_event_user_callback;
-void onAysncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_disc_eng_event_user_callback && event) {
-        on_nan_event_disc_eng_event_user_callback(*event);
-    }
-}
-
-std::function<void(const NanDisabledInd&)> on_nan_event_disabled_user_callback;
-void onAysncNanEventDisabled(NanDisabledInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_disabled_user_callback && event) {
-        on_nan_event_disabled_user_callback(*event);
-    }
-}
-
-std::function<void(const NanTCAInd&)> on_nan_event_tca_user_callback;
-void onAysncNanEventTca(NanTCAInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_tca_user_callback && event) {
-        on_nan_event_tca_user_callback(*event);
-    }
-}
-
-std::function<void(const NanBeaconSdfPayloadInd&)>
-    on_nan_event_beacon_sdf_payload_user_callback;
-void onAysncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_beacon_sdf_payload_user_callback && event) {
-        on_nan_event_beacon_sdf_payload_user_callback(*event);
-    }
-}
-
-std::function<void(const NanDataPathRequestInd&)>
-    on_nan_event_data_path_request_user_callback;
-void onAysncNanEventDataPathRequest(NanDataPathRequestInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_data_path_request_user_callback && event) {
-        on_nan_event_data_path_request_user_callback(*event);
-    }
-}
-std::function<void(const NanDataPathConfirmInd&)>
-    on_nan_event_data_path_confirm_user_callback;
-void onAysncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_data_path_confirm_user_callback && event) {
-        on_nan_event_data_path_confirm_user_callback(*event);
-    }
-}
-
-std::function<void(const NanDataPathEndInd&)>
-    on_nan_event_data_path_end_user_callback;
-void onAysncNanEventDataPathEnd(NanDataPathEndInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_data_path_end_user_callback && event) {
-        on_nan_event_data_path_end_user_callback(*event);
-    }
-}
-
-std::function<void(const NanTransmitFollowupInd&)>
-    on_nan_event_transmit_follow_up_user_callback;
-void onAysncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_transmit_follow_up_user_callback && event) {
-        on_nan_event_transmit_follow_up_user_callback(*event);
-    }
-}
-
-std::function<void(const NanRangeRequestInd&)>
-    on_nan_event_range_request_user_callback;
-void onAysncNanEventRangeRequest(NanRangeRequestInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_range_request_user_callback && event) {
-        on_nan_event_range_request_user_callback(*event);
-    }
-}
-
-std::function<void(const NanRangeReportInd&)>
-    on_nan_event_range_report_user_callback;
-void onAysncNanEventRangeReport(NanRangeReportInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_range_report_user_callback && event) {
-        on_nan_event_range_report_user_callback(*event);
-    }
-}
-
-std::function<void(const NanDataPathScheduleUpdateInd&)>
-    on_nan_event_schedule_update_user_callback;
-void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (on_nan_event_schedule_update_user_callback && event) {
-        on_nan_event_schedule_update_user_callback(*event);
-    }
-}
-// End of the free-standing "C" style callbacks.
-
-WifiLegacyHal::WifiLegacyHal(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : global_handle_(nullptr),
-      awaiting_event_loop_termination_(false),
-      is_started_(false),
-      iface_tool_(iface_tool) {}
-
-wifi_error WifiLegacyHal::initialize() {
-    LOG(DEBUG) << "Initialize legacy HAL";
-    // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
-    // for now is this function call which we can directly call.
-    if (!initHalFuncTableWithStubs(&global_func_table_)) {
-        LOG(ERROR)
-            << "Failed to initialize legacy hal function table with stubs";
-        return WIFI_ERROR_UNKNOWN;
-    }
-    wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
-    if (status != WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to initialize legacy hal function table";
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::start() {
-    // Ensure that we're starting in a good state.
-    CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
-          iface_name_to_handle_.empty() && !awaiting_event_loop_termination_);
-    if (is_started_) {
-        LOG(DEBUG) << "Legacy HAL already started";
-        return WIFI_SUCCESS;
-    }
-    LOG(DEBUG) << "Waiting for the driver ready";
-    wifi_error status = global_func_table_.wifi_wait_for_driver_ready();
-    if (status == WIFI_ERROR_TIMED_OUT) {
-        LOG(ERROR) << "Timed out awaiting driver ready";
-        return status;
-    }
-    property_set(kDriverPropName, "ok");
-
-    LOG(DEBUG) << "Starting legacy HAL";
-    if (!iface_tool_.lock()->SetWifiUpState(true)) {
-        LOG(ERROR) << "Failed to set WiFi interface up";
-        return WIFI_ERROR_UNKNOWN;
-    }
-    status = global_func_table_.wifi_initialize(&global_handle_);
-    if (status != WIFI_SUCCESS || !global_handle_) {
-        LOG(ERROR) << "Failed to retrieve global handle";
-        return status;
-    }
-    std::thread(&WifiLegacyHal::runEventLoop, this).detach();
-    status = retrieveIfaceHandles();
-    if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) {
-        LOG(ERROR) << "Failed to retrieve wlan interface handle";
-        return status;
-    }
-    LOG(DEBUG) << "Legacy HAL start complete";
-    is_started_ = true;
-    return WIFI_SUCCESS;
-}
-
-wifi_error WifiLegacyHal::stop(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
-    const std::function<void()>& on_stop_complete_user_callback) {
-    if (!is_started_) {
-        LOG(DEBUG) << "Legacy HAL already stopped";
-        on_stop_complete_user_callback();
-        return WIFI_SUCCESS;
-    }
-    LOG(DEBUG) << "Stopping legacy HAL";
-    on_stop_complete_internal_callback = [on_stop_complete_user_callback,
-                                          this](wifi_handle handle) {
-        CHECK_EQ(global_handle_, handle) << "Handle mismatch";
-        LOG(INFO) << "Legacy HAL stop complete callback received";
-        // Invalidate all the internal pointers now that the HAL is
-        // stopped.
-        invalidate();
-        iface_tool_.lock()->SetWifiUpState(false);
-        on_stop_complete_user_callback();
-        is_started_ = false;
-    };
-    awaiting_event_loop_termination_ = true;
-    global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete);
-    const auto status = stop_wait_cv_.wait_for(
-        *lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs),
-        [this] { return !awaiting_event_loop_termination_; });
-    if (!status) {
-        LOG(ERROR) << "Legacy HAL stop failed or timed out";
-        return WIFI_ERROR_UNKNOWN;
-    }
-    LOG(DEBUG) << "Legacy HAL stop complete";
-    return WIFI_SUCCESS;
-}
-
-bool WifiLegacyHal::isStarted() { return is_started_; }
-
-std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion(
-    const std::string& iface_name) {
-    std::array<char, kMaxVersionStringLength> buffer;
-    buffer.fill(0);
-    wifi_error status = global_func_table_.wifi_get_driver_version(
-        getIfaceHandle(iface_name), buffer.data(), buffer.size());
-    return {status, buffer.data()};
-}
-
-std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion(
-    const std::string& iface_name) {
-    std::array<char, kMaxVersionStringLength> buffer;
-    buffer.fill(0);
-    wifi_error status = global_func_table_.wifi_get_firmware_version(
-        getIfaceHandle(iface_name), buffer.data(), buffer.size());
-    return {status, buffer.data()};
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::requestDriverMemoryDump(const std::string& iface_name) {
-    std::vector<uint8_t> driver_dump;
-    on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer,
-                                                             int buffer_size) {
-        driver_dump.insert(driver_dump.end(),
-                           reinterpret_cast<uint8_t*>(buffer),
-                           reinterpret_cast<uint8_t*>(buffer) + buffer_size);
-    };
-    wifi_error status = global_func_table_.wifi_get_driver_memory_dump(
-        getIfaceHandle(iface_name), {onSyncDriverMemoryDump});
-    on_driver_memory_dump_internal_callback = nullptr;
-    return {status, std::move(driver_dump)};
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::requestFirmwareMemoryDump(const std::string& iface_name) {
-    std::vector<uint8_t> firmware_dump;
-    on_firmware_memory_dump_internal_callback =
-        [&firmware_dump](char* buffer, int buffer_size) {
-            firmware_dump.insert(
-                firmware_dump.end(), reinterpret_cast<uint8_t*>(buffer),
-                reinterpret_cast<uint8_t*>(buffer) + buffer_size);
-        };
-    wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
-        getIfaceHandle(iface_name), {onSyncFirmwareMemoryDump});
-    on_firmware_memory_dump_internal_callback = nullptr;
-    return {status, std::move(firmware_dump)};
-}
-
-std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet(
-    const std::string& iface_name) {
-    feature_set set;
-    static_assert(sizeof(set) == sizeof(uint32_t),
-                  "Some feature_flags can not be represented in output");
-    wifi_error status = global_func_table_.wifi_get_supported_feature_set(
-        getIfaceHandle(iface_name), &set);
-    return {status, static_cast<uint32_t>(set)};
-}
-
-std::pair<wifi_error, PacketFilterCapabilities>
-WifiLegacyHal::getPacketFilterCapabilities(const std::string& iface_name) {
-    PacketFilterCapabilities caps;
-    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
-        getIfaceHandle(iface_name), &caps.version, &caps.max_len);
-    return {status, caps};
-}
-
-wifi_error WifiLegacyHal::setPacketFilter(const std::string& iface_name,
-                                          const std::vector<uint8_t>& program) {
-    return global_func_table_.wifi_set_packet_filter(
-        getIfaceHandle(iface_name), program.data(), program.size());
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::readApfPacketFilterData(const std::string& iface_name) {
-    PacketFilterCapabilities caps;
-    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
-        getIfaceHandle(iface_name), &caps.version, &caps.max_len);
-    if (status != WIFI_SUCCESS) {
-        return {status, {}};
-    }
-
-    // Size the buffer to read the entire program & work memory.
-    std::vector<uint8_t> buffer(caps.max_len);
-
-    status = global_func_table_.wifi_read_packet_filter(
-        getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(),
-        buffer.size());
-    return {status, move(buffer)};
-}
-
-std::pair<wifi_error, wifi_gscan_capabilities>
-WifiLegacyHal::getGscanCapabilities(const std::string& iface_name) {
-    wifi_gscan_capabilities caps;
-    wifi_error status = global_func_table_.wifi_get_gscan_capabilities(
-        getIfaceHandle(iface_name), &caps);
-    return {status, caps};
-}
-
-wifi_error WifiLegacyHal::startGscan(
-    const std::string& iface_name, wifi_request_id id,
-    const wifi_scan_cmd_params& params,
-    const std::function<void(wifi_request_id)>& on_failure_user_callback,
-    const on_gscan_results_callback& on_results_user_callback,
-    const on_gscan_full_result_callback& on_full_result_user_callback) {
-    // If there is already an ongoing background scan, reject new scan requests.
-    if (on_gscan_event_internal_callback ||
-        on_gscan_full_result_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-
-    // This callback will be used to either trigger |on_results_user_callback|
-    // or |on_failure_user_callback|.
-    on_gscan_event_internal_callback =
-        [iface_name, on_failure_user_callback, on_results_user_callback, this](
-            wifi_request_id id, wifi_scan_event event) {
-            switch (event) {
-                case WIFI_SCAN_RESULTS_AVAILABLE:
-                case WIFI_SCAN_THRESHOLD_NUM_SCANS:
-                case WIFI_SCAN_THRESHOLD_PERCENT: {
-                    wifi_error status;
-                    std::vector<wifi_cached_scan_results> cached_scan_results;
-                    std::tie(status, cached_scan_results) =
-                        getGscanCachedResults(iface_name);
-                    if (status == WIFI_SUCCESS) {
-                        on_results_user_callback(id, cached_scan_results);
-                        return;
-                    }
-                    FALLTHROUGH_INTENDED;
-                }
-                // Fall through if failed. Failure to retrieve cached scan
-                // results should trigger a background scan failure.
-                case WIFI_SCAN_FAILED:
-                    on_failure_user_callback(id);
-                    on_gscan_event_internal_callback = nullptr;
-                    on_gscan_full_result_internal_callback = nullptr;
-                    return;
-            }
-            LOG(FATAL) << "Unexpected gscan event received: " << event;
-        };
-
-    on_gscan_full_result_internal_callback = [on_full_result_user_callback](
-                                                 wifi_request_id id,
-                                                 wifi_scan_result* result,
-                                                 uint32_t buckets_scanned) {
-        if (result) {
-            on_full_result_user_callback(id, result, buckets_scanned);
-        }
-    };
-
-    wifi_scan_result_handler handler = {onAsyncGscanFullResult,
-                                        onAsyncGscanEvent};
-    wifi_error status = global_func_table_.wifi_start_gscan(
-        id, getIfaceHandle(iface_name), params, handler);
-    if (status != WIFI_SUCCESS) {
-        on_gscan_event_internal_callback = nullptr;
-        on_gscan_full_result_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::stopGscan(const std::string& iface_name,
-                                    wifi_request_id id) {
-    // If there is no an ongoing background scan, reject stop requests.
-    // TODO(b/32337212): This needs to be handled by the HIDL object because we
-    // need to return the NOT_STARTED error code.
-    if (!on_gscan_event_internal_callback &&
-        !on_gscan_full_result_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    wifi_error status =
-        global_func_table_.wifi_stop_gscan(id, getIfaceHandle(iface_name));
-    // If the request Id is wrong, don't stop the ongoing background scan. Any
-    // other error should be treated as the end of background scan.
-    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
-        on_gscan_event_internal_callback = nullptr;
-        on_gscan_full_result_internal_callback = nullptr;
-    }
-    return status;
-}
-
-std::pair<wifi_error, std::vector<uint32_t>>
-WifiLegacyHal::getValidFrequenciesForBand(const std::string& iface_name,
-                                          wifi_band band) {
-    static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
-                  "Wifi Channel cannot be represented in output");
-    std::vector<uint32_t> freqs;
-    freqs.resize(kMaxGscanFrequenciesForBand);
-    int32_t num_freqs = 0;
-    wifi_error status = global_func_table_.wifi_get_valid_channels(
-        getIfaceHandle(iface_name), band, freqs.size(),
-        reinterpret_cast<wifi_channel*>(freqs.data()), &num_freqs);
-    CHECK(num_freqs >= 0 &&
-          static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
-    freqs.resize(num_freqs);
-    return {status, std::move(freqs)};
-}
-
-wifi_error WifiLegacyHal::setDfsFlag(const std::string& iface_name,
-                                     bool dfs_on) {
-    return global_func_table_.wifi_set_nodfs_flag(getIfaceHandle(iface_name),
-                                                  dfs_on ? 0 : 1);
-}
-
-wifi_error WifiLegacyHal::enableLinkLayerStats(const std::string& iface_name,
-                                               bool debug) {
-    wifi_link_layer_params params;
-    params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
-    params.aggressive_statistics_gathering = debug;
-    return global_func_table_.wifi_set_link_stats(getIfaceHandle(iface_name),
-                                                  params);
-}
-
-wifi_error WifiLegacyHal::disableLinkLayerStats(const std::string& iface_name) {
-    // TODO: Do we care about these responses?
-    uint32_t clear_mask_rsp;
-    uint8_t stop_rsp;
-    return global_func_table_.wifi_clear_link_stats(
-        getIfaceHandle(iface_name), 0xFFFFFFFF, &clear_mask_rsp, 1, &stop_rsp);
-}
-
-std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
-    const std::string& iface_name) {
-    LinkLayerStats link_stats{};
-    LinkLayerStats* link_stats_ptr = &link_stats;
-
-    on_link_layer_stats_result_internal_callback =
-        [&link_stats_ptr](wifi_request_id /* id */,
-                          wifi_iface_stat* iface_stats_ptr, int num_radios,
-                          wifi_radio_stat* radio_stats_ptr) {
-            wifi_radio_stat* l_radio_stats_ptr;
-
-            if (iface_stats_ptr != nullptr) {
-                link_stats_ptr->iface = *iface_stats_ptr;
-                link_stats_ptr->iface.num_peers = 0;
-            } else {
-                LOG(ERROR) << "Invalid iface stats in link layer stats";
-            }
-            if (num_radios <= 0 || radio_stats_ptr == nullptr) {
-                LOG(ERROR) << "Invalid radio stats in link layer stats";
-                return;
-            }
-            l_radio_stats_ptr = radio_stats_ptr;
-            for (int i = 0; i < num_radios; i++) {
-                LinkLayerRadioStats radio;
-
-                radio.stats = *l_radio_stats_ptr;
-                // Copy over the tx level array to the separate vector.
-                if (l_radio_stats_ptr->num_tx_levels > 0 &&
-                    l_radio_stats_ptr->tx_time_per_levels != nullptr) {
-                    radio.tx_time_per_levels.assign(
-                        l_radio_stats_ptr->tx_time_per_levels,
-                        l_radio_stats_ptr->tx_time_per_levels +
-                            l_radio_stats_ptr->num_tx_levels);
-                }
-                radio.stats.num_tx_levels = 0;
-                radio.stats.tx_time_per_levels = nullptr;
-                /* Copy over the channel stat to separate vector */
-                if (l_radio_stats_ptr->num_channels > 0) {
-                    /* Copy the channel stats */
-                    radio.channel_stats.assign(
-                        l_radio_stats_ptr->channels,
-                        l_radio_stats_ptr->channels +
-                            l_radio_stats_ptr->num_channels);
-                }
-                link_stats_ptr->radios.push_back(radio);
-                l_radio_stats_ptr =
-                    (wifi_radio_stat*)((u8*)l_radio_stats_ptr +
-                                       sizeof(wifi_radio_stat) +
-                                       (sizeof(wifi_channel_stat) *
-                                        l_radio_stats_ptr->num_channels));
-            }
-        };
-
-    wifi_error status = global_func_table_.wifi_get_link_stats(
-        0, getIfaceHandle(iface_name), {onSyncLinkLayerStatsResult});
-    on_link_layer_stats_result_internal_callback = nullptr;
-    return {status, link_stats};
-}
-
-wifi_error WifiLegacyHal::startRssiMonitoring(
-    const std::string& iface_name, wifi_request_id id, int8_t max_rssi,
-    int8_t min_rssi,
-    const on_rssi_threshold_breached_callback&
-        on_threshold_breached_user_callback) {
-    if (on_rssi_threshold_breached_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_rssi_threshold_breached_internal_callback =
-        [on_threshold_breached_user_callback](wifi_request_id id,
-                                              uint8_t* bssid_ptr, int8_t rssi) {
-            if (!bssid_ptr) {
-                return;
-            }
-            std::array<uint8_t, 6> bssid_arr;
-            // |bssid_ptr| pointer is assumed to have 6 bytes for the mac
-            // address.
-            std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
-            on_threshold_breached_user_callback(id, bssid_arr, rssi);
-        };
-    wifi_error status = global_func_table_.wifi_start_rssi_monitoring(
-        id, getIfaceHandle(iface_name), max_rssi, min_rssi,
-        {onAsyncRssiThresholdBreached});
-    if (status != WIFI_SUCCESS) {
-        on_rssi_threshold_breached_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::stopRssiMonitoring(const std::string& iface_name,
-                                             wifi_request_id id) {
-    if (!on_rssi_threshold_breached_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    wifi_error status = global_func_table_.wifi_stop_rssi_monitoring(
-        id, getIfaceHandle(iface_name));
-    // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
-    // other error should be treated as the end of background scan.
-    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
-        on_rssi_threshold_breached_internal_callback = nullptr;
-    }
-    return status;
-}
-
-std::pair<wifi_error, wifi_roaming_capabilities>
-WifiLegacyHal::getRoamingCapabilities(const std::string& iface_name) {
-    wifi_roaming_capabilities caps;
-    wifi_error status = global_func_table_.wifi_get_roaming_capabilities(
-        getIfaceHandle(iface_name), &caps);
-    return {status, caps};
-}
-
-wifi_error WifiLegacyHal::configureRoaming(const std::string& iface_name,
-                                           const wifi_roaming_config& config) {
-    wifi_roaming_config config_internal = config;
-    return global_func_table_.wifi_configure_roaming(getIfaceHandle(iface_name),
-                                                     &config_internal);
-}
-
-wifi_error WifiLegacyHal::enableFirmwareRoaming(const std::string& iface_name,
-                                                fw_roaming_state_t state) {
-    return global_func_table_.wifi_enable_firmware_roaming(
-        getIfaceHandle(iface_name), state);
-}
-
-wifi_error WifiLegacyHal::configureNdOffload(const std::string& iface_name,
-                                             bool enable) {
-    return global_func_table_.wifi_configure_nd_offload(
-        getIfaceHandle(iface_name), enable);
-}
-
-wifi_error WifiLegacyHal::startSendingOffloadedPacket(
-    const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
-    const std::vector<uint8_t>& ip_packet_data,
-    const std::array<uint8_t, 6>& src_address,
-    const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
-    std::vector<uint8_t> ip_packet_data_internal(ip_packet_data);
-    std::vector<uint8_t> src_address_internal(
-        src_address.data(), src_address.data() + src_address.size());
-    std::vector<uint8_t> dst_address_internal(
-        dst_address.data(), dst_address.data() + dst_address.size());
-    return global_func_table_.wifi_start_sending_offloaded_packet(
-        cmd_id, getIfaceHandle(iface_name), ether_type,
-        ip_packet_data_internal.data(), ip_packet_data_internal.size(),
-        src_address_internal.data(), dst_address_internal.data(), period_in_ms);
-}
-
-wifi_error WifiLegacyHal::stopSendingOffloadedPacket(
-    const std::string& iface_name, uint32_t cmd_id) {
-    return global_func_table_.wifi_stop_sending_offloaded_packet(
-        cmd_id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::setScanningMacOui(const std::string& iface_name,
-                                            const std::array<uint8_t, 3>& oui) {
-    std::vector<uint8_t> oui_internal(oui.data(), oui.data() + oui.size());
-    return global_func_table_.wifi_set_scanning_mac_oui(
-        getIfaceHandle(iface_name), oui_internal.data());
-}
-
-wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name,
-                                                wifi_power_scenario scenario) {
-    return global_func_table_.wifi_select_tx_power_scenario(
-        getIfaceHandle(iface_name), scenario);
-}
-
-wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) {
-    return global_func_table_.wifi_reset_tx_power_scenario(
-        getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name,
-                                         wifi_latency_mode mode) {
-    return global_func_table_.wifi_set_latency_mode(getIfaceHandle(iface_name),
-                                                    mode);
-}
-
-std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
-    const std::string& iface_name) {
-    uint32_t supported_feature_flags;
-    wifi_error status =
-        global_func_table_.wifi_get_logger_supported_feature_set(
-            getIfaceHandle(iface_name), &supported_feature_flags);
-    return {status, supported_feature_flags};
-}
-
-wifi_error WifiLegacyHal::startPktFateMonitoring(
-    const std::string& iface_name) {
-    return global_func_table_.wifi_start_pkt_fate_monitoring(
-        getIfaceHandle(iface_name));
-}
-
-std::pair<wifi_error, std::vector<wifi_tx_report>> WifiLegacyHal::getTxPktFates(
-    const std::string& iface_name) {
-    std::vector<wifi_tx_report> tx_pkt_fates;
-    tx_pkt_fates.resize(MAX_FATE_LOG_LEN);
-    size_t num_fates = 0;
-    wifi_error status = global_func_table_.wifi_get_tx_pkt_fates(
-        getIfaceHandle(iface_name), tx_pkt_fates.data(), tx_pkt_fates.size(),
-        &num_fates);
-    CHECK(num_fates <= MAX_FATE_LOG_LEN);
-    tx_pkt_fates.resize(num_fates);
-    return {status, std::move(tx_pkt_fates)};
-}
-
-std::pair<wifi_error, std::vector<wifi_rx_report>> WifiLegacyHal::getRxPktFates(
-    const std::string& iface_name) {
-    std::vector<wifi_rx_report> rx_pkt_fates;
-    rx_pkt_fates.resize(MAX_FATE_LOG_LEN);
-    size_t num_fates = 0;
-    wifi_error status = global_func_table_.wifi_get_rx_pkt_fates(
-        getIfaceHandle(iface_name), rx_pkt_fates.data(), rx_pkt_fates.size(),
-        &num_fates);
-    CHECK(num_fates <= MAX_FATE_LOG_LEN);
-    rx_pkt_fates.resize(num_fates);
-    return {status, std::move(rx_pkt_fates)};
-}
-
-std::pair<wifi_error, WakeReasonStats> WifiLegacyHal::getWakeReasonStats(
-    const std::string& iface_name) {
-    WakeReasonStats stats;
-    stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
-    stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
-
-    // This legacy struct needs separate memory to store the variable sized wake
-    // reason types.
-    stats.wake_reason_cnt.cmd_event_wake_cnt =
-        reinterpret_cast<int32_t*>(stats.cmd_event_wake_cnt.data());
-    stats.wake_reason_cnt.cmd_event_wake_cnt_sz =
-        stats.cmd_event_wake_cnt.size();
-    stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0;
-    stats.wake_reason_cnt.driver_fw_local_wake_cnt =
-        reinterpret_cast<int32_t*>(stats.driver_fw_local_wake_cnt.data());
-    stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz =
-        stats.driver_fw_local_wake_cnt.size();
-    stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
-
-    wifi_error status = global_func_table_.wifi_get_wake_reason_stats(
-        getIfaceHandle(iface_name), &stats.wake_reason_cnt);
-
-    CHECK(
-        stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 &&
-        static_cast<uint32_t>(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <=
-            kMaxWakeReasonStatsArraySize);
-    stats.cmd_event_wake_cnt.resize(
-        stats.wake_reason_cnt.cmd_event_wake_cnt_used);
-    stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr;
-
-    CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 &&
-          static_cast<uint32_t>(
-              stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <=
-              kMaxWakeReasonStatsArraySize);
-    stats.driver_fw_local_wake_cnt.resize(
-        stats.wake_reason_cnt.driver_fw_local_wake_cnt_used);
-    stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr;
-
-    return {status, stats};
-}
-
-wifi_error WifiLegacyHal::registerRingBufferCallbackHandler(
-    const std::string& iface_name,
-    const on_ring_buffer_data_callback& on_user_data_callback) {
-    if (on_ring_buffer_data_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_ring_buffer_data_internal_callback =
-        [on_user_data_callback](char* ring_name, char* buffer, int buffer_size,
-                                wifi_ring_buffer_status* status) {
-            if (status && buffer) {
-                std::vector<uint8_t> buffer_vector(
-                    reinterpret_cast<uint8_t*>(buffer),
-                    reinterpret_cast<uint8_t*>(buffer) + buffer_size);
-                on_user_data_callback(ring_name, buffer_vector, *status);
-            }
-        };
-    wifi_error status = global_func_table_.wifi_set_log_handler(
-        0, getIfaceHandle(iface_name), {onAsyncRingBufferData});
-    if (status != WIFI_SUCCESS) {
-        on_ring_buffer_data_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler(
-    const std::string& iface_name) {
-    if (!on_ring_buffer_data_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_ring_buffer_data_internal_callback = nullptr;
-    return global_func_table_.wifi_reset_log_handler(
-        0, getIfaceHandle(iface_name));
-}
-
-std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
-WifiLegacyHal::getRingBuffersStatus(const std::string& iface_name) {
-    std::vector<wifi_ring_buffer_status> ring_buffers_status;
-    ring_buffers_status.resize(kMaxRingBuffers);
-    uint32_t num_rings = kMaxRingBuffers;
-    wifi_error status = global_func_table_.wifi_get_ring_buffers_status(
-        getIfaceHandle(iface_name), &num_rings, ring_buffers_status.data());
-    CHECK(num_rings <= kMaxRingBuffers);
-    ring_buffers_status.resize(num_rings);
-    return {status, std::move(ring_buffers_status)};
-}
-
-wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& iface_name,
-                                                 const std::string& ring_name,
-                                                 uint32_t verbose_level,
-                                                 uint32_t max_interval_sec,
-                                                 uint32_t min_data_size) {
-    return global_func_table_.wifi_start_logging(
-        getIfaceHandle(iface_name), verbose_level, 0, max_interval_sec,
-        min_data_size, makeCharVec(ring_name).data());
-}
-
-wifi_error WifiLegacyHal::getRingBufferData(const std::string& iface_name,
-                                            const std::string& ring_name) {
-    return global_func_table_.wifi_get_ring_data(getIfaceHandle(iface_name),
-                                                 makeCharVec(ring_name).data());
-}
-
-wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
-    const std::string& iface_name,
-    const on_error_alert_callback& on_user_alert_callback) {
-    if (on_error_alert_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_error_alert_internal_callback = [on_user_alert_callback](
-                                           wifi_request_id id, char* buffer,
-                                           int buffer_size, int err_code) {
-        if (buffer) {
-            CHECK(id == 0);
-            on_user_alert_callback(
-                err_code,
-                std::vector<uint8_t>(
-                    reinterpret_cast<uint8_t*>(buffer),
-                    reinterpret_cast<uint8_t*>(buffer) + buffer_size));
-        }
-    };
-    wifi_error status = global_func_table_.wifi_set_alert_handler(
-        0, getIfaceHandle(iface_name), {onAsyncErrorAlert});
-    if (status != WIFI_SUCCESS) {
-        on_error_alert_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler(
-    const std::string& iface_name) {
-    if (!on_error_alert_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_error_alert_internal_callback = nullptr;
-    return global_func_table_.wifi_reset_alert_handler(
-        0, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler(
-    const std::string& iface_name,
-    const on_radio_mode_change_callback& on_user_change_callback) {
-    if (on_radio_mode_change_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    on_radio_mode_change_internal_callback = [on_user_change_callback](
-                                                 wifi_request_id /* id */,
-                                                 uint32_t num_macs,
-                                                 wifi_mac_info* mac_infos_arr) {
-        if (num_macs > 0 && mac_infos_arr) {
-            std::vector<WifiMacInfo> mac_infos_vec;
-            for (uint32_t i = 0; i < num_macs; i++) {
-                WifiMacInfo mac_info;
-                mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id;
-                mac_info.mac_band = mac_infos_arr[i].mac_band;
-                for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) {
-                    WifiIfaceInfo iface_info;
-                    iface_info.name = mac_infos_arr[i].iface_info[j].iface_name;
-                    iface_info.channel = mac_infos_arr[i].iface_info[j].channel;
-                    mac_info.iface_infos.push_back(iface_info);
-                }
-                mac_infos_vec.push_back(mac_info);
-            }
-            on_user_change_callback(mac_infos_vec);
-        }
-    };
-    wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler(
-        0, getIfaceHandle(iface_name), {onAsyncRadioModeChange});
-    if (status != WIFI_SUCCESS) {
-        on_radio_mode_change_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::startRttRangeRequest(
-    const std::string& iface_name, wifi_request_id id,
-    const std::vector<wifi_rtt_config>& rtt_configs,
-    const on_rtt_results_callback& on_results_user_callback) {
-    if (on_rtt_results_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-
-    on_rtt_results_internal_callback =
-        [on_results_user_callback](wifi_request_id id, unsigned num_results,
-                                   wifi_rtt_result* rtt_results[]) {
-            if (num_results > 0 && !rtt_results) {
-                LOG(ERROR) << "Unexpected nullptr in RTT results";
-                return;
-            }
-            std::vector<const wifi_rtt_result*> rtt_results_vec;
-            std::copy_if(rtt_results, rtt_results + num_results,
-                         back_inserter(rtt_results_vec),
-                         [](wifi_rtt_result* rtt_result) {
-                             return rtt_result != nullptr;
-                         });
-            on_results_user_callback(id, rtt_results_vec);
-        };
-
-    std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
-    wifi_error status = global_func_table_.wifi_rtt_range_request(
-        id, getIfaceHandle(iface_name), rtt_configs.size(),
-        rtt_configs_internal.data(), {onAsyncRttResults});
-    if (status != WIFI_SUCCESS) {
-        on_rtt_results_internal_callback = nullptr;
-    }
-    return status;
-}
-
-wifi_error WifiLegacyHal::cancelRttRangeRequest(
-    const std::string& iface_name, wifi_request_id id,
-    const std::vector<std::array<uint8_t, 6>>& mac_addrs) {
-    if (!on_rtt_results_internal_callback) {
-        return WIFI_ERROR_NOT_AVAILABLE;
-    }
-    static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, 6>),
-                  "MAC address size mismatch");
-    // TODO: How do we handle partial cancels (i.e only a subset of enabled mac
-    // addressed are cancelled).
-    std::vector<std::array<uint8_t, 6>> mac_addrs_internal(mac_addrs);
-    wifi_error status = global_func_table_.wifi_rtt_range_cancel(
-        id, getIfaceHandle(iface_name), mac_addrs.size(),
-        reinterpret_cast<mac_addr*>(mac_addrs_internal.data()));
-    // If the request Id is wrong, don't stop the ongoing range request. Any
-    // other error should be treated as the end of rtt ranging.
-    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
-        on_rtt_results_internal_callback = nullptr;
-    }
-    return status;
-}
-
-std::pair<wifi_error, wifi_rtt_capabilities> WifiLegacyHal::getRttCapabilities(
-    const std::string& iface_name) {
-    wifi_rtt_capabilities rtt_caps;
-    wifi_error status = global_func_table_.wifi_get_rtt_capabilities(
-        getIfaceHandle(iface_name), &rtt_caps);
-    return {status, rtt_caps};
-}
-
-std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo(
-    const std::string& iface_name) {
-    wifi_rtt_responder rtt_responder;
-    wifi_error status = global_func_table_.wifi_rtt_get_responder_info(
-        getIfaceHandle(iface_name), &rtt_responder);
-    return {status, rtt_responder};
-}
-
-wifi_error WifiLegacyHal::enableRttResponder(
-    const std::string& iface_name, wifi_request_id id,
-    const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
-    const wifi_rtt_responder& info) {
-    wifi_rtt_responder info_internal(info);
-    return global_func_table_.wifi_enable_responder(
-        id, getIfaceHandle(iface_name), channel_hint, max_duration_secs,
-        &info_internal);
-}
-
-wifi_error WifiLegacyHal::disableRttResponder(const std::string& iface_name,
-                                              wifi_request_id id) {
-    return global_func_table_.wifi_disable_responder(
-        id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::setRttLci(const std::string& iface_name,
-                                    wifi_request_id id,
-                                    const wifi_lci_information& info) {
-    wifi_lci_information info_internal(info);
-    return global_func_table_.wifi_set_lci(id, getIfaceHandle(iface_name),
-                                           &info_internal);
-}
-
-wifi_error WifiLegacyHal::setRttLcr(const std::string& iface_name,
-                                    wifi_request_id id,
-                                    const wifi_lcr_information& info) {
-    wifi_lcr_information info_internal(info);
-    return global_func_table_.wifi_set_lcr(id, getIfaceHandle(iface_name),
-                                           &info_internal);
-}
-
-wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(
-    const std::string& iface_name, const NanCallbackHandlers& user_callbacks) {
-    on_nan_notify_response_user_callback = user_callbacks.on_notify_response;
-    on_nan_event_publish_terminated_user_callback =
-        user_callbacks.on_event_publish_terminated;
-    on_nan_event_match_user_callback = user_callbacks.on_event_match;
-    on_nan_event_match_expired_user_callback =
-        user_callbacks.on_event_match_expired;
-    on_nan_event_subscribe_terminated_user_callback =
-        user_callbacks.on_event_subscribe_terminated;
-    on_nan_event_followup_user_callback = user_callbacks.on_event_followup;
-    on_nan_event_disc_eng_event_user_callback =
-        user_callbacks.on_event_disc_eng_event;
-    on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled;
-    on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
-    on_nan_event_beacon_sdf_payload_user_callback =
-        user_callbacks.on_event_beacon_sdf_payload;
-    on_nan_event_data_path_request_user_callback =
-        user_callbacks.on_event_data_path_request;
-    on_nan_event_data_path_confirm_user_callback =
-        user_callbacks.on_event_data_path_confirm;
-    on_nan_event_data_path_end_user_callback =
-        user_callbacks.on_event_data_path_end;
-    on_nan_event_transmit_follow_up_user_callback =
-        user_callbacks.on_event_transmit_follow_up;
-    on_nan_event_range_request_user_callback =
-        user_callbacks.on_event_range_request;
-    on_nan_event_range_report_user_callback =
-        user_callbacks.on_event_range_report;
-    on_nan_event_schedule_update_user_callback =
-        user_callbacks.on_event_schedule_update;
-
-    return global_func_table_.wifi_nan_register_handler(
-        getIfaceHandle(iface_name),
-        {onAysncNanNotifyResponse, onAysncNanEventPublishReplied,
-         onAysncNanEventPublishTerminated, onAysncNanEventMatch,
-         onAysncNanEventMatchExpired, onAysncNanEventSubscribeTerminated,
-         onAysncNanEventFollowup, onAysncNanEventDiscEngEvent,
-         onAysncNanEventDisabled, onAysncNanEventTca,
-         onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
-         onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
-         onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
-         onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
-}
-
-wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name,
-                                           transaction_id id,
-                                           const NanEnableRequest& msg) {
-    NanEnableRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_enable_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanDisableRequest(const std::string& iface_name,
-                                            transaction_id id) {
-    return global_func_table_.wifi_nan_disable_request(
-        id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::nanPublishRequest(const std::string& iface_name,
-                                            transaction_id id,
-                                            const NanPublishRequest& msg) {
-    NanPublishRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_publish_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanPublishCancelRequest(
-    const std::string& iface_name, transaction_id id,
-    const NanPublishCancelRequest& msg) {
-    NanPublishCancelRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_publish_cancel_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanSubscribeRequest(const std::string& iface_name,
-                                              transaction_id id,
-                                              const NanSubscribeRequest& msg) {
-    NanSubscribeRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_subscribe_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanSubscribeCancelRequest(
-    const std::string& iface_name, transaction_id id,
-    const NanSubscribeCancelRequest& msg) {
-    NanSubscribeCancelRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_subscribe_cancel_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanTransmitFollowupRequest(
-    const std::string& iface_name, transaction_id id,
-    const NanTransmitFollowupRequest& msg) {
-    NanTransmitFollowupRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_transmit_followup_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanStatsRequest(const std::string& iface_name,
-                                          transaction_id id,
-                                          const NanStatsRequest& msg) {
-    NanStatsRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_stats_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanConfigRequest(const std::string& iface_name,
-                                           transaction_id id,
-                                           const NanConfigRequest& msg) {
-    NanConfigRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_config_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanTcaRequest(const std::string& iface_name,
-                                        transaction_id id,
-                                        const NanTCARequest& msg) {
-    NanTCARequest msg_internal(msg);
-    return global_func_table_.wifi_nan_tca_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(
-    const std::string& iface_name, transaction_id id,
-    const NanBeaconSdfPayloadRequest& msg) {
-    NanBeaconSdfPayloadRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_beacon_sdf_payload_request(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-std::pair<wifi_error, NanVersion> WifiLegacyHal::nanGetVersion() {
-    NanVersion version;
-    wifi_error status =
-        global_func_table_.wifi_nan_get_version(global_handle_, &version);
-    return {status, version};
-}
-
-wifi_error WifiLegacyHal::nanGetCapabilities(const std::string& iface_name,
-                                             transaction_id id) {
-    return global_func_table_.wifi_nan_get_capabilities(
-        id, getIfaceHandle(iface_name));
-}
-
-wifi_error WifiLegacyHal::nanDataInterfaceCreate(
-    const std::string& iface_name, transaction_id id,
-    const std::string& data_iface_name) {
-    return global_func_table_.wifi_nan_data_interface_create(
-        id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
-}
-
-wifi_error WifiLegacyHal::nanDataInterfaceDelete(
-    const std::string& iface_name, transaction_id id,
-    const std::string& data_iface_name) {
-    return global_func_table_.wifi_nan_data_interface_delete(
-        id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
-}
-
-wifi_error WifiLegacyHal::nanDataRequestInitiator(
-    const std::string& iface_name, transaction_id id,
-    const NanDataPathInitiatorRequest& msg) {
-    NanDataPathInitiatorRequest msg_internal(msg);
-    return global_func_table_.wifi_nan_data_request_initiator(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanDataIndicationResponse(
-    const std::string& iface_name, transaction_id id,
-    const NanDataPathIndicationResponse& msg) {
-    NanDataPathIndicationResponse msg_internal(msg);
-    return global_func_table_.wifi_nan_data_indication_response(
-        id, getIfaceHandle(iface_name), &msg_internal);
-}
-
-typedef struct {
-    u8 num_ndp_instances;
-    NanDataPathId ndp_instance_id;
-} NanDataPathEndSingleNdpIdRequest;
-
-wifi_error WifiLegacyHal::nanDataEnd(const std::string& iface_name,
-                                     transaction_id id,
-                                     uint32_t ndpInstanceId) {
-    NanDataPathEndSingleNdpIdRequest msg;
-    msg.num_ndp_instances = 1;
-    msg.ndp_instance_id = ndpInstanceId;
-    wifi_error status = global_func_table_.wifi_nan_data_end(
-        id, getIfaceHandle(iface_name), (NanDataPathEndRequest*)&msg);
-    return status;
-}
-
-wifi_error WifiLegacyHal::setCountryCode(const std::string& iface_name,
-                                         std::array<int8_t, 2> code) {
-    std::string code_str(code.data(), code.data() + code.size());
-    return global_func_table_.wifi_set_country_code(getIfaceHandle(iface_name),
-                                                    code_str.c_str());
-}
-
-wifi_error WifiLegacyHal::retrieveIfaceHandles() {
-    wifi_interface_handle* iface_handles = nullptr;
-    int num_iface_handles = 0;
-    wifi_error status = global_func_table_.wifi_get_ifaces(
-        global_handle_, &num_iface_handles, &iface_handles);
-    if (status != WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to enumerate interface handles";
-        return status;
-    }
-    for (int i = 0; i < num_iface_handles; ++i) {
-        std::array<char, IFNAMSIZ> iface_name_arr = {};
-        status = global_func_table_.wifi_get_iface_name(
-            iface_handles[i], iface_name_arr.data(), iface_name_arr.size());
-        if (status != WIFI_SUCCESS) {
-            LOG(WARNING) << "Failed to get interface handle name";
-            continue;
-        }
-        // Assuming the interface name is null terminated since the legacy HAL
-        // API does not return a size.
-        std::string iface_name(iface_name_arr.data());
-        LOG(INFO) << "Adding interface handle for " << iface_name;
-        iface_name_to_handle_[iface_name] = iface_handles[i];
-    }
-    return WIFI_SUCCESS;
-}
-
-wifi_interface_handle WifiLegacyHal::getIfaceHandle(
-    const std::string& iface_name) {
-    const auto iface_handle_iter = iface_name_to_handle_.find(iface_name);
-    if (iface_handle_iter == iface_name_to_handle_.end()) {
-        LOG(ERROR) << "Unknown iface name: " << iface_name;
-        return nullptr;
-    }
-    return iface_handle_iter->second;
-}
-
-void WifiLegacyHal::runEventLoop() {
-    LOG(DEBUG) << "Starting legacy HAL event loop";
-    global_func_table_.wifi_event_loop(global_handle_);
-    const auto lock = hidl_sync_util::acquireGlobalLock();
-    if (!awaiting_event_loop_termination_) {
-        LOG(FATAL)
-            << "Legacy HAL event loop terminated, but HAL was not stopping";
-    }
-    LOG(DEBUG) << "Legacy HAL event loop terminated";
-    awaiting_event_loop_termination_ = false;
-    stop_wait_cv_.notify_one();
-}
-
-std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
-WifiLegacyHal::getGscanCachedResults(const std::string& iface_name) {
-    std::vector<wifi_cached_scan_results> cached_scan_results;
-    cached_scan_results.resize(kMaxCachedGscanResults);
-    int32_t num_results = 0;
-    wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
-        getIfaceHandle(iface_name), true /* always flush */,
-        cached_scan_results.size(), cached_scan_results.data(), &num_results);
-    CHECK(num_results >= 0 &&
-          static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
-    cached_scan_results.resize(num_results);
-    // Check for invalid IE lengths in these cached scan results and correct it.
-    for (auto& cached_scan_result : cached_scan_results) {
-        int num_scan_results = cached_scan_result.num_results;
-        for (int i = 0; i < num_scan_results; i++) {
-            auto& scan_result = cached_scan_result.results[i];
-            if (scan_result.ie_length > 0) {
-                LOG(DEBUG) << "Cached scan result has non-zero IE length "
-                           << scan_result.ie_length;
-                scan_result.ie_length = 0;
-            }
-        }
-    }
-    return {status, std::move(cached_scan_results)};
-}
-
-void WifiLegacyHal::invalidate() {
-    global_handle_ = nullptr;
-    iface_name_to_handle_.clear();
-    on_driver_memory_dump_internal_callback = nullptr;
-    on_firmware_memory_dump_internal_callback = nullptr;
-    on_gscan_event_internal_callback = nullptr;
-    on_gscan_full_result_internal_callback = nullptr;
-    on_link_layer_stats_result_internal_callback = nullptr;
-    on_rssi_threshold_breached_internal_callback = nullptr;
-    on_ring_buffer_data_internal_callback = nullptr;
-    on_error_alert_internal_callback = nullptr;
-    on_radio_mode_change_internal_callback = nullptr;
-    on_rtt_results_internal_callback = nullptr;
-    on_nan_notify_response_user_callback = nullptr;
-    on_nan_event_publish_terminated_user_callback = nullptr;
-    on_nan_event_match_user_callback = nullptr;
-    on_nan_event_match_expired_user_callback = nullptr;
-    on_nan_event_subscribe_terminated_user_callback = nullptr;
-    on_nan_event_followup_user_callback = nullptr;
-    on_nan_event_disc_eng_event_user_callback = nullptr;
-    on_nan_event_disabled_user_callback = nullptr;
-    on_nan_event_tca_user_callback = nullptr;
-    on_nan_event_beacon_sdf_payload_user_callback = nullptr;
-    on_nan_event_data_path_request_user_callback = nullptr;
-    on_nan_event_data_path_confirm_user_callback = nullptr;
-    on_nan_event_data_path_end_user_callback = nullptr;
-    on_nan_event_transmit_follow_up_user_callback = nullptr;
-    on_nan_event_range_request_user_callback = nullptr;
-    on_nan_event_range_report_user_callback = nullptr;
-    on_nan_event_schedule_update_user_callback = nullptr;
-}
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_legacy_hal.h b/wifi/1.3/default/wifi_legacy_hal.h
deleted file mode 100644
index 9cfa172..0000000
--- a/wifi/1.3/default/wifi_legacy_hal.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_LEGACY_HAL_H_
-#define WIFI_LEGACY_HAL_H_
-
-#include <condition_variable>
-#include <functional>
-#include <map>
-#include <thread>
-#include <vector>
-
-#include <wifi_system/interface_tool.h>
-
-// HACK: The include inside the namespace below also transitively includes a
-// bunch of libc headers into the namespace, which leads to functions like
-// socketpair being defined in
-// android::hardware::wifi::V1_1::implementation::legacy_hal. Include this one
-// particular header as a hacky workaround until that's fixed.
-#include <sys/socket.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-// This is in a separate namespace to prevent typename conflicts between
-// the legacy HAL types and the HIDL interface types.
-namespace legacy_hal {
-// Wrap all the types defined inside the legacy HAL header files inside this
-// namespace.
-#include <hardware_legacy/wifi_hal.h>
-
-// APF capabilities supported by the iface.
-struct PacketFilterCapabilities {
-    uint32_t version;
-    uint32_t max_len;
-};
-
-// WARNING: We don't care about the variable sized members of either
-// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
-// to escape the compiler warnings regarding this.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
-// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
-// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
-// into a separate return element to avoid passing pointers around.
-struct LinkLayerRadioStats {
-    wifi_radio_stat stats;
-    std::vector<uint32_t> tx_time_per_levels;
-    std::vector<wifi_channel_stat> channel_stats;
-};
-
-struct LinkLayerStats {
-    wifi_iface_stat iface;
-    std::vector<LinkLayerRadioStats> radios;
-};
-#pragma GCC diagnostic pop
-
-// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
-// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
-// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
-// API. Separate that out into a separate return elements to avoid passing
-// pointers around.
-struct WakeReasonStats {
-    WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
-    std::vector<uint32_t> cmd_event_wake_cnt;
-    std::vector<uint32_t> driver_fw_local_wake_cnt;
-};
-
-// NAN response and event callbacks struct.
-struct NanCallbackHandlers {
-    // NotifyResponse invoked to notify the status of the Request.
-    std::function<void(transaction_id, const NanResponseMsg&)>
-        on_notify_response;
-    // Various event callbacks.
-    std::function<void(const NanPublishTerminatedInd&)>
-        on_event_publish_terminated;
-    std::function<void(const NanMatchInd&)> on_event_match;
-    std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
-    std::function<void(const NanSubscribeTerminatedInd&)>
-        on_event_subscribe_terminated;
-    std::function<void(const NanFollowupInd&)> on_event_followup;
-    std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
-    std::function<void(const NanDisabledInd&)> on_event_disabled;
-    std::function<void(const NanTCAInd&)> on_event_tca;
-    std::function<void(const NanBeaconSdfPayloadInd&)>
-        on_event_beacon_sdf_payload;
-    std::function<void(const NanDataPathRequestInd&)>
-        on_event_data_path_request;
-    std::function<void(const NanDataPathConfirmInd&)>
-        on_event_data_path_confirm;
-    std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
-    std::function<void(const NanTransmitFollowupInd&)>
-        on_event_transmit_follow_up;
-    std::function<void(const NanRangeRequestInd&)> on_event_range_request;
-    std::function<void(const NanRangeReportInd&)> on_event_range_report;
-    std::function<void(const NanDataPathScheduleUpdateInd&)>
-        on_event_schedule_update;
-};
-
-// Full scan results contain IE info and are hence passed by reference, to
-// preserve the variable length array member |ie_data|. Callee must not retain
-// the pointer.
-using on_gscan_full_result_callback =
-    std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
-// These scan results don't contain any IE info, so no need to pass by
-// reference.
-using on_gscan_results_callback = std::function<void(
-    wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
-
-// Invoked when the rssi value breaches the thresholds set.
-using on_rssi_threshold_breached_callback =
-    std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
-
-// Callback for RTT range request results.
-// Rtt results contain IE info and are hence passed by reference, to
-// preserve the |LCI| and |LCR| pointers. Callee must not retain
-// the pointer.
-using on_rtt_results_callback = std::function<void(
-    wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
-
-// Callback for ring buffer data.
-using on_ring_buffer_data_callback =
-    std::function<void(const std::string&, const std::vector<uint8_t>&,
-                       const wifi_ring_buffer_status&)>;
-
-// Callback for alerts.
-using on_error_alert_callback =
-    std::function<void(int32_t, const std::vector<uint8_t>&)>;
-
-// Struct for the mac info from the legacy HAL. This is a cleaner version
-// of the |wifi_mac_info| & |wifi_iface_info|.
-typedef struct {
-    std::string name;
-    wifi_channel channel;
-} WifiIfaceInfo;
-
-typedef struct {
-    uint32_t wlan_mac_id;
-    /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
-    uint32_t mac_band;
-    /* Represents the connected Wi-Fi interfaces associated with each MAC */
-    std::vector<WifiIfaceInfo> iface_infos;
-} WifiMacInfo;
-
-// Callback for radio mode change
-using on_radio_mode_change_callback =
-    std::function<void(const std::vector<WifiMacInfo>&)>;
-
-/**
- * Class that encapsulates all legacy HAL interactions.
- * This class manages the lifetime of the event loop thread used by legacy HAL.
- *
- * Note: There will only be a single instance of this class created in the Wifi
- * object and will be valid for the lifetime of the process.
- */
-class WifiLegacyHal {
-   public:
-    WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
-    virtual ~WifiLegacyHal() = default;
-
-    // Initialize the legacy HAL function table.
-    virtual wifi_error initialize();
-    // Start the legacy HAL and the event looper thread.
-    virtual wifi_error start();
-    // Deinitialize the legacy HAL and wait for the event loop thread to exit
-    // using a predefined timeout.
-    virtual wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
-                            const std::function<void()>& on_complete_callback);
-    // Checks if legacy HAL has successfully started
-    bool isStarted();
-    // Wrappers for all the functions in the legacy HAL function table.
-    virtual std::pair<wifi_error, std::string> getDriverVersion(
-        const std::string& iface_name);
-    virtual std::pair<wifi_error, std::string> getFirmwareVersion(
-        const std::string& iface_name);
-    std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
-        const std::string& iface_name);
-    std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
-        const std::string& iface_name);
-    std::pair<wifi_error, uint32_t> getSupportedFeatureSet(
-        const std::string& iface_name);
-    // APF functions.
-    std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
-        const std::string& iface_name);
-    wifi_error setPacketFilter(const std::string& iface_name,
-                               const std::vector<uint8_t>& program);
-    std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
-        const std::string& iface_name);
-    // Gscan functions.
-    std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
-        const std::string& iface_name);
-    // These API's provides a simplified interface over the legacy Gscan API's:
-    // a) All scan events from the legacy HAL API other than the
-    //    |WIFI_SCAN_FAILED| are treated as notification of results.
-    //    This method then retrieves the cached scan results from the legacy
-    //    HAL API and triggers the externally provided
-    //    |on_results_user_callback| on success.
-    // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan
-    // results
-    //    triggers the externally provided |on_failure_user_callback|.
-    // c) Full scan result event triggers the externally provided
-    //    |on_full_result_user_callback|.
-    wifi_error startGscan(
-        const std::string& iface_name, wifi_request_id id,
-        const wifi_scan_cmd_params& params,
-        const std::function<void(wifi_request_id)>& on_failure_callback,
-        const on_gscan_results_callback& on_results_callback,
-        const on_gscan_full_result_callback& on_full_result_callback);
-    wifi_error stopGscan(const std::string& iface_name, wifi_request_id id);
-    std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
-        const std::string& iface_name, wifi_band band);
-    virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on);
-    // Link layer stats functions.
-    wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
-    wifi_error disableLinkLayerStats(const std::string& iface_name);
-    std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(
-        const std::string& iface_name);
-    // RSSI monitor functions.
-    wifi_error startRssiMonitoring(const std::string& iface_name,
-                                   wifi_request_id id, int8_t max_rssi,
-                                   int8_t min_rssi,
-                                   const on_rssi_threshold_breached_callback&
-                                       on_threshold_breached_callback);
-    wifi_error stopRssiMonitoring(const std::string& iface_name,
-                                  wifi_request_id id);
-    std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities(
-        const std::string& iface_name);
-    wifi_error configureRoaming(const std::string& iface_name,
-                                const wifi_roaming_config& config);
-    wifi_error enableFirmwareRoaming(const std::string& iface_name,
-                                     fw_roaming_state_t state);
-    wifi_error configureNdOffload(const std::string& iface_name, bool enable);
-    wifi_error startSendingOffloadedPacket(
-        const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
-        const std::vector<uint8_t>& ip_packet_data,
-        const std::array<uint8_t, 6>& src_address,
-        const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
-    wifi_error stopSendingOffloadedPacket(const std::string& iface_name,
-                                          uint32_t cmd_id);
-    wifi_error setScanningMacOui(const std::string& iface_name,
-                                 const std::array<uint8_t, 3>& oui);
-    virtual wifi_error selectTxPowerScenario(const std::string& iface_name,
-                                             wifi_power_scenario scenario);
-    virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
-    wifi_error setLatencyMode(const std::string& iface_name,
-                              wifi_latency_mode mode);
-    // Logger/debug functions.
-    std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(
-        const std::string& iface_name);
-    wifi_error startPktFateMonitoring(const std::string& iface_name);
-    std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates(
-        const std::string& iface_name);
-    std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates(
-        const std::string& iface_name);
-    std::pair<wifi_error, WakeReasonStats> getWakeReasonStats(
-        const std::string& iface_name);
-    wifi_error registerRingBufferCallbackHandler(
-        const std::string& iface_name,
-        const on_ring_buffer_data_callback& on_data_callback);
-    wifi_error deregisterRingBufferCallbackHandler(
-        const std::string& iface_name);
-    std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
-    getRingBuffersStatus(const std::string& iface_name);
-    wifi_error startRingBufferLogging(const std::string& iface_name,
-                                      const std::string& ring_name,
-                                      uint32_t verbose_level,
-                                      uint32_t max_interval_sec,
-                                      uint32_t min_data_size);
-    wifi_error getRingBufferData(const std::string& iface_name,
-                                 const std::string& ring_name);
-    wifi_error registerErrorAlertCallbackHandler(
-        const std::string& iface_name,
-        const on_error_alert_callback& on_alert_callback);
-    wifi_error deregisterErrorAlertCallbackHandler(
-        const std::string& iface_name);
-    // Radio mode functions.
-    virtual wifi_error registerRadioModeChangeCallbackHandler(
-        const std::string& iface_name,
-        const on_radio_mode_change_callback& on_user_change_callback);
-    // RTT functions.
-    wifi_error startRttRangeRequest(
-        const std::string& iface_name, wifi_request_id id,
-        const std::vector<wifi_rtt_config>& rtt_configs,
-        const on_rtt_results_callback& on_results_callback);
-    wifi_error cancelRttRangeRequest(
-        const std::string& iface_name, wifi_request_id id,
-        const std::vector<std::array<uint8_t, 6>>& mac_addrs);
-    std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(
-        const std::string& iface_name);
-    std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(
-        const std::string& iface_name);
-    wifi_error enableRttResponder(const std::string& iface_name,
-                                  wifi_request_id id,
-                                  const wifi_channel_info& channel_hint,
-                                  uint32_t max_duration_secs,
-                                  const wifi_rtt_responder& info);
-    wifi_error disableRttResponder(const std::string& iface_name,
-                                   wifi_request_id id);
-    wifi_error setRttLci(const std::string& iface_name, wifi_request_id id,
-                         const wifi_lci_information& info);
-    wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id,
-                         const wifi_lcr_information& info);
-    // NAN functions.
-    virtual wifi_error nanRegisterCallbackHandlers(
-        const std::string& iface_name, const NanCallbackHandlers& callbacks);
-    wifi_error nanEnableRequest(const std::string& iface_name,
-                                transaction_id id, const NanEnableRequest& msg);
-    virtual wifi_error nanDisableRequest(const std::string& iface_name,
-                                         transaction_id id);
-    wifi_error nanPublishRequest(const std::string& iface_name,
-                                 transaction_id id,
-                                 const NanPublishRequest& msg);
-    wifi_error nanPublishCancelRequest(const std::string& iface_name,
-                                       transaction_id id,
-                                       const NanPublishCancelRequest& msg);
-    wifi_error nanSubscribeRequest(const std::string& iface_name,
-                                   transaction_id id,
-                                   const NanSubscribeRequest& msg);
-    wifi_error nanSubscribeCancelRequest(const std::string& iface_name,
-                                         transaction_id id,
-                                         const NanSubscribeCancelRequest& msg);
-    wifi_error nanTransmitFollowupRequest(
-        const std::string& iface_name, transaction_id id,
-        const NanTransmitFollowupRequest& msg);
-    wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id,
-                               const NanStatsRequest& msg);
-    wifi_error nanConfigRequest(const std::string& iface_name,
-                                transaction_id id, const NanConfigRequest& msg);
-    wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id,
-                             const NanTCARequest& msg);
-    wifi_error nanBeaconSdfPayloadRequest(
-        const std::string& iface_name, transaction_id id,
-        const NanBeaconSdfPayloadRequest& msg);
-    std::pair<wifi_error, NanVersion> nanGetVersion();
-    wifi_error nanGetCapabilities(const std::string& iface_name,
-                                  transaction_id id);
-    wifi_error nanDataInterfaceCreate(const std::string& iface_name,
-                                      transaction_id id,
-                                      const std::string& data_iface_name);
-    virtual wifi_error nanDataInterfaceDelete(
-        const std::string& iface_name, transaction_id id,
-        const std::string& data_iface_name);
-    wifi_error nanDataRequestInitiator(const std::string& iface_name,
-                                       transaction_id id,
-                                       const NanDataPathInitiatorRequest& msg);
-    wifi_error nanDataIndicationResponse(
-        const std::string& iface_name, transaction_id id,
-        const NanDataPathIndicationResponse& msg);
-    wifi_error nanDataEnd(const std::string& iface_name, transaction_id id,
-                          uint32_t ndpInstanceId);
-    // AP functions.
-    wifi_error setCountryCode(const std::string& iface_name,
-                              std::array<int8_t, 2> code);
-
-   private:
-    // Retrieve interface handles for all the available interfaces.
-    wifi_error retrieveIfaceHandles();
-    wifi_interface_handle getIfaceHandle(const std::string& iface_name);
-    // Run the legacy HAL event loop thread.
-    void runEventLoop();
-    // Retrieve the cached gscan results to pass the results back to the
-    // external callbacks.
-    std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
-    getGscanCachedResults(const std::string& iface_name);
-    void invalidate();
-
-    // Global function table of legacy HAL.
-    wifi_hal_fn global_func_table_;
-    // Opaque handle to be used for all global operations.
-    wifi_handle global_handle_;
-    // Map of interface name to handle that is to be used for all interface
-    // specific operations.
-    std::map<std::string, wifi_interface_handle> iface_name_to_handle_;
-    // Flag to indicate if we have initiated the cleanup of legacy HAL.
-    std::atomic<bool> awaiting_event_loop_termination_;
-    std::condition_variable_any stop_wait_cv_;
-    // Flag to indicate if the legacy HAL has been started.
-    bool is_started_;
-    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
-};
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.3/default/wifi_legacy_hal_stubs.cpp b/wifi/1.3/default/wifi_legacy_hal_stubs.cpp
deleted file mode 100644
index dedd2d4..0000000
--- a/wifi/1.3/default/wifi_legacy_hal_stubs.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "wifi_legacy_hal_stubs.h"
-
-// TODO: Remove these stubs from HalTool in libwifi-system.
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace legacy_hal {
-template <typename>
-struct stubFunction;
-
-template <typename R, typename... Args>
-struct stubFunction<R (*)(Args...)> {
-    static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
-};
-template <typename... Args>
-struct stubFunction<void (*)(Args...)> {
-    static constexpr void invoke(Args...) {}
-};
-
-template <typename T>
-void populateStubFor(T* val) {
-    *val = &stubFunction<T>::invoke;
-}
-
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
-    if (hal_fn == nullptr) {
-        return false;
-    }
-    populateStubFor(&hal_fn->wifi_initialize);
-    populateStubFor(&hal_fn->wifi_wait_for_driver_ready);
-    populateStubFor(&hal_fn->wifi_cleanup);
-    populateStubFor(&hal_fn->wifi_event_loop);
-    populateStubFor(&hal_fn->wifi_get_error_info);
-    populateStubFor(&hal_fn->wifi_get_supported_feature_set);
-    populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
-    populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
-    populateStubFor(&hal_fn->wifi_get_supported_channels);
-    populateStubFor(&hal_fn->wifi_is_epr_supported);
-    populateStubFor(&hal_fn->wifi_get_ifaces);
-    populateStubFor(&hal_fn->wifi_get_iface_name);
-    populateStubFor(&hal_fn->wifi_set_iface_event_handler);
-    populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
-    populateStubFor(&hal_fn->wifi_start_gscan);
-    populateStubFor(&hal_fn->wifi_stop_gscan);
-    populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
-    populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
-    populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
-    populateStubFor(&hal_fn->wifi_set_significant_change_handler);
-    populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
-    populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
-    populateStubFor(&hal_fn->wifi_set_link_stats);
-    populateStubFor(&hal_fn->wifi_get_link_stats);
-    populateStubFor(&hal_fn->wifi_clear_link_stats);
-    populateStubFor(&hal_fn->wifi_get_valid_channels);
-    populateStubFor(&hal_fn->wifi_rtt_range_request);
-    populateStubFor(&hal_fn->wifi_rtt_range_cancel);
-    populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
-    populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
-    populateStubFor(&hal_fn->wifi_enable_responder);
-    populateStubFor(&hal_fn->wifi_disable_responder);
-    populateStubFor(&hal_fn->wifi_set_nodfs_flag);
-    populateStubFor(&hal_fn->wifi_start_logging);
-    populateStubFor(&hal_fn->wifi_set_epno_list);
-    populateStubFor(&hal_fn->wifi_reset_epno_list);
-    populateStubFor(&hal_fn->wifi_set_country_code);
-    populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
-    populateStubFor(&hal_fn->wifi_set_log_handler);
-    populateStubFor(&hal_fn->wifi_reset_log_handler);
-    populateStubFor(&hal_fn->wifi_set_alert_handler);
-    populateStubFor(&hal_fn->wifi_reset_alert_handler);
-    populateStubFor(&hal_fn->wifi_get_firmware_version);
-    populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
-    populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
-    populateStubFor(&hal_fn->wifi_get_ring_data);
-    populateStubFor(&hal_fn->wifi_enable_tdls);
-    populateStubFor(&hal_fn->wifi_disable_tdls);
-    populateStubFor(&hal_fn->wifi_get_tdls_status);
-    populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
-    populateStubFor(&hal_fn->wifi_get_driver_version);
-    populateStubFor(&hal_fn->wifi_set_passpoint_list);
-    populateStubFor(&hal_fn->wifi_reset_passpoint_list);
-    populateStubFor(&hal_fn->wifi_set_lci);
-    populateStubFor(&hal_fn->wifi_set_lcr);
-    populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
-    populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
-    populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
-    populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
-    populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
-    populateStubFor(&hal_fn->wifi_configure_nd_offload);
-    populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
-    populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
-    populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
-    populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
-    populateStubFor(&hal_fn->wifi_nan_enable_request);
-    populateStubFor(&hal_fn->wifi_nan_disable_request);
-    populateStubFor(&hal_fn->wifi_nan_publish_request);
-    populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
-    populateStubFor(&hal_fn->wifi_nan_subscribe_request);
-    populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
-    populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
-    populateStubFor(&hal_fn->wifi_nan_stats_request);
-    populateStubFor(&hal_fn->wifi_nan_config_request);
-    populateStubFor(&hal_fn->wifi_nan_tca_request);
-    populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
-    populateStubFor(&hal_fn->wifi_nan_register_handler);
-    populateStubFor(&hal_fn->wifi_nan_get_version);
-    populateStubFor(&hal_fn->wifi_nan_get_capabilities);
-    populateStubFor(&hal_fn->wifi_nan_data_interface_create);
-    populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
-    populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
-    populateStubFor(&hal_fn->wifi_nan_data_indication_response);
-    populateStubFor(&hal_fn->wifi_nan_data_end);
-    populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
-    populateStubFor(&hal_fn->wifi_set_packet_filter);
-    populateStubFor(&hal_fn->wifi_read_packet_filter);
-    populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
-    populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
-    populateStubFor(&hal_fn->wifi_configure_roaming);
-    populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
-    populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
-    populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
-    populateStubFor(&hal_fn->wifi_set_latency_mode);
-    return true;
-}
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_legacy_hal_stubs.h b/wifi/1.3/default/wifi_legacy_hal_stubs.h
deleted file mode 100644
index 64854e0..0000000
--- a/wifi/1.3/default/wifi_legacy_hal_stubs.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_LEGACY_HAL_STUBS_H_
-#define WIFI_LEGACY_HAL_STUBS_H_
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace legacy_hal {
-#include <hardware_legacy/wifi_hal.h>
-
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/1.3/default/wifi_mode_controller.cpp b/wifi/1.3/default/wifi_mode_controller.cpp
deleted file mode 100644
index c392486..0000000
--- a/wifi/1.3/default/wifi_mode_controller.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-
-#include "wifi_mode_controller.h"
-
-using android::hardware::wifi::V1_0::IfaceType;
-using android::wifi_hal::DriverTool;
-
-namespace {
-int convertIfaceTypeToFirmwareMode(IfaceType type) {
-    int mode;
-    switch (type) {
-        case IfaceType::AP:
-            mode = DriverTool::kFirmwareModeAp;
-            break;
-        case IfaceType::P2P:
-            mode = DriverTool::kFirmwareModeP2p;
-            break;
-        case IfaceType::NAN:
-            // NAN is exposed in STA mode currently.
-            mode = DriverTool::kFirmwareModeSta;
-            break;
-        case IfaceType::STA:
-            mode = DriverTool::kFirmwareModeSta;
-            break;
-    }
-    return mode;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace mode_controller {
-
-WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
-
-bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
-    return driver_tool_->IsFirmwareModeChangeNeeded(
-        convertIfaceTypeToFirmwareMode(type));
-}
-
-bool WifiModeController::initialize() {
-    if (!driver_tool_->LoadDriver()) {
-        LOG(ERROR) << "Failed to load WiFi driver";
-        return false;
-    }
-    return true;
-}
-
-bool WifiModeController::changeFirmwareMode(IfaceType type) {
-    if (!driver_tool_->ChangeFirmwareMode(
-            convertIfaceTypeToFirmwareMode(type))) {
-        LOG(ERROR) << "Failed to change firmware mode";
-        return false;
-    }
-    return true;
-}
-
-bool WifiModeController::deinitialize() {
-    if (!driver_tool_->UnloadDriver()) {
-        LOG(ERROR) << "Failed to unload WiFi driver";
-        return false;
-    }
-    return true;
-}
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_mode_controller.h b/wifi/1.3/default/wifi_mode_controller.h
deleted file mode 100644
index ace5a52..0000000
--- a/wifi/1.3/default/wifi_mode_controller.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_MODE_CONTROLLER_H_
-#define WIFI_MODE_CONTROLLER_H_
-
-#include <wifi_hal/driver_tool.h>
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-namespace mode_controller {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * Class that encapsulates all firmware mode configuration.
- * This class will perform the necessary firmware reloads to put the chip in the
- * required state (essentially a wrapper over DriverTool).
- */
-class WifiModeController {
-   public:
-    WifiModeController();
-    virtual ~WifiModeController() = default;
-
-    // Checks if a firmware mode change is necessary to support the specified
-    // iface type operations.
-    virtual bool isFirmwareModeChangeNeeded(IfaceType type);
-    virtual bool initialize();
-    // Change the firmware mode to support the specified iface type operations.
-    virtual bool changeFirmwareMode(IfaceType type);
-    // Unload the driver. This should be invoked whenever |IWifi.stop()| is
-    // invoked.
-    virtual bool deinitialize();
-
-   private:
-    std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
-};
-
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.3/default/wifi_nan_iface.cpp b/wifi/1.3/default/wifi_nan_iface.cpp
deleted file mode 100644
index ff9f422..0000000
--- a/wifi/1.3/default/wifi_nan_iface.cpp
+++ /dev/null
@@ -1,887 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_nan_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiNanIface::WifiNanIface(
-    const std::string& ifname,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
-    : ifname_(ifname),
-      legacy_hal_(legacy_hal),
-      iface_util_(iface_util),
-      is_valid_(true) {
-    // Register all the callbacks here. these should be valid for the lifetime
-    // of the object. Whenever the mode changes legacy HAL will remove
-    // all of these callbacks.
-    legacy_hal::NanCallbackHandlers callback_handlers;
-    android::wp<WifiNanIface> weak_ptr_this(this);
-
-    // Callback for response.
-    callback_handlers
-        .on_notify_response = [weak_ptr_this](
-                                  legacy_hal::transaction_id id,
-                                  const legacy_hal::NanResponseMsg& msg) {
-        const auto shared_ptr_this = weak_ptr_this.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        WifiNanStatus wifiNanStatus;
-        if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(
-                msg, &wifiNanStatus)) {
-            LOG(ERROR) << "Failed to convert nan response header";
-            return;
-        }
-
-        switch (msg.response_type) {
-            case legacy_hal::NAN_RESPONSE_ENABLED: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->notifyEnableResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_DISABLED: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->notifyDisableResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_PUBLISH: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyStartPublishResponse(
-                                 id, wifiNanStatus,
-                                 msg.body.publish_response.publish_id)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->notifyStopPublishResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyTransmitFollowupResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyStartSubscribeResponse(
-                                 id, wifiNanStatus,
-                                 msg.body.subscribe_response.subscribe_id)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyStopSubscribeResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_CONFIG: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback->notifyConfigResponse(id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_GET_CAPABILITIES: {
-                NanCapabilities hidl_struct;
-                if (!hidl_struct_util::
-                        convertLegacyNanCapabilitiesResponseToHidl(
-                            msg.body.nan_capabilities, &hidl_struct)) {
-                    LOG(ERROR) << "Failed to convert nan capabilities response";
-                    return;
-                }
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyCapabilitiesResponse(id, wifiNanStatus,
-                                                          hidl_struct)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_DP_INTERFACE_CREATE: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyCreateDataInterfaceResponse(id,
-                                                                 wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_DP_INTERFACE_DELETE: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyDeleteDataInterfaceResponse(id,
-                                                                 wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyInitiateDataPathResponse(
-                                 id, wifiNanStatus,
-                                 msg.body.data_request_response.ndp_instance_id)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyRespondToDataPathIndicationResponse(
-                                 id, wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_DP_END: {
-                for (const auto& callback :
-                     shared_ptr_this->getEventCallbacks()) {
-                    if (!callback
-                             ->notifyTerminateDataPathResponse(id,
-                                                               wifiNanStatus)
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-                break;
-            }
-            case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
-            /* fall through */
-            case legacy_hal::NAN_RESPONSE_TCA:
-            /* fall through */
-            case legacy_hal::NAN_RESPONSE_STATS:
-            /* fall through */
-            case legacy_hal::NAN_RESPONSE_ERROR:
-            /* fall through */
-            default:
-                LOG(ERROR) << "Unknown or unhandled response type: "
-                           << msg.response_type;
-                return;
-        }
-    };
-
-    callback_handlers.on_event_disc_eng_event =
-        [weak_ptr_this](const legacy_hal::NanDiscEngEventInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            NanClusterEventInd hidl_struct;
-            // event types defined identically - hence can be cast
-            hidl_struct.eventType = (NanClusterEventType)msg.event_type;
-            hidl_struct.addr = msg.data.mac_addr.addr;
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventClusterEvent(hidl_struct).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_disabled =
-        [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            WifiNanStatus status;
-            hidl_struct_util::convertToWifiNanStatus(
-                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventDisabled(status).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_publish_terminated =
-        [weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            WifiNanStatus status;
-            hidl_struct_util::convertToWifiNanStatus(
-                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventPublishTerminated(msg.publish_id, status)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_subscribe_terminated =
-        [weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            WifiNanStatus status;
-            hidl_struct_util::convertToWifiNanStatus(
-                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback
-                         ->eventSubscribeTerminated(msg.subscribe_id, status)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_match =
-        [weak_ptr_this](const legacy_hal::NanMatchInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            NanMatchInd hidl_struct;
-            if (!hidl_struct_util::convertLegacyNanMatchIndToHidl(
-                    msg, &hidl_struct)) {
-                LOG(ERROR) << "Failed to convert nan capabilities response";
-                return;
-            }
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventMatch(hidl_struct).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_match_expired =
-        [weak_ptr_this](const legacy_hal::NanMatchExpiredInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback
-                         ->eventMatchExpired(msg.publish_subscribe_id,
-                                             msg.requestor_instance_id)
-                         .isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_followup =
-        [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            NanFollowupReceivedInd hidl_struct;
-            if (!hidl_struct_util::convertLegacyNanFollowupIndToHidl(
-                    msg, &hidl_struct)) {
-                LOG(ERROR) << "Failed to convert nan capabilities response";
-                return;
-            }
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventFollowupReceived(hidl_struct).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_transmit_follow_up =
-        [weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            WifiNanStatus status;
-            hidl_struct_util::convertToWifiNanStatus(
-                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_data_path_request =
-        [weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            NanDataPathRequestInd hidl_struct;
-            if (!hidl_struct_util::convertLegacyNanDataPathRequestIndToHidl(
-                    msg, &hidl_struct)) {
-                LOG(ERROR) << "Failed to convert nan capabilities response";
-                return;
-            }
-
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventDataPathRequest(hidl_struct).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_data_path_confirm =
-        [weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            V1_2::NanDataPathConfirmInd hidl_struct;
-            if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(
-                    msg, &hidl_struct)) {
-                LOG(ERROR) << "Failed to convert nan capabilities response";
-                return;
-            }
-
-            for (const auto& callback :
-                 shared_ptr_this->getEventCallbacks_1_2()) {
-                if (!callback->eventDataPathConfirm_1_2(hidl_struct).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-
-    callback_handlers.on_event_data_path_end =
-        [weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                for (int i = 0; i < msg.num_ndp_instances; ++i) {
-                    if (!callback
-                             ->eventDataPathTerminated(msg.ndp_instance_id[i])
-                             .isOk()) {
-                        LOG(ERROR) << "Failed to invoke the callback";
-                    }
-                }
-            }
-        };
-
-    callback_handlers.on_event_beacon_sdf_payload =
-        [weak_ptr_this](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
-            LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
-        };
-
-    callback_handlers.on_event_range_request =
-        [weak_ptr_this](const legacy_hal::NanRangeRequestInd& /* msg */) {
-            LOG(ERROR) << "on_event_range_request - should not be called";
-        };
-
-    callback_handlers.on_event_range_report =
-        [weak_ptr_this](const legacy_hal::NanRangeReportInd& /* msg */) {
-            LOG(ERROR) << "on_event_range_report - should not be called";
-        };
-
-    callback_handlers
-        .on_event_schedule_update = [weak_ptr_this](
-                                        const legacy_hal::
-                                            NanDataPathScheduleUpdateInd& msg) {
-        const auto shared_ptr_this = weak_ptr_this.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        V1_2::NanDataPathScheduleUpdateInd hidl_struct;
-        if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
-                msg, &hidl_struct)) {
-            LOG(ERROR) << "Failed to convert nan capabilities response";
-            return;
-        }
-
-        for (const auto& callback : shared_ptr_this->getEventCallbacks_1_2()) {
-            if (!callback->eventDataPathScheduleUpdate(hidl_struct).isOk()) {
-                LOG(ERROR) << "Failed to invoke the callback";
-            }
-        }
-    };
-
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_,
-                                                        callback_handlers);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
-        invalidate();
-    }
-
-    // Register for iface state toggle events.
-    iface_util::IfaceEventHandlers event_handlers = {};
-    event_handlers.on_state_toggle_off_on =
-        [weak_ptr_this](const std::string& /* iface_name */) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            // Tell framework that NAN has been disabled.
-            WifiNanStatus status = {
-                NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventDisabled(status).isOk()) {
-                    LOG(ERROR) << "Failed to invoke the callback";
-                }
-            }
-        };
-    iface_util_.lock()->registerIfaceEventHandlers(ifname_, event_handlers);
-}
-
-void WifiNanIface::invalidate() {
-    // send commands to HAL to actually disable and destroy interfaces
-    legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
-    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");
-    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1");
-    iface_util_.lock()->unregisterIfaceEventHandlers(ifname_);
-    legacy_hal_.reset();
-    event_cb_handler_.invalidate();
-    event_cb_handler_1_2_.invalidate();
-    is_valid_ = false;
-}
-
-bool WifiNanIface::isValid() { return is_valid_; }
-
-std::string WifiNanIface::getName() { return ifname_; }
-
-std::set<sp<V1_0::IWifiNanIfaceEventCallback>>
-WifiNanIface::getEventCallbacks() {
-    return event_cb_handler_.getCallbacks();
-}
-
-std::set<sp<V1_2::IWifiNanIfaceEventCallback>>
-WifiNanIface::getEventCallbacks_1_2() {
-    return event_cb_handler_1_2_.getCallbacks();
-}
-
-Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiNanIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiNanIface::registerEventCallback(
-    const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::registerEventCallbackInternal,
-                           hidl_status_cb, callback);
-}
-
-Return<void> WifiNanIface::getCapabilitiesRequest(
-    uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::getCapabilitiesRequestInternal,
-                           hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiNanIface::enableRequest(uint16_t cmd_id,
-                                         const NanEnableRequest& msg,
-                                         enableRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequestInternal, hidl_status_cb,
-                           cmd_id, msg);
-}
-
-Return<void> WifiNanIface::configRequest(uint16_t cmd_id,
-                                         const NanConfigRequest& msg,
-                                         configRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequestInternal, hidl_status_cb,
-                           cmd_id, msg);
-}
-
-Return<void> WifiNanIface::disableRequest(uint16_t cmd_id,
-                                          disableRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::disableRequestInternal,
-                           hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiNanIface::startPublishRequest(
-    uint16_t cmd_id, const NanPublishRequest& msg,
-    startPublishRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::startPublishRequestInternal,
-                           hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::stopPublishRequest(
-    uint16_t cmd_id, uint8_t sessionId, stopPublishRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::stopPublishRequestInternal,
-                           hidl_status_cb, cmd_id, sessionId);
-}
-
-Return<void> WifiNanIface::startSubscribeRequest(
-    uint16_t cmd_id, const NanSubscribeRequest& msg,
-    startSubscribeRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::startSubscribeRequestInternal,
-                           hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::stopSubscribeRequest(
-    uint16_t cmd_id, uint8_t sessionId,
-    stopSubscribeRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::stopSubscribeRequestInternal,
-                           hidl_status_cb, cmd_id, sessionId);
-}
-
-Return<void> WifiNanIface::transmitFollowupRequest(
-    uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
-    transmitFollowupRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::transmitFollowupRequestInternal,
-                           hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::createDataInterfaceRequest(
-    uint16_t cmd_id, const hidl_string& iface_name,
-    createDataInterfaceRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::createDataInterfaceRequestInternal,
-                           hidl_status_cb, cmd_id, iface_name);
-}
-
-Return<void> WifiNanIface::deleteDataInterfaceRequest(
-    uint16_t cmd_id, const hidl_string& iface_name,
-    deleteDataInterfaceRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::deleteDataInterfaceRequestInternal,
-                           hidl_status_cb, cmd_id, iface_name);
-}
-
-Return<void> WifiNanIface::initiateDataPathRequest(
-    uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
-    initiateDataPathRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::initiateDataPathRequestInternal,
-                           hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::respondToDataPathIndicationRequest(
-    uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
-    respondToDataPathIndicationRequest_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-        &WifiNanIface::respondToDataPathIndicationRequestInternal,
-        hidl_status_cb, cmd_id, msg);
-}
-
-Return<void> WifiNanIface::terminateDataPathRequest(
-    uint16_t cmd_id, uint32_t ndpInstanceId,
-    terminateDataPathRequest_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::terminateDataPathRequestInternal,
-                           hidl_status_cb, cmd_id, ndpInstanceId);
-}
-
-Return<void> WifiNanIface::registerEventCallback_1_2(
-    const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
-    registerEventCallback_1_2_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::registerEventCallback_1_2Internal,
-                           hidl_status_cb, callback);
-}
-
-Return<void> WifiNanIface::enableRequest_1_2(
-    uint16_t cmd_id, const NanEnableRequest& msg1,
-    const V1_2::NanConfigRequestSupplemental& msg2,
-    enableRequest_1_2_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::enableRequest_1_2Internal,
-                           hidl_status_cb, cmd_id, msg1, msg2);
-}
-
-Return<void> WifiNanIface::configRequest_1_2(
-    uint16_t cmd_id, const NanConfigRequest& msg1,
-    const V1_2::NanConfigRequestSupplemental& msg2,
-    configRequest_1_2_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiNanIface::configRequest_1_2Internal,
-                           hidl_status_cb, cmd_id, msg1, msg2);
-}
-
-std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiNanIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
-}
-
-WifiStatus WifiNanIface::registerEventCallbackInternal(
-    const sp<V1_0::IWifiNanIfaceEventCallback>& callback) {
-    if (!event_cb_handler_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::enableRequestInternal(
-    uint16_t /* cmd_id */, const NanEnableRequest& /* msg */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::configRequestInternal(
-    uint16_t /* cmd_id */, const NanConfigRequest& /* msg */) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-}
-
-WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::startPublishRequestInternal(
-    uint16_t cmd_id, const NanPublishRequest& msg) {
-    legacy_hal::NanPublishRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(msg,
-                                                                &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::stopPublishRequestInternal(uint16_t cmd_id,
-                                                    uint8_t sessionId) {
-    legacy_hal::NanPublishCancelRequest legacy_msg;
-    legacy_msg.publish_id = sessionId;
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id,
-                                                    legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::startSubscribeRequestInternal(
-    uint16_t cmd_id, const NanSubscribeRequest& msg) {
-    legacy_hal::NanSubscribeRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(
-            msg, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::stopSubscribeRequestInternal(uint16_t cmd_id,
-                                                      uint8_t sessionId) {
-    legacy_hal::NanSubscribeCancelRequest legacy_msg;
-    legacy_msg.subscribe_id = sessionId;
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id,
-                                                      legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::transmitFollowupRequestInternal(
-    uint16_t cmd_id, const NanTransmitFollowupRequest& msg) {
-    legacy_hal::NanTransmitFollowupRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanTransmitFollowupRequestToLegacy(
-            msg, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id,
-                                                       legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::createDataInterfaceRequestInternal(
-    uint16_t cmd_id, const std::string& iface_name) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::deleteDataInterfaceRequestInternal(
-    uint16_t cmd_id, const std::string& iface_name) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::initiateDataPathRequestInternal(
-    uint16_t cmd_id, const NanInitiateDataPathRequest& msg) {
-    legacy_hal::NanDataPathInitiatorRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequestToLegacy(
-            msg, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id,
-                                                    legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
-    uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg) {
-    legacy_hal::NanDataPathIndicationResponse legacy_msg;
-    if (!hidl_struct_util::convertHidlNanDataPathIndicationResponseToLegacy(
-            msg, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id,
-                                                      legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::terminateDataPathRequestInternal(
-    uint16_t cmd_id, uint32_t ndpInstanceId) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
-    const sp<V1_2::IWifiNanIfaceEventCallback>& callback) {
-    sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
-    if (!event_cb_handler_.addCallback(callback_1_0)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    if (!event_cb_handler_1_2_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::enableRequest_1_2Internal(
-    uint16_t cmd_id, const NanEnableRequest& msg1,
-    const V1_2::NanConfigRequestSupplemental& msg2) {
-    legacy_hal::NanEnableRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanEnableRequest_1_2ToLegacy(
-            msg1, msg2, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::configRequest_1_2Internal(
-    uint16_t cmd_id, const NanConfigRequest& msg1,
-    const V1_2::NanConfigRequestSupplemental& msg2) {
-    legacy_hal::NanConfigRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanConfigRequest_1_2ToLegacy(
-            msg1, msg2, &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_nan_iface.h b/wifi/1.3/default/wifi_nan_iface.h
deleted file mode 100644
index 737be93..0000000
--- a/wifi/1.3/default/wifi_nan_iface.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_NAN_IFACE_H_
-#define WIFI_NAN_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
-#include <android/hardware/wifi/1.2/IWifiNanIface.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a NAN Iface instance.
- */
-class WifiNanIface : public V1_2::IWifiNanIface {
-   public:
-    WifiNanIface(const std::string& ifname,
-                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::string getName();
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-    Return<void> registerEventCallback(
-        const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
-        registerEventCallback_cb hidl_status_cb) override;
-    Return<void> getCapabilitiesRequest(
-        uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) override;
-    Return<void> enableRequest(uint16_t cmd_id, const NanEnableRequest& msg,
-                               enableRequest_cb hidl_status_cb) override;
-    Return<void> configRequest(uint16_t cmd_id, const NanConfigRequest& msg,
-                               configRequest_cb hidl_status_cb) override;
-    Return<void> disableRequest(uint16_t cmd_id,
-                                disableRequest_cb hidl_status_cb) override;
-    Return<void> startPublishRequest(
-        uint16_t cmd_id, const NanPublishRequest& msg,
-        startPublishRequest_cb hidl_status_cb) override;
-    Return<void> stopPublishRequest(
-        uint16_t cmd_id, uint8_t sessionId,
-        stopPublishRequest_cb hidl_status_cb) override;
-    Return<void> startSubscribeRequest(
-        uint16_t cmd_id, const NanSubscribeRequest& msg,
-        startSubscribeRequest_cb hidl_status_cb) override;
-    Return<void> stopSubscribeRequest(
-        uint16_t cmd_id, uint8_t sessionId,
-        stopSubscribeRequest_cb hidl_status_cb) override;
-    Return<void> transmitFollowupRequest(
-        uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
-        transmitFollowupRequest_cb hidl_status_cb) override;
-    Return<void> createDataInterfaceRequest(
-        uint16_t cmd_id, const hidl_string& iface_name,
-        createDataInterfaceRequest_cb hidl_status_cb) override;
-    Return<void> deleteDataInterfaceRequest(
-        uint16_t cmd_id, const hidl_string& iface_name,
-        deleteDataInterfaceRequest_cb hidl_status_cb) override;
-    Return<void> initiateDataPathRequest(
-        uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
-        initiateDataPathRequest_cb hidl_status_cb) override;
-    Return<void> respondToDataPathIndicationRequest(
-        uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
-        respondToDataPathIndicationRequest_cb hidl_status_cb) override;
-    Return<void> terminateDataPathRequest(
-        uint16_t cmd_id, uint32_t ndpInstanceId,
-        terminateDataPathRequest_cb hidl_status_cb) override;
-
-    Return<void> registerEventCallback_1_2(
-        const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
-        registerEventCallback_1_2_cb hidl_status_cb) override;
-    Return<void> enableRequest_1_2(
-        uint16_t cmd_id, const NanEnableRequest& msg1,
-        const V1_2::NanConfigRequestSupplemental& msg2,
-        enableRequest_1_2_cb hidl_status_cb) override;
-    Return<void> configRequest_1_2(
-        uint16_t cmd_id, const NanConfigRequest& msg1,
-        const V1_2::NanConfigRequestSupplemental& msg2,
-        configRequest_1_2_cb hidl_status_cb) override;
-
-   private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-    WifiStatus registerEventCallbackInternal(
-        const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
-    WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
-    WifiStatus enableRequestInternal(uint16_t cmd_id,
-                                     const NanEnableRequest& msg);
-    WifiStatus configRequestInternal(uint16_t cmd_id,
-                                     const NanConfigRequest& msg);
-    WifiStatus disableRequestInternal(uint16_t cmd_id);
-    WifiStatus startPublishRequestInternal(uint16_t cmd_id,
-                                           const NanPublishRequest& msg);
-    WifiStatus stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId);
-    WifiStatus startSubscribeRequestInternal(uint16_t cmd_id,
-                                             const NanSubscribeRequest& msg);
-    WifiStatus stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId);
-    WifiStatus transmitFollowupRequestInternal(
-        uint16_t cmd_id, const NanTransmitFollowupRequest& msg);
-    WifiStatus createDataInterfaceRequestInternal(
-        uint16_t cmd_id, const std::string& iface_name);
-    WifiStatus deleteDataInterfaceRequestInternal(
-        uint16_t cmd_id, const std::string& iface_name);
-    WifiStatus initiateDataPathRequestInternal(
-        uint16_t cmd_id, const NanInitiateDataPathRequest& msg);
-    WifiStatus respondToDataPathIndicationRequestInternal(
-        uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg);
-    WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id,
-                                                uint32_t ndpInstanceId);
-
-    WifiStatus registerEventCallback_1_2Internal(
-        const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
-    WifiStatus enableRequest_1_2Internal(
-        uint16_t cmd_id, const NanEnableRequest& msg1,
-        const V1_2::NanConfigRequestSupplemental& msg2);
-    WifiStatus configRequest_1_2Internal(
-        uint16_t cmd_id, const NanConfigRequest& msg,
-        const V1_2::NanConfigRequestSupplemental& msg2);
-
-    // all 1_0 and descendant callbacks
-    std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
-    // all 1_2 and descendant callbacks
-    std::set<sp<V1_2::IWifiNanIfaceEventCallback>> getEventCallbacks_1_2();
-
-    std::string ifname_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
-    bool is_valid_;
-    hidl_callback_util::HidlCallbackHandler<V1_0::IWifiNanIfaceEventCallback>
-        event_cb_handler_;
-    hidl_callback_util::HidlCallbackHandler<V1_2::IWifiNanIfaceEventCallback>
-        event_cb_handler_1_2_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_NAN_IFACE_H_
diff --git a/wifi/1.3/default/wifi_p2p_iface.cpp b/wifi/1.3/default/wifi_p2p_iface.cpp
deleted file mode 100644
index b5d5886..0000000
--- a/wifi/1.3/default/wifi_p2p_iface.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_return_util.h"
-#include "wifi_p2p_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiP2pIface::WifiP2pIface(
-    const std::string& ifname,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
-
-void WifiP2pIface::invalidate() {
-    legacy_hal_.reset();
-    is_valid_ = false;
-}
-
-bool WifiP2pIface::isValid() { return is_valid_; }
-
-std::string WifiP2pIface::getName() { return ifname_; }
-
-Return<void> WifiP2pIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiP2pIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiP2pIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiP2pIface::getTypeInternal, hidl_status_cb);
-}
-
-std::pair<WifiStatus, std::string> WifiP2pIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::P2P};
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_p2p_iface.h b/wifi/1.3/default/wifi_p2p_iface.h
deleted file mode 100644
index 8a7207a..0000000
--- a/wifi/1.3/default/wifi_p2p_iface.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_P2P_IFACE_H_
-#define WIFI_P2P_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a P2P Iface instance.
- */
-class WifiP2pIface : public V1_0::IWifiP2pIface {
-   public:
-    WifiP2pIface(const std::string& ifname,
-                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::string getName();
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-
-   private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-
-    std::string ifname_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    bool is_valid_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_P2P_IFACE_H_
diff --git a/wifi/1.3/default/wifi_rtt_controller.cpp b/wifi/1.3/default/wifi_rtt_controller.cpp
deleted file mode 100644
index 3dcbee6..0000000
--- a/wifi/1.3/default/wifi_rtt_controller.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_rtt_controller.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiRttController::WifiRttController(
-    const std::string& iface_name, const sp<IWifiIface>& bound_iface,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : ifname_(iface_name),
-      bound_iface_(bound_iface),
-      legacy_hal_(legacy_hal),
-      is_valid_(true) {}
-
-void WifiRttController::invalidate() {
-    legacy_hal_.reset();
-    event_callbacks_.clear();
-    is_valid_ = false;
-}
-
-bool WifiRttController::isValid() { return is_valid_; }
-
-std::vector<sp<IWifiRttControllerEventCallback>>
-WifiRttController::getEventCallbacks() {
-    return event_callbacks_;
-}
-
-std::string WifiRttController::getIfaceName() { return ifname_; }
-
-Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::getBoundIfaceInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::registerEventCallback(
-    const sp<IWifiRttControllerEventCallback>& callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this,
-                           WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::registerEventCallbackInternal,
-                           hidl_status_cb, callback);
-}
-
-Return<void> WifiRttController::rangeRequest(
-    uint32_t cmd_id, const hidl_vec<RttConfig>& rtt_configs,
-    rangeRequest_cb hidl_status_cb) {
-    return validateAndCall(this,
-                           WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                           &WifiRttController::rangeRequestInternal,
-                           hidl_status_cb, cmd_id, rtt_configs);
-}
-
-Return<void> WifiRttController::rangeCancel(
-    uint32_t cmd_id, const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
-    rangeCancel_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::rangeCancelInternal, hidl_status_cb, cmd_id, addrs);
-}
-
-Return<void> WifiRttController::getCapabilities(
-    getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::getCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::setLci(uint32_t cmd_id,
-                                       const RttLciInformation& lci,
-                                       setLci_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::setLciInternal, hidl_status_cb, cmd_id, lci);
-}
-
-Return<void> WifiRttController::setLcr(uint32_t cmd_id,
-                                       const RttLcrInformation& lcr,
-                                       setLcr_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::setLcrInternal, hidl_status_cb, cmd_id, lcr);
-}
-
-Return<void> WifiRttController::getResponderInfo(
-    getResponderInfo_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::getResponderInfoInternal, hidl_status_cb);
-}
-
-Return<void> WifiRttController::enableResponder(
-    uint32_t cmd_id, const WifiChannelInfo& channel_hint,
-    uint32_t max_duration_seconds, const RttResponder& info,
-    enableResponder_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::enableResponderInternal, hidl_status_cb, cmd_id,
-        channel_hint, max_duration_seconds, info);
-}
-
-Return<void> WifiRttController::disableResponder(
-    uint32_t cmd_id, disableResponder_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-        &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id);
-}
-
-std::pair<WifiStatus, sp<IWifiIface>>
-WifiRttController::getBoundIfaceInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
-}
-
-WifiStatus WifiRttController::registerEventCallbackInternal(
-    const sp<IWifiRttControllerEventCallback>& callback) {
-    // TODO(b/31632518): remove the callback when the client is destroyed
-    event_callbacks_.emplace_back(callback);
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiRttController::rangeRequestInternal(
-    uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
-    std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
-    if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(
-            rtt_configs, &legacy_configs)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    android::wp<WifiRttController> weak_ptr_this(this);
-    const auto& on_results_callback =
-        [weak_ptr_this](
-            legacy_hal::wifi_request_id id,
-            const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            std::vector<RttResult> hidl_results;
-            if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(
-                    results, &hidl_results)) {
-                LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                callback->onResults(id, hidl_results);
-            }
-        };
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->startRttRangeRequest(
-            ifname_, cmd_id, legacy_configs, on_results_callback);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::rangeCancelInternal(
-    uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
-    std::vector<std::array<uint8_t, 6>> legacy_addrs;
-    for (const auto& addr : addrs) {
-        legacy_addrs.push_back(addr);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id,
-                                                  legacy_addrs);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, RttCapabilities>
-WifiRttController::getCapabilitiesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::wifi_rtt_capabilities legacy_caps;
-    std::tie(legacy_status, legacy_caps) =
-        legacy_hal_.lock()->getRttCapabilities(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    RttCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps,
-                                                              &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id,
-                                             const RttLciInformation& lci) {
-    legacy_hal::wifi_lci_information legacy_lci;
-    if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci,
-                                                                &legacy_lci)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id,
-                                             const RttLcrInformation& lcr) {
-    legacy_hal::wifi_lcr_information legacy_lcr;
-    if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr,
-                                                                &legacy_lcr)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, RttResponder>
-WifiRttController::getResponderInfoInternal() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::wifi_rtt_responder legacy_responder;
-    std::tie(legacy_status, legacy_responder) =
-        legacy_hal_.lock()->getRttResponderInfo(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    RttResponder hidl_responder;
-    if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder,
-                                                           &hidl_responder)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
-}
-
-WifiStatus WifiRttController::enableResponderInternal(
-    uint32_t cmd_id, const WifiChannelInfo& channel_hint,
-    uint32_t max_duration_seconds, const RttResponder& info) {
-    legacy_hal::wifi_channel_info legacy_channel_info;
-    if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(
-            channel_hint, &legacy_channel_info)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_rtt_responder legacy_responder;
-    if (!hidl_struct_util::convertHidlRttResponderToLegacy(info,
-                                                           &legacy_responder)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->enableRttResponder(
-            ifname_, cmd_id, legacy_channel_info, max_duration_seconds,
-            legacy_responder);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_rtt_controller.h b/wifi/1.3/default/wifi_rtt_controller.h
deleted file mode 100644
index eedd22a..0000000
--- a/wifi/1.3/default/wifi_rtt_controller.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_RTT_CONTROLLER_H_
-#define WIFI_RTT_CONTROLLER_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiIface.h>
-#include <android/hardware/wifi/1.0/IWifiRttController.h>
-#include <android/hardware/wifi/1.0/IWifiRttControllerEventCallback.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-/**
- * HIDL interface object used to control all RTT operations.
- */
-class WifiRttController : public V1_0::IWifiRttController {
-   public:
-    WifiRttController(
-        const std::string& iface_name, const sp<IWifiIface>& bound_iface,
-        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::vector<sp<IWifiRttControllerEventCallback>> getEventCallbacks();
-    std::string getIfaceName();
-
-    // HIDL methods exposed.
-    Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
-    Return<void> registerEventCallback(
-        const sp<IWifiRttControllerEventCallback>& callback,
-        registerEventCallback_cb hidl_status_cb) override;
-    Return<void> rangeRequest(uint32_t cmd_id,
-                              const hidl_vec<RttConfig>& rtt_configs,
-                              rangeRequest_cb hidl_status_cb) override;
-    Return<void> rangeCancel(uint32_t cmd_id,
-                             const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
-                             rangeCancel_cb hidl_status_cb) override;
-    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-    Return<void> setLci(uint32_t cmd_id, const RttLciInformation& lci,
-                        setLci_cb hidl_status_cb) override;
-    Return<void> setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
-                        setLcr_cb hidl_status_cb) override;
-    Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
-    Return<void> enableResponder(uint32_t cmd_id,
-                                 const WifiChannelInfo& channel_hint,
-                                 uint32_t max_duration_seconds,
-                                 const RttResponder& info,
-                                 enableResponder_cb hidl_status_cb) override;
-    Return<void> disableResponder(uint32_t cmd_id,
-                                  disableResponder_cb hidl_status_cb) override;
-
-   private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, sp<IWifiIface>> getBoundIfaceInternal();
-    WifiStatus registerEventCallbackInternal(
-        const sp<IWifiRttControllerEventCallback>& callback);
-    WifiStatus rangeRequestInternal(uint32_t cmd_id,
-                                    const std::vector<RttConfig>& rtt_configs);
-    WifiStatus rangeCancelInternal(
-        uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs);
-    std::pair<WifiStatus, RttCapabilities> getCapabilitiesInternal();
-    WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
-    WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
-    std::pair<WifiStatus, RttResponder> getResponderInfoInternal();
-    WifiStatus enableResponderInternal(uint32_t cmd_id,
-                                       const WifiChannelInfo& channel_hint,
-                                       uint32_t max_duration_seconds,
-                                       const RttResponder& info);
-    WifiStatus disableResponderInternal(uint32_t cmd_id);
-
-    std::string ifname_;
-    sp<IWifiIface> bound_iface_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::vector<sp<IWifiRttControllerEventCallback>> event_callbacks_;
-    bool is_valid_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiRttController);
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/1.3/default/wifi_sta_iface.cpp b/wifi/1.3/default/wifi_sta_iface.cpp
deleted file mode 100644
index a6539e5..0000000
--- a/wifi/1.3/default/wifi_sta_iface.cpp
+++ /dev/null
@@ -1,647 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_sta_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiStaIface::WifiStaIface(
-    const std::string& ifname,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
-    : ifname_(ifname),
-      legacy_hal_(legacy_hal),
-      iface_util_(iface_util),
-      is_valid_(true) {
-    // Turn on DFS channel usage for STA iface.
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->setDfsFlag(ifname_, true);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR)
-            << "Failed to set DFS flag; DFS channels may be unavailable.";
-    }
-}
-
-void WifiStaIface::invalidate() {
-    legacy_hal_.reset();
-    event_cb_handler_.invalidate();
-    is_valid_ = false;
-}
-
-bool WifiStaIface::isValid() { return is_valid_; }
-
-std::string WifiStaIface::getName() { return ifname_; }
-
-std::set<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
-    return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getNameInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getType(getType_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getTypeInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::registerEventCallback(
-    const sp<IWifiStaIfaceEventCallback>& callback,
-    registerEventCallback_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::registerEventCallbackInternal,
-                           hidl_status_cb, callback);
-}
-
-Return<void> WifiStaIface::getCapabilities(getCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getCapabilitiesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getApfPacketFilterCapabilities(
-    getApfPacketFilterCapabilities_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-        &WifiStaIface::getApfPacketFilterCapabilitiesInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::installApfPacketFilter(
-    uint32_t cmd_id, const hidl_vec<uint8_t>& program,
-    installApfPacketFilter_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::installApfPacketFilterInternal,
-                           hidl_status_cb, cmd_id, program);
-}
-
-Return<void> WifiStaIface::readApfPacketFilterData(
-    readApfPacketFilterData_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::readApfPacketFilterDataInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getBackgroundScanCapabilities(
-    getBackgroundScanCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getBackgroundScanCapabilitiesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getValidFrequenciesForBand(
-    WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getValidFrequenciesForBandInternal,
-                           hidl_status_cb, band);
-}
-
-Return<void> WifiStaIface::startBackgroundScan(
-    uint32_t cmd_id, const StaBackgroundScanParameters& params,
-    startBackgroundScan_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::startBackgroundScanInternal,
-                           hidl_status_cb, cmd_id, params);
-}
-
-Return<void> WifiStaIface::stopBackgroundScan(
-    uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::stopBackgroundScanInternal,
-                           hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::enableLinkLayerStatsCollection(
-    bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-        &WifiStaIface::enableLinkLayerStatsCollectionInternal, hidl_status_cb,
-        debug);
-}
-
-Return<void> WifiStaIface::disableLinkLayerStatsCollection(
-    disableLinkLayerStatsCollection_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-        &WifiStaIface::disableLinkLayerStatsCollectionInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats(
-    getLinkLayerStats_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getLinkLayerStatsInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats_1_3(
-    getLinkLayerStats_1_3_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getLinkLayerStatsInternal_1_3,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::startRssiMonitoring(
-    uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
-    startRssiMonitoring_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::startRssiMonitoringInternal,
-                           hidl_status_cb, cmd_id, max_rssi, min_rssi);
-}
-
-Return<void> WifiStaIface::stopRssiMonitoring(
-    uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::stopRssiMonitoringInternal,
-                           hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::getRoamingCapabilities(
-    getRoamingCapabilities_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getRoamingCapabilitiesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::configureRoaming(
-    const StaRoamingConfig& config, configureRoaming_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::configureRoamingInternal,
-                           hidl_status_cb, config);
-}
-
-Return<void> WifiStaIface::setRoamingState(StaRoamingState state,
-                                           setRoamingState_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setRoamingStateInternal,
-                           hidl_status_cb, state);
-}
-
-Return<void> WifiStaIface::enableNdOffload(bool enable,
-                                           enableNdOffload_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::enableNdOffloadInternal,
-                           hidl_status_cb, enable);
-}
-
-Return<void> WifiStaIface::startSendingKeepAlivePackets(
-    uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
-    uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
-    const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
-    startSendingKeepAlivePackets_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::startSendingKeepAlivePacketsInternal,
-                           hidl_status_cb, cmd_id, ip_packet_data, ether_type,
-                           src_address, dst_address, period_in_ms);
-}
-
-Return<void> WifiStaIface::stopSendingKeepAlivePackets(
-    uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::stopSendingKeepAlivePacketsInternal,
-                           hidl_status_cb, cmd_id);
-}
-
-Return<void> WifiStaIface::setScanningMacOui(
-    const hidl_array<uint8_t, 3>& oui, setScanningMacOui_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setScanningMacOuiInternal,
-                           hidl_status_cb, oui);
-}
-
-Return<void> WifiStaIface::startDebugPacketFateMonitoring(
-    startDebugPacketFateMonitoring_cb hidl_status_cb) {
-    return validateAndCall(
-        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-        &WifiStaIface::startDebugPacketFateMonitoringInternal, hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getDebugTxPacketFates(
-    getDebugTxPacketFates_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getDebugTxPacketFatesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getDebugRxPacketFates(
-    getDebugRxPacketFates_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getDebugRxPacketFatesInternal,
-                           hidl_status_cb);
-}
-
-Return<void> WifiStaIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
-                                         setMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::setMacAddressInternal, hidl_status_cb,
-                           mac);
-}
-
-Return<void> WifiStaIface::getFactoryMacAddress(
-    getFactoryMacAddress_cb hidl_status_cb) {
-    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                           &WifiStaIface::getFactoryMacAddressInternal,
-                           hidl_status_cb);
-}
-
-std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiStaIface::getTypeInternal() {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::STA};
-}
-
-WifiStatus WifiStaIface::registerEventCallbackInternal(
-    const sp<IWifiStaIfaceEventCallback>& callback) {
-    if (!event_cb_handler_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    uint32_t legacy_feature_set;
-    std::tie(legacy_status, legacy_feature_set) =
-        legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), 0};
-    }
-    uint32_t legacy_logger_feature_set;
-    std::tie(legacy_status, legacy_logger_feature_set) =
-        legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        // some devices don't support querying logger feature set
-        legacy_logger_feature_set = 0;
-    }
-    uint32_t hidl_caps;
-    if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
-            legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, StaApfPacketFilterCapabilities>
-WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::PacketFilterCapabilities legacy_caps;
-    std::tie(legacy_status, legacy_caps) =
-        legacy_hal_.lock()->getPacketFilterCapabilities(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    StaApfPacketFilterCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps,
-                                                              &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiStaIface::installApfPacketFilterInternal(
-    uint32_t /* cmd_id */, const std::vector<uint8_t>& program) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->setPacketFilter(ifname_, program);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiStaIface::readApfPacketFilterDataInternal() {
-    const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>>
-        legacy_status_and_data =
-            legacy_hal_.lock()->readApfPacketFilterData(ifname_);
-    return {createWifiStatusFromLegacyError(legacy_status_and_data.first),
-            std::move(legacy_status_and_data.second)};
-}
-
-std::pair<WifiStatus, StaBackgroundScanCapabilities>
-WifiStaIface::getBackgroundScanCapabilitiesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::wifi_gscan_capabilities legacy_caps;
-    std::tie(legacy_status, legacy_caps) =
-        legacy_hal_.lock()->getGscanCapabilities(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    StaBackgroundScanCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps,
-                                                                &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiStaIface::getValidFrequenciesForBandInternal(WifiBand band) {
-    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
-                  "Size mismatch");
-    legacy_hal::wifi_error legacy_status;
-    std::vector<uint32_t> valid_frequencies;
-    std::tie(legacy_status, valid_frequencies) =
-        legacy_hal_.lock()->getValidFrequenciesForBand(
-            ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
-    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
-}
-
-WifiStatus WifiStaIface::startBackgroundScanInternal(
-    uint32_t cmd_id, const StaBackgroundScanParameters& params) {
-    legacy_hal::wifi_scan_cmd_params legacy_params;
-    if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params,
-                                                          &legacy_params)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    android::wp<WifiStaIface> weak_ptr_this(this);
-    const auto& on_failure_callback =
-        [weak_ptr_this](legacy_hal::wifi_request_id id) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onBackgroundScanFailure(id).isOk()) {
-                    LOG(ERROR)
-                        << "Failed to invoke onBackgroundScanFailure callback";
-                }
-            }
-        };
-    const auto& on_results_callback =
-        [weak_ptr_this](
-            legacy_hal::wifi_request_id id,
-            const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            std::vector<StaScanData> hidl_scan_datas;
-            if (!hidl_struct_util::
-                    convertLegacyVectorOfCachedGscanResultsToHidl(
-                        results, &hidl_scan_datas)) {
-                LOG(ERROR) << "Failed to convert scan results to HIDL structs";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onBackgroundScanResults(id, hidl_scan_datas)
-                         .isOk()) {
-                    LOG(ERROR)
-                        << "Failed to invoke onBackgroundScanResults callback";
-                }
-            }
-        };
-    const auto& on_full_result_callback = [weak_ptr_this](
-                                              legacy_hal::wifi_request_id id,
-                                              const legacy_hal::
-                                                  wifi_scan_result* result,
-                                              uint32_t buckets_scanned) {
-        const auto shared_ptr_this = weak_ptr_this.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-            LOG(ERROR) << "Callback invoked on an invalid object";
-            return;
-        }
-        StaScanResult hidl_scan_result;
-        if (!hidl_struct_util::convertLegacyGscanResultToHidl(
-                *result, true, &hidl_scan_result)) {
-            LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
-            return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-            if (!callback
-                     ->onBackgroundFullScanResult(id, buckets_scanned,
-                                                  hidl_scan_result)
-                     .isOk()) {
-                LOG(ERROR)
-                    << "Failed to invoke onBackgroundFullScanResult callback";
-            }
-        }
-    };
-    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startGscan(
-        ifname_, cmd_id, legacy_params, on_failure_callback,
-        on_results_callback, on_full_result_callback);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->disableLinkLayerStats(ifname_);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, V1_0::StaLinkLayerStats>
-WifiStaIface::getLinkLayerStatsInternal() {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
-}
-
-std::pair<WifiStatus, V1_3::StaLinkLayerStats>
-WifiStaIface::getLinkLayerStatsInternal_1_3() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::LinkLayerStats legacy_stats;
-    std::tie(legacy_status, legacy_stats) =
-        legacy_hal_.lock()->getLinkLayerStats(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    V1_3::StaLinkLayerStats hidl_stats;
-    if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
-                                                             &hidl_stats)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
-}
-
-WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id,
-                                                     int32_t max_rssi,
-                                                     int32_t min_rssi) {
-    android::wp<WifiStaIface> weak_ptr_this(this);
-    const auto& on_threshold_breached_callback =
-        [weak_ptr_this](legacy_hal::wifi_request_id id,
-                        std::array<uint8_t, 6> bssid, int8_t rssi) {
-            const auto shared_ptr_this = weak_ptr_this.promote();
-            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-                LOG(ERROR) << "Callback invoked on an invalid object";
-                return;
-            }
-            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onRssiThresholdBreached(id, bssid, rssi)
-                         .isOk()) {
-                    LOG(ERROR)
-                        << "Failed to invoke onRssiThresholdBreached callback";
-                }
-            }
-        };
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->startRssiMonitoring(ifname_, cmd_id, max_rssi,
-                                                min_rssi,
-                                                on_threshold_breached_callback);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, StaRoamingCapabilities>
-WifiStaIface::getRoamingCapabilitiesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    legacy_hal::wifi_roaming_capabilities legacy_caps;
-    std::tie(legacy_status, legacy_caps) =
-        legacy_hal_.lock()->getRoamingCapabilities(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    StaRoamingCapabilities hidl_caps;
-    if (!hidl_struct_util::convertLegacyRoamingCapabilitiesToHidl(legacy_caps,
-                                                                  &hidl_caps)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiStaIface::configureRoamingInternal(
-    const StaRoamingConfig& config) {
-    legacy_hal::wifi_roaming_config legacy_config;
-    if (!hidl_struct_util::convertHidlRoamingConfigToLegacy(config,
-                                                            &legacy_config)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->configureRoaming(ifname_, legacy_config);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->enableFirmwareRoaming(
-            ifname_, hidl_struct_util::convertHidlRoamingStateToLegacy(state));
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->configureNdOffload(ifname_, enable);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
-    uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
-    uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
-    const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->startSendingOffloadedPacket(
-            ifname_, cmd_id, ether_type, ip_packet_data, src_address,
-            dst_address, period_in_ms);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::setScanningMacOuiInternal(
-    const std::array<uint8_t, 3>& oui) {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->setScanningMacOui(ifname_, oui);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->startPktFateMonitoring(ifname_);
-    return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
-WifiStaIface::getDebugTxPacketFatesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<legacy_hal::wifi_tx_report> legacy_fates;
-    std::tie(legacy_status, legacy_fates) =
-        legacy_hal_.lock()->getTxPktFates(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<WifiDebugTxPacketFateReport> hidl_fates;
-    if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(
-            legacy_fates, &hidl_fates)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
-WifiStaIface::getDebugRxPacketFatesInternal() {
-    legacy_hal::wifi_error legacy_status;
-    std::vector<legacy_hal::wifi_rx_report> legacy_fates;
-    std::tie(legacy_status, legacy_fates) =
-        legacy_hal_.lock()->getRxPktFates(ifname_);
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), {}};
-    }
-    std::vector<WifiDebugRxPacketFateReport> hidl_fates;
-    if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(
-            legacy_fates, &hidl_fates)) {
-        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
-}
-
-WifiStatus WifiStaIface::setMacAddressInternal(
-    const std::array<uint8_t, 6>& mac) {
-    bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
-    if (!status) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, std::array<uint8_t, 6>>
-WifiStaIface::getFactoryMacAddressInternal() {
-    std::array<uint8_t, 6> mac =
-        iface_util_.lock()->getFactoryMacAddress(ifname_);
-    return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_sta_iface.h b/wifi/1.3/default/wifi_sta_iface.h
deleted file mode 100644
index 9224939..0000000
--- a/wifi/1.3/default/wifi_sta_iface.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_STA_IFACE_H_
-#define WIFI_STA_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-#include <android/hardware/wifi/1.3/IWifiStaIface.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_iface_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a STA Iface instance.
- */
-class WifiStaIface : public V1_3::IWifiStaIface {
-   public:
-    WifiStaIface(const std::string& ifname,
-                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
-    // Refer to |WifiChip::invalidate()|.
-    void invalidate();
-    bool isValid();
-    std::set<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
-    std::string getName();
-
-    // HIDL methods exposed.
-    Return<void> getName(getName_cb hidl_status_cb) override;
-    Return<void> getType(getType_cb hidl_status_cb) override;
-    Return<void> registerEventCallback(
-        const sp<IWifiStaIfaceEventCallback>& callback,
-        registerEventCallback_cb hidl_status_cb) override;
-    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-    Return<void> getApfPacketFilterCapabilities(
-        getApfPacketFilterCapabilities_cb hidl_status_cb) override;
-    Return<void> installApfPacketFilter(
-        uint32_t cmd_id, const hidl_vec<uint8_t>& program,
-        installApfPacketFilter_cb hidl_status_cb) override;
-    Return<void> readApfPacketFilterData(
-        readApfPacketFilterData_cb hidl_status_cb) override;
-    Return<void> getBackgroundScanCapabilities(
-        getBackgroundScanCapabilities_cb hidl_status_cb) override;
-    Return<void> getValidFrequenciesForBand(
-        WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override;
-    Return<void> startBackgroundScan(
-        uint32_t cmd_id, const StaBackgroundScanParameters& params,
-        startBackgroundScan_cb hidl_status_cb) override;
-    Return<void> stopBackgroundScan(
-        uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) override;
-    Return<void> enableLinkLayerStatsCollection(
-        bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) override;
-    Return<void> disableLinkLayerStatsCollection(
-        disableLinkLayerStatsCollection_cb hidl_status_cb) override;
-    Return<void> getLinkLayerStats(
-        getLinkLayerStats_cb hidl_status_cb) override;
-    Return<void> getLinkLayerStats_1_3(
-        getLinkLayerStats_1_3_cb hidl_status_cb) override;
-    Return<void> startRssiMonitoring(
-        uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
-        startRssiMonitoring_cb hidl_status_cb) override;
-    Return<void> stopRssiMonitoring(
-        uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
-    Return<void> getRoamingCapabilities(
-        getRoamingCapabilities_cb hidl_status_cb) override;
-    Return<void> configureRoaming(const StaRoamingConfig& config,
-                                  configureRoaming_cb hidl_status_cb) override;
-    Return<void> setRoamingState(StaRoamingState state,
-                                 setRoamingState_cb hidl_status_cb) override;
-    Return<void> enableNdOffload(bool enable,
-                                 enableNdOffload_cb hidl_status_cb) override;
-    Return<void> startSendingKeepAlivePackets(
-        uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
-        uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
-        const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
-        startSendingKeepAlivePackets_cb hidl_status_cb) override;
-    Return<void> stopSendingKeepAlivePackets(
-        uint32_t cmd_id,
-        stopSendingKeepAlivePackets_cb hidl_status_cb) override;
-    Return<void> setScanningMacOui(
-        const hidl_array<uint8_t, 3>& oui,
-        setScanningMacOui_cb hidl_status_cb) override;
-    Return<void> startDebugPacketFateMonitoring(
-        startDebugPacketFateMonitoring_cb hidl_status_cb) override;
-    Return<void> getDebugTxPacketFates(
-        getDebugTxPacketFates_cb hidl_status_cb) override;
-    Return<void> getDebugRxPacketFates(
-        getDebugRxPacketFates_cb hidl_status_cb) override;
-    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
-                               setMacAddress_cb hidl_status_cb) override;
-    Return<void> getFactoryMacAddress(
-        getFactoryMacAddress_cb hidl_status_cb) override;
-
-   private:
-    // Corresponding worker functions for the HIDL methods.
-    std::pair<WifiStatus, std::string> getNameInternal();
-    std::pair<WifiStatus, IfaceType> getTypeInternal();
-    WifiStatus registerEventCallbackInternal(
-        const sp<IWifiStaIfaceEventCallback>& callback);
-    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
-    std::pair<WifiStatus, StaApfPacketFilterCapabilities>
-    getApfPacketFilterCapabilitiesInternal();
-    WifiStatus installApfPacketFilterInternal(
-        uint32_t cmd_id, const std::vector<uint8_t>& program);
-    std::pair<WifiStatus, std::vector<uint8_t>>
-    readApfPacketFilterDataInternal();
-    std::pair<WifiStatus, StaBackgroundScanCapabilities>
-    getBackgroundScanCapabilitiesInternal();
-    std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-    getValidFrequenciesForBandInternal(WifiBand band);
-    WifiStatus startBackgroundScanInternal(
-        uint32_t cmd_id, const StaBackgroundScanParameters& params);
-    WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
-    WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
-    WifiStatus disableLinkLayerStatsCollectionInternal();
-    std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
-    std::pair<WifiStatus, V1_3::StaLinkLayerStats>
-    getLinkLayerStatsInternal_1_3();
-    WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
-                                           int32_t min_rssi);
-    WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
-    std::pair<WifiStatus, StaRoamingCapabilities>
-    getRoamingCapabilitiesInternal();
-    WifiStatus configureRoamingInternal(const StaRoamingConfig& config);
-    WifiStatus setRoamingStateInternal(StaRoamingState state);
-    WifiStatus enableNdOffloadInternal(bool enable);
-    WifiStatus startSendingKeepAlivePacketsInternal(
-        uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
-        uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
-        const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
-    WifiStatus stopSendingKeepAlivePacketsInternal(uint32_t cmd_id);
-    WifiStatus setScanningMacOuiInternal(const std::array<uint8_t, 3>& oui);
-    WifiStatus startDebugPacketFateMonitoringInternal();
-    std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
-    getDebugTxPacketFatesInternal();
-    std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
-    getDebugRxPacketFatesInternal();
-    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
-    std::pair<WifiStatus, std::array<uint8_t, 6>>
-    getFactoryMacAddressInternal();
-
-    std::string ifname_;
-    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
-    bool is_valid_;
-    hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback>
-        event_cb_handler_;
-
-    DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_STA_IFACE_H_
diff --git a/wifi/1.3/default/wifi_status_util.cpp b/wifi/1.3/default/wifi_status_util.cpp
deleted file mode 100644
index 0a5bb13..0000000
--- a/wifi/1.3/default/wifi_status_util.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-
-std::string legacyErrorToString(legacy_hal::wifi_error error) {
-    switch (error) {
-        case legacy_hal::WIFI_SUCCESS:
-            return "SUCCESS";
-        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
-            return "UNINITIALIZED";
-        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
-            return "NOT_AVAILABLE";
-        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
-            return "NOT_SUPPORTED";
-        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
-            return "INVALID_ARGS";
-        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
-            return "INVALID_REQUEST_ID";
-        case legacy_hal::WIFI_ERROR_TIMED_OUT:
-            return "TIMED_OUT";
-        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
-            return "TOO_MANY_REQUESTS";
-        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
-            return "OUT_OF_MEMORY";
-        case legacy_hal::WIFI_ERROR_BUSY:
-            return "BUSY";
-        case legacy_hal::WIFI_ERROR_UNKNOWN:
-            return "UNKNOWN";
-    }
-}
-
-WifiStatus createWifiStatus(WifiStatusCode code,
-                            const std::string& description) {
-    return {code, description};
-}
-
-WifiStatus createWifiStatus(WifiStatusCode code) {
-    return createWifiStatus(code, "");
-}
-
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
-                                           const std::string& desc) {
-    switch (error) {
-        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
-        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
-            return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
-
-        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
-            return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
-
-        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
-        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
-            return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
-
-        case legacy_hal::WIFI_ERROR_TIMED_OUT:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
-                                    desc + ", timed out");
-
-        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
-                                    desc + ", too many requests");
-
-        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
-                                    desc + ", out of memory");
-
-        case legacy_hal::WIFI_ERROR_BUSY:
-            return createWifiStatus(WifiStatusCode::ERROR_BUSY);
-
-        case legacy_hal::WIFI_ERROR_NONE:
-            return createWifiStatus(WifiStatusCode::SUCCESS, desc);
-
-        case legacy_hal::WIFI_ERROR_UNKNOWN:
-            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
-    }
-}
-
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
-    return createWifiStatusFromLegacyError(error, "");
-}
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.3/default/wifi_status_util.h b/wifi/1.3/default/wifi_status_util.h
deleted file mode 100644
index bc8baa9..0000000
--- a/wifi/1.3/default/wifi_status_util.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 WIFI_STATUS_UTIL_H_
-#define WIFI_STATUS_UTIL_H_
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_3 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-std::string legacyErrorToString(legacy_hal::wifi_error error);
-WifiStatus createWifiStatus(WifiStatusCode code,
-                            const std::string& description);
-WifiStatus createWifiStatus(WifiStatusCode code);
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
-                                           const std::string& description);
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
-
-}  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_STATUS_UTIL_H_
diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp
index 9ffda8b..3568330 100644
--- a/wifi/1.3/vts/functional/Android.bp
+++ b/wifi/1.3/vts/functional/Android.bp
@@ -18,7 +18,6 @@
     name: "VtsHalWifiV1_3TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiV1_3TargetTest.cpp",
         "wifi_chip_hidl_test.cpp",
         "wifi_sta_iface_hidl_test.cpp",
     ],
@@ -30,4 +29,6 @@
         "android.hardware.wifi@1.3",
         "libwifi-system-iface"
     ],
+    disable_framework: true,
+    test_suites: ["general-tests", "vts"],
 }
diff --git a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
deleted file mode 100644
index faf426e..0000000
--- a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
+++ /dev/null
@@ -1,50 +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 <android-base/logging.h>
-#include <android/hardware/wifi/1.3/IWifi.h>
-
-#include "wifi_hidl_test_utils.h"
-
-using ::android::hardware::wifi::V1_3::IWifi;
-
-// Test environment for Wifi HIDL HAL.
-class WifiHidlEnvironment_1_3 : public WifiHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiHidlEnvironment_1_3* Instance() {
-        static WifiHidlEnvironment_1_3* instance = new WifiHidlEnvironment_1_3;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<android::hardware::wifi::V1_3::IWifi>();
-    }
-
-   private:
-    WifiHidlEnvironment_1_3() {}
-};
-
-WifiHidlEnvironment_1_3* gEnv = WifiHidlEnvironment_1_3::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
diff --git a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
index d980fcb..e99b34a 100644
--- a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
@@ -16,9 +16,11 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.3/IWifi.h>
 #include <android/hardware/wifi/1.3/IWifiChip.h>
-
-#include <VtsHalHidlTargetTestBase.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"
@@ -39,14 +41,17 @@
 /**
  * Fixture to use for all Wifi chip HIDL interface tests.
  */
-class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_chip_ = IWifiChip::castFrom(getWifiChip());
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_chip_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     // Helper function to configure the Chip in one of the supported modes.
@@ -70,6 +75,9 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -77,7 +85,7 @@
  * This test case tests the setLatencyMode() API with
  * Latency mode NORMAL
  */
-TEST_F(WifiChipHidlTest, SetLatencyMode_normal) {
+TEST_P(WifiChipHidlTest, SetLatencyMode_normal) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, setLatencyMode, kLatencyModeNormal);
@@ -92,7 +100,7 @@
  * SetLatencyMode_low
  * This test case tests the setLatencyMode() API with Latency mode LOW
  */
-TEST_F(WifiChipHidlTest, SetLatencyMode_low) {
+TEST_P(WifiChipHidlTest, SetLatencyMode_low) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, setLatencyMode, kLatencyModeLow);
@@ -106,7 +114,7 @@
 /*
  * GetCapabilities_1_3
  */
-TEST_F(WifiChipHidlTest, GetCapabilities_1_3) {
+TEST_P(WifiChipHidlTest, GetCapabilities_1_3) {
     configureChipForIfaceType(IfaceType::STA, true);
     const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities_1_3);
     if (status_and_caps.first.code != WifiStatusCode::SUCCESS) {
@@ -116,3 +124,9 @@
     }
     EXPECT_NE(0u, status_and_caps.second);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_3::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
index 71e90ac..41d4ebb 100644
--- a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -19,28 +19,36 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.3/IWifi.h>
 #include <android/hardware/wifi/1.3/IWifiStaIface.h>
-
-#include <VtsHalHidlTargetTestBase.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_array;
+using ::android::hardware::wifi::V1_0::WifiStatus;
 using ::android::hardware::wifi::V1_0::WifiStatusCode;
 using ::android::hardware::wifi::V1_3::IWifiStaIface;
 
 /**
  * Fixture to use for all STA Iface HIDL interface tests.
  */
-class WifiStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface());
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_sta_iface_ =
+            IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName()));
         ASSERT_NE(nullptr, wifi_sta_iface_.get());
     }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
     bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
@@ -51,6 +59,9 @@
     }
 
     sp<IWifiStaIface> wifi_sta_iface_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -58,15 +69,12 @@
  * Ensures that calls to get factory MAC address will retrieve a non-zero MAC
  * and return a success status code.
  */
-TEST_F(WifiStaIfaceHidlTest, GetFactoryMacAddress) {
-    const auto& status_and_mac =
+TEST_P(WifiStaIfaceHidlTest, GetFactoryMacAddress) {
+    std::pair<WifiStatus, hidl_array<uint8_t, 6> > status_and_mac =
         HIDL_INVOKE(wifi_sta_iface_, getFactoryMacAddress);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code);
-    const int num_elements = sizeof(status_and_mac.second) / sizeof(uint8_t);
-    EXPECT_EQ(6, num_elements);
-    for (int i = 0; i < num_elements; i++) {
-        EXPECT_NE(0, status_and_mac.second[i]);
-    }
+    hidl_array<uint8_t, 6> all_zero{};
+    EXPECT_NE(all_zero, status_and_mac.second);
 }
 
 /*
@@ -74,7 +82,7 @@
  * Ensures that calls to get link layer stats V1_3 will retrieve a non-empty
  * StaLinkLayerStats after link layer stats collection is enabled.
  */
-TEST_F(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) {
+TEST_P(WifiStaIfaceHidlTest, GetLinkLayerStats_1_3) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
         // No-op if link layer stats is not supported.
@@ -95,3 +103,9 @@
         WifiStatusCode::SUCCESS,
         HIDL_INVOKE(wifi_sta_iface_, disableLinkLayerStatsCollection).code);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiStaIfaceHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_3::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp
new file mode 100644
index 0000000..5620d03
--- /dev/null
+++ b/wifi/1.4/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi@1.4",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IWifi.hal",
+        "IWifiApIface.hal",
+        "IWifiChip.hal",
+        "IWifiChipEventCallback.hal",
+        "IWifiNanIface.hal",
+        "IWifiRttController.hal",
+        "IWifiRttControllerEventCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/wifi/1.4/IWifi.hal b/wifi/1.4/IWifi.hal
new file mode 100644
index 0000000..765e09d
--- /dev/null
+++ b/wifi/1.4/IWifi.hal
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.4;
+
+import @1.3::IWifi;
+
+/**
+ * This is the root of the HAL module and is the interface returned when
+ * loading an implementation of the Wi-Fi HAL. There must be at most one
+ * module loaded in the system.
+ * IWifi.getChip() must return @1.2::IWifiChip
+ */
+interface IWifi extends @1.3::IWifi {};
diff --git a/wifi/1.4/IWifiApIface.hal b/wifi/1.4/IWifiApIface.hal
new file mode 100644
index 0000000..80c576d
--- /dev/null
+++ b/wifi/1.4/IWifiApIface.hal
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.4;
+
+import @1.0::IWifiApIface;
+import @1.0::MacAddress;
+import @1.0::WifiStatus;
+
+/**
+ * Represents a network interface in AP mode.
+ *
+ * This can be obtained through @1.0::IWifiChip.getApIface() and casting
+ * IWifiApIface up to 1.4.
+ */
+interface IWifiApIface extends @1.0::IWifiApIface {
+    /**
+     * Changes the MAC address of the interface to the given MAC address.
+     *
+     * @param mac MAC address to change to.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    setMacAddress(MacAddress mac) generates (WifiStatus status);
+
+    /**
+     * Gets the factory MAC address of the interface.
+     *
+     * @return status WifiStatus of the operation
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     * @return mac factory MAC address of the interface
+     */
+    getFactoryMacAddress() generates (WifiStatus status, MacAddress mac);
+};
diff --git a/wifi/1.4/IWifiChip.hal b/wifi/1.4/IWifiChip.hal
new file mode 100644
index 0000000..07f4a65
--- /dev/null
+++ b/wifi/1.4/IWifiChip.hal
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.4;
+
+import @1.0::WifiStatus;
+import @1.0::IWifiIface;
+import @1.3::IWifiChip;
+import IWifiChipEventCallback;
+import IWifiRttController;
+
+/**
+ * Interface that represents a chip that must be configured as a single unit.
+ */
+interface IWifiChip extends @1.3::IWifiChip {
+    /**
+     * Requests notifications of significant events on this chip. Multiple calls
+     * to this must register multiple callbacks each of which must receive all
+     * events.
+     *
+     * @param callback An instance of the |IWifiChipEventCallback| HIDL interface
+     *        object.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+     */
+    registerEventCallback_1_4(IWifiChipEventCallback callback) generates (WifiStatus status);
+
+    /**
+     * Create a RTTController instance.
+     *
+     * RTT controller can be either:
+     * a) Bound to a specific iface by passing in the corresponding |IWifiIface|
+     * object in |iface| param, OR
+     * b) Let the implementation decide the iface to use for RTT operations by
+     * passing null in |iface| param.
+     *
+     * @param boundIface HIDL interface object representing the iface if
+     *        the responder must be bound to a specific iface, null otherwise.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+     */
+    createRttController_1_4(IWifiIface boundIface)
+        generates (WifiStatus status, IWifiRttController rtt);
+};
diff --git a/wifi/1.4/IWifiChipEventCallback.hal b/wifi/1.4/IWifiChipEventCallback.hal
new file mode 100644
index 0000000..9ead344
--- /dev/null
+++ b/wifi/1.4/IWifiChipEventCallback.hal
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.4;
+
+import @1.2::IWifiChipEventCallback;
+import WifiBand;
+
+/**
+ * Wifi chip event callbacks.
+ */
+interface IWifiChipEventCallback extends @1.2::IWifiChipEventCallback {
+    /**
+     * Struct describing the state of each hardware radio chain (hardware MAC)
+     * on the device.
+     */
+    struct RadioModeInfo {
+        /**
+         * Identifier for this radio chain. This is vendor dependent & used
+         * only for debugging purposes.
+         */
+        uint32_t radioId;
+
+        /**
+         * List of bands on which this radio chain is operating.
+         * Can be one of:
+         * a) WifiBand.BAND_24GHZ => 2.4Ghz.
+         * b) WifiBand.BAND_5GHZ => 5Ghz.
+         * c) WifiBand.BAND_24GHZ_5GHZ = 2.4Ghz + 5Ghz (Radio is time sharing
+         * across the 2 bands).
+         * d) WifiBand.BAND_6GHZ => 6Ghz.
+         * e) WifiBand.BAND_5GHZ_6GHZ => 5Ghz + 6Ghz (Radio is time sharing
+         * across the 2 bands).
+         * f) WifiBand.BAND_24GHZ_5GHZ_6GHZ => 2.4Ghz + 5Ghz + 6Ghz (Radio is
+         * time sharing across the 3 bands).
+         */
+        WifiBand bandInfo;
+
+        /**
+         * List of interfaces on this radio chain (hardware MAC).
+         */
+        vec<IfaceInfo> ifaceInfos;
+    };
+
+    /**
+     * Asynchronous callback indicating a radio mode change.
+     * Radio mode change could be a result of:
+     * a) Bringing up concurrent interfaces (For ex: STA + AP).
+     * b) Change in operating band of one of the concurrent interfaces (For ex:
+     * STA connection moved from 2.4G to 5G)
+     *
+     * @param radioModeInfos List of RadioModeInfo structures for each
+     * radio chain (hardware MAC) on the device.
+     */
+    oneway onRadioModeChange_1_4(vec<RadioModeInfo> radioModeInfos);
+};
diff --git a/wifi/1.4/IWifiNanIface.hal b/wifi/1.4/IWifiNanIface.hal
new file mode 100644
index 0000000..881d06c
--- /dev/null
+++ b/wifi/1.4/IWifiNanIface.hal
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.4;
+
+import @1.0::CommandIdShort;
+import @1.0::WifiStatus;
+import @1.2::IWifiNanIface;
+import @1.2::NanConfigRequestSupplemental;
+import NanConfigRequest;
+import NanEnableRequest;
+
+/**
+ * Interface used to represent a single NAN (Neighbour Aware Network) iface.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIface extends @1.2::IWifiNanIface {
+    /**
+     * Enable NAN: configures and activates NAN clustering (does not start
+     * a discovery session or set up data-interfaces or data-paths). Use the
+     * |IWifiNanIface.configureRequest| method to change the configuration of an already enabled
+     * NAN interface.
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyEnableResponse|.
+     *
+     * Note: supersedes the @1.2::IWifiNanIface.enableRequest() method which is deprecated as of
+     * HAL version 1.4.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg1 Instance of |NanEnableRequest|.
+     * @param msg2 Instance of |NanConfigRequestSupplemental|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    enableRequest_1_4(CommandIdShort cmdId, NanEnableRequest msg1,
+        NanConfigRequestSupplemental msg2) generates (WifiStatus status);
+
+    /**
+     * Configure NAN: configures an existing NAN functionality (i.e. assumes
+     * |IWifiNanIface.enableRequest| already submitted and succeeded).
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyConfigResponse|.
+     *
+     * Note: supersedes the @1.2::IWifiNanIface.configRequest() method which is deprecated as of
+     * HAL version 1.4.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg1 Instance of |NanConfigRequest|.
+     * @param msg1 Instance of |NanConfigRequestSupplemental|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    configRequest_1_4(CommandIdShort cmdId, NanConfigRequest msg1,
+        NanConfigRequestSupplemental msg2) generates (WifiStatus status);
+};
diff --git a/wifi/1.4/IWifiRttController.hal b/wifi/1.4/IWifiRttController.hal
new file mode 100644
index 0000000..5c71975
--- /dev/null
+++ b/wifi/1.4/IWifiRttController.hal
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.4;
+
+import @1.0::IWifiRttController;
+import @1.0::CommandId;
+import @1.0::WifiChannelInfo;
+import @1.0::WifiStatus;
+import IWifiRttControllerEventCallback;
+
+/**
+ * Interface used to perform RTT(Round trip time) operations.
+ */
+interface IWifiRttController extends @1.0::IWifiRttController {
+    /**
+     * Requests notifications of significant events on this rtt controller.
+     * Multiple calls to this must register multiple callbacks each of which must
+     * receive all events.
+     *
+     * @param callback An instance of the |IWifiRttControllerEventCallback| HIDL
+     *        interface object.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+     */
+    registerEventCallback_1_4(IWifiRttControllerEventCallback callback)
+        generates (WifiStatus status);
+
+    /**
+     * API to request RTT measurement.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param rttConfigs Vector of |RttConfig| parameters.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    rangeRequest_1_4(CommandId cmdId, vec<RttConfig> rttConfigs) generates (WifiStatus status);
+
+    /**
+     * RTT capabilities of the device.
+     *
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     * @return capabilities Instance of |RttCapabilities|.
+     */
+    getCapabilities_1_4() generates (WifiStatus status, RttCapabilities capabilities);
+
+    /**
+     * Get RTT responder information e.g. WiFi channel to enable responder on.
+     *
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     * @return info Instance of |RttResponderInfo|.
+     */
+    getResponderInfo_1_4() generates (WifiStatus status, RttResponder info);
+
+    /**
+     * Enable RTT responder mode.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @parm channelHint Hint of the channel information where RTT responder must
+     *       be enabled on.
+     * @param maxDurationInSeconds Timeout of responder mode.
+     * @param info Instance of |RttResponderInfo|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    enableResponder_1_4(CommandId cmdId, WifiChannelInfo channelHint,
+        uint32_t maxDurationInSeconds, RttResponder info) generates (WifiStatus status);
+};
diff --git a/wifi/1.4/IWifiRttControllerEventCallback.hal b/wifi/1.4/IWifiRttControllerEventCallback.hal
new file mode 100644
index 0000000..75de3d4
--- /dev/null
+++ b/wifi/1.4/IWifiRttControllerEventCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.4;
+
+import @1.0::IWifiRttControllerEventCallback;
+import @1.0::CommandId;
+
+/**
+ * RTT Response and Event Callbacks.
+ */
+interface IWifiRttControllerEventCallback extends @1.0::IWifiRttControllerEventCallback {
+    /*
+     * Invoked when an RTT result is available.
+     *
+     * @param cmdId command Id corresponding to the original request.
+     * @param results Vector of |RttResult| instances.
+     */
+    oneway onResults_1_4(CommandId cmdId, vec<RttResult> results);
+};
diff --git a/wifi/1.4/default/Android.mk b/wifi/1.4/default/Android.mk
new file mode 100644
index 0000000..6be7dad
--- /dev/null
+++ b/wifi/1.4/default/Android.mk
@@ -0,0 +1,177 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+LOCAL_PATH := $(call my-dir)
+
+###
+### android.hardware.wifi static library
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-lib
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+ifdef WIFI_HAL_INTERFACE_COMBINATIONS
+LOCAL_CPPFLAGS += -DWIFI_HAL_INTERFACE_COMBINATIONS="$(WIFI_HAL_INTERFACE_COMBINATIONS)"
+endif
+ifdef WIFI_HIDL_FEATURE_AWARE
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE
+endif
+ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DUAL_INTERFACE
+endif
+ifdef WIFI_HIDL_FEATURE_DISABLE_AP
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP
+endif
+ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+endif
+ifdef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+LOCAL_CPPFLAGS += -DWIFI_AVOID_IFACE_RESET_MAC_CHANGE
+endif
+# Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
+LOCAL_CFLAGS += -Wno-error=implicit-fallthrough
+LOCAL_SRC_FILES := \
+    hidl_struct_util.cpp \
+    hidl_sync_util.cpp \
+    ringbuffer.cpp \
+    wifi.cpp \
+    wifi_ap_iface.cpp \
+    wifi_chip.cpp \
+    wifi_feature_flags.cpp \
+    wifi_iface_util.cpp \
+    wifi_legacy_hal.cpp \
+    wifi_legacy_hal_stubs.cpp \
+    wifi_mode_controller.cpp \
+    wifi_nan_iface.cpp \
+    wifi_p2p_iface.cpp \
+    wifi_rtt_controller.cpp \
+    wifi_sta_iface.cpp \
+    wifi_status_util.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3 \
+    android.hardware.wifi@1.4
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_STATIC_LIBRARY)
+
+###
+### android.hardware.wifi daemon
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service
+LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+LOCAL_SRC_FILES := \
+    service.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3 \
+    android.hardware.wifi@1.4
+LOCAL_STATIC_LIBRARIES := \
+    android.hardware.wifi@1.0-service-lib
+LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
+include $(BUILD_EXECUTABLE)
+
+###
+### android.hardware.wifi daemon
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-lazy
+LOCAL_VINTF_FRAGMENTS := android.hardware.wifi@1.0-service.xml
+LOCAL_OVERRIDES_MODULES := android.hardware.wifi@1.0-service
+LOCAL_CFLAGS := -DLAZY_SERVICE
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+LOCAL_SRC_FILES := \
+    service.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3 \
+    android.hardware.wifi@1.4
+LOCAL_STATIC_LIBRARIES := \
+    android.hardware.wifi@1.0-service-lib
+LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc
+include $(BUILD_EXECUTABLE)
+
+###
+### android.hardware.wifi unit tests.
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-tests
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+LOCAL_SRC_FILES := \
+    tests/hidl_struct_util_unit_tests.cpp \
+    tests/main.cpp \
+    tests/mock_interface_tool.cpp \
+    tests/mock_wifi_feature_flags.cpp \
+    tests/mock_wifi_iface_util.cpp \
+    tests/mock_wifi_legacy_hal.cpp \
+    tests/mock_wifi_mode_controller.cpp \
+    tests/ringbuffer_unit_tests.cpp \
+    tests/wifi_nan_iface_unit_tests.cpp \
+    tests/wifi_chip_unit_tests.cpp \
+    tests/wifi_iface_util_unit_tests.cpp
+LOCAL_STATIC_LIBRARIES := \
+    libgmock \
+    libgtest \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3 \
+    android.hardware.wifi@1.4 \
+    android.hardware.wifi@1.0-service-lib
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface
+include $(BUILD_NATIVE_TEST)
diff --git a/wifi/1.3/default/OWNERS b/wifi/1.4/default/OWNERS
similarity index 100%
rename from wifi/1.3/default/OWNERS
rename to wifi/1.4/default/OWNERS
diff --git a/wifi/1.3/default/THREADING.README b/wifi/1.4/default/THREADING.README
similarity index 100%
rename from wifi/1.3/default/THREADING.README
rename to wifi/1.4/default/THREADING.README
diff --git a/wifi/1.3/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.4/default/android.hardware.wifi@1.0-service-lazy.rc
similarity index 100%
rename from wifi/1.3/default/android.hardware.wifi@1.0-service-lazy.rc
rename to wifi/1.4/default/android.hardware.wifi@1.0-service-lazy.rc
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.rc b/wifi/1.4/default/android.hardware.wifi@1.0-service.rc
new file mode 100644
index 0000000..64a51b0
--- /dev/null
+++ b/wifi/1.4/default/android.hardware.wifi@1.0-service.rc
@@ -0,0 +1,10 @@
+service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
+    interface android.hardware.wifi@1.0::IWifi default
+    interface android.hardware.wifi@1.1::IWifi default
+    interface android.hardware.wifi@1.2::IWifi default
+    interface android.hardware.wifi@1.3::IWifi default
+    interface android.hardware.wifi@1.4::IWifi default
+    class hal
+    capabilities NET_ADMIN NET_RAW SYS_MODULE
+    user wifi
+    group wifi gps
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
new file mode 100644
index 0000000..b5d25cd
--- /dev/null
+++ b/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.wifi</name>
+        <transport>hwbinder</transport>
+        <version>1.4</version>
+        <interface>
+            <name>IWifi</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/wifi/1.4/default/hidl_callback_util.h b/wifi/1.4/default/hidl_callback_util.h
new file mode 100644
index 0000000..fc601b8
--- /dev/null
+++ b/wifi/1.4/default/hidl_callback_util.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_CALLBACK_UTIL_H_
+#define HIDL_CALLBACK_UTIL_H_
+
+#include <set>
+
+#include <hidl/HidlSupport.h>
+
+namespace {
+// Type of callback invoked by the death handler.
+using on_death_cb_function = std::function<void(uint64_t)>;
+
+// Private class used to keep track of death of individual
+// callbacks stored in HidlCallbackHandler.
+template <typename CallbackType>
+class HidlDeathHandler : public android::hardware::hidl_death_recipient {
+   public:
+    HidlDeathHandler(const on_death_cb_function& user_cb_function)
+        : cb_function_(user_cb_function) {}
+    ~HidlDeathHandler() = default;
+
+    // Death notification for callbacks.
+    void serviceDied(
+        uint64_t cookie,
+        const android::wp<android::hidl::base::V1_0::IBase>& /* who */)
+        override {
+        cb_function_(cookie);
+    }
+
+   private:
+    on_death_cb_function cb_function_;
+
+    DISALLOW_COPY_AND_ASSIGN(HidlDeathHandler);
+};
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_callback_util {
+template <typename CallbackType>
+// Provides a class to manage callbacks for the various HIDL interfaces and
+// handle the death of the process hosting each callback.
+class HidlCallbackHandler {
+   public:
+    HidlCallbackHandler()
+        : death_handler_(new HidlDeathHandler<CallbackType>(
+              std::bind(&HidlCallbackHandler::onObjectDeath, this,
+                        std::placeholders::_1))) {}
+    ~HidlCallbackHandler() = default;
+
+    bool addCallback(const sp<CallbackType>& cb) {
+        // TODO(b/33818800): Can't compare proxies yet. So, use the cookie
+        // (callback proxy's raw pointer) to track the death of individual
+        // clients.
+        uint64_t cookie = reinterpret_cast<uint64_t>(cb.get());
+        if (cb_set_.find(cb) != cb_set_.end()) {
+            LOG(WARNING) << "Duplicate death notification registration";
+            return true;
+        }
+        if (!cb->linkToDeath(death_handler_, cookie)) {
+            LOG(ERROR) << "Failed to register death notification";
+            return false;
+        }
+        cb_set_.insert(cb);
+        return true;
+    }
+
+    const std::set<android::sp<CallbackType>>& getCallbacks() {
+        return cb_set_;
+    }
+
+    // Death notification for callbacks.
+    void onObjectDeath(uint64_t cookie) {
+        CallbackType* cb = reinterpret_cast<CallbackType*>(cookie);
+        const auto& iter = cb_set_.find(cb);
+        if (iter == cb_set_.end()) {
+            LOG(ERROR) << "Unknown callback death notification received";
+            return;
+        }
+        cb_set_.erase(iter);
+        LOG(DEBUG) << "Dead callback removed from list";
+    }
+
+    void invalidate() {
+        for (const sp<CallbackType>& cb : cb_set_) {
+            if (!cb->unlinkToDeath(death_handler_)) {
+                LOG(ERROR) << "Failed to deregister death notification";
+            }
+        }
+        cb_set_.clear();
+    }
+
+   private:
+    std::set<sp<CallbackType>> cb_set_;
+    sp<HidlDeathHandler<CallbackType>> death_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(HidlCallbackHandler);
+};
+
+}  // namespace hidl_callback_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+#endif  // HIDL_CALLBACK_UTIL_H_
diff --git a/wifi/1.4/default/hidl_return_util.h b/wifi/1.4/default/hidl_return_util.h
new file mode 100644
index 0000000..99c7092
--- /dev/null
+++ b/wifi/1.4/default/hidl_return_util.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 HIDL_RETURN_UTIL_H_
+#define HIDL_RETURN_UTIL_H_
+
+#include "hidl_sync_util.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_return_util {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * These utility functions are used to invoke a method on the provided
+ * HIDL interface object.
+ * These functions checks if the provided HIDL interface object is valid.
+ * a) if valid, Invokes the corresponding internal implementation function of
+ * the HIDL method. It then invokes the HIDL continuation callback with
+ * the status and any returned values.
+ * b) if invalid, invokes the HIDL continuation callback with the
+ * provided error status and default values.
+ */
+// Use for HIDL methods which return only an instance of WifiStatus.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCall(
+    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+    const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        hidl_cb((obj->*work)(std::forward<Args>(args)...));
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid));
+    }
+    return Void();
+}
+
+// Use for HIDL methods which return only an instance of WifiStatus.
+// This version passes the global lock acquired to the body of the method.
+// Note: Only used by IWifi::stop() currently.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCallWithLock(
+    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+    const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
+    auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...));
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid));
+    }
+    return Void();
+}
+
+// Use for HIDL methods which return instance of WifiStatus and a single return
+// value.
+template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
+Return<void> validateAndCall(
+    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+    const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
+    Args&&... args) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
+        const WifiStatus& status = std::get<0>(ret_pair);
+        const auto& ret_value = std::get<1>(ret_pair);
+        hidl_cb(status, ret_value);
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid),
+                typename std::remove_reference<ReturnT>::type());
+    }
+    return Void();
+}
+
+// Use for HIDL methods which return instance of WifiStatus and 2 return
+// values.
+template <typename ObjT, typename WorkFuncT, typename ReturnT1,
+          typename ReturnT2, typename... Args>
+Return<void> validateAndCall(
+    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+    const std::function<void(const WifiStatus&, ReturnT1, ReturnT2)>& hidl_cb,
+    Args&&... args) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        const auto& ret_tuple = (obj->*work)(std::forward<Args>(args)...);
+        const WifiStatus& status = std::get<0>(ret_tuple);
+        const auto& ret_value1 = std::get<1>(ret_tuple);
+        const auto& ret_value2 = std::get<2>(ret_tuple);
+        hidl_cb(status, ret_value1, ret_value2);
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid),
+                typename std::remove_reference<ReturnT1>::type(),
+                typename std::remove_reference<ReturnT2>::type());
+    }
+    return Void();
+}
+
+}  // namespace hidl_return_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+#endif  // HIDL_RETURN_UTIL_H_
diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp
new file mode 100644
index 0000000..fd1d5b1
--- /dev/null
+++ b/wifi/1.4/default/hidl_struct_util.cpp
@@ -0,0 +1,2738 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <utils/SystemClock.h>
+
+#include "hidl_struct_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_struct_util {
+
+WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
+    legacy_hal::wifi_channel_width type);
+
+hidl_string safeConvertChar(const char* str, size_t max_len) {
+    const char* c = str;
+    size_t size = 0;
+    while (*c && (unsigned char)*c < 128 && size < max_len) {
+        ++size;
+        ++c;
+    }
+    return hidl_string(str, size);
+}
+
+IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(
+    uint32_t feature) {
+    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+    switch (feature) {
+        case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
+            return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP;
+        case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
+            return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP;
+        case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
+            return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT;
+        case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
+            return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT;
+        case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
+            return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask
+convertLegacyLoggerFeatureToHidlStaIfaceCapability(uint32_t feature) {
+    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+    switch (feature) {
+        case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
+            return HidlStaIfaceCaps::DEBUG_PACKET_FATE;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
+    uint32_t feature) {
+    using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
+    switch (feature) {
+        case WIFI_FEATURE_SET_TX_POWER_LIMIT:
+            return HidlChipCaps::SET_TX_POWER_LIMIT;
+        case WIFI_FEATURE_USE_BODY_HEAD_SAR:
+            return HidlChipCaps::USE_BODY_HEAD_SAR;
+        case WIFI_FEATURE_D2D_RTT:
+            return HidlChipCaps::D2D_RTT;
+        case WIFI_FEATURE_D2AP_RTT:
+            return HidlChipCaps::D2AP_RTT;
+        case WIFI_FEATURE_SET_LATENCY_MODE:
+            return HidlChipCaps::SET_LATENCY_MODE;
+        case WIFI_FEATURE_P2P_RAND_MAC:
+            return HidlChipCaps::P2P_RAND_MAC;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask
+convertLegacyFeatureToHidlStaIfaceCapability(uint64_t feature) {
+    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+    switch (feature) {
+        case WIFI_FEATURE_GSCAN:
+            return HidlStaIfaceCaps::BACKGROUND_SCAN;
+        case WIFI_FEATURE_LINK_LAYER_STATS:
+            return HidlStaIfaceCaps::LINK_LAYER_STATS;
+        case WIFI_FEATURE_RSSI_MONITOR:
+            return HidlStaIfaceCaps::RSSI_MONITOR;
+        case WIFI_FEATURE_CONTROL_ROAMING:
+            return HidlStaIfaceCaps::CONTROL_ROAMING;
+        case WIFI_FEATURE_IE_WHITELIST:
+            return HidlStaIfaceCaps::PROBE_IE_WHITELIST;
+        case WIFI_FEATURE_SCAN_RAND:
+            return HidlStaIfaceCaps::SCAN_RAND;
+        case WIFI_FEATURE_INFRA_5G:
+            return HidlStaIfaceCaps::STA_5G;
+        case WIFI_FEATURE_HOTSPOT:
+            return HidlStaIfaceCaps::HOTSPOT;
+        case WIFI_FEATURE_PNO:
+            return HidlStaIfaceCaps::PNO;
+        case WIFI_FEATURE_TDLS:
+            return HidlStaIfaceCaps::TDLS;
+        case WIFI_FEATURE_TDLS_OFFCHANNEL:
+            return HidlStaIfaceCaps::TDLS_OFFCHANNEL;
+        case WIFI_FEATURE_CONFIG_NDO:
+            return HidlStaIfaceCaps::ND_OFFLOAD;
+        case WIFI_FEATURE_MKEEP_ALIVE:
+            return HidlStaIfaceCaps::KEEP_ALIVE;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+bool convertLegacyFeaturesToHidlChipCapabilities(
+    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint32_t* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+    for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
+        if (feature & legacy_logger_feature_set) {
+            *hidl_caps |=
+                convertLegacyLoggerFeatureToHidlChipCapability(feature);
+        }
+    }
+    std::vector<uint32_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
+                                      WIFI_FEATURE_USE_BODY_HEAD_SAR,
+                                      WIFI_FEATURE_D2D_RTT,
+                                      WIFI_FEATURE_D2AP_RTT,
+                                      WIFI_FEATURE_SET_LATENCY_MODE,
+                                      WIFI_FEATURE_P2P_RAND_MAC};
+    for (const auto feature : features) {
+        if (feature & legacy_feature_set) {
+            *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
+        }
+    }
+
+    // There are no flags for these 3 in the legacy feature set. Adding them to
+    // the set because all the current devices support it.
+    *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
+    *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
+    *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
+    return true;
+}
+
+WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(
+    uint32_t flag) {
+    switch (flag) {
+        case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
+            return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
+        case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
+            return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
+    };
+    CHECK(false) << "Unknown legacy flag: " << flag;
+    return {};
+}
+
+bool convertLegacyDebugRingBufferStatusToHidl(
+    const legacy_hal::wifi_ring_buffer_status& legacy_status,
+    WifiDebugRingBufferStatus* hidl_status) {
+    if (!hidl_status) {
+        return false;
+    }
+    *hidl_status = {};
+    hidl_status->ringName =
+        safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
+                        sizeof(legacy_status.name));
+    hidl_status->flags = 0;
+    for (const auto flag : {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES,
+                            WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
+        if (flag & legacy_status.flags) {
+            hidl_status->flags |= static_cast<
+                std::underlying_type<WifiDebugRingBufferFlags>::type>(
+                convertLegacyDebugRingBufferFlagsToHidl(flag));
+        }
+    }
+    hidl_status->ringId = legacy_status.ring_id;
+    hidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
+    // Calculate free size of the ring the buffer. We don't need to send the
+    // exact read/write pointers that were there in the legacy HAL interface.
+    if (legacy_status.written_bytes >= legacy_status.read_bytes) {
+        hidl_status->freeSizeInBytes =
+            legacy_status.ring_buffer_byte_size -
+            (legacy_status.written_bytes - legacy_status.read_bytes);
+    } else {
+        hidl_status->freeSizeInBytes =
+            legacy_status.read_bytes - legacy_status.written_bytes;
+    }
+    hidl_status->verboseLevel = legacy_status.verbose_level;
+    return true;
+}
+
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
+    if (!hidl_status_vec) {
+        return false;
+    }
+    *hidl_status_vec = {};
+    for (const auto& legacy_status : legacy_status_vec) {
+        WifiDebugRingBufferStatus hidl_status;
+        if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status,
+                                                      &hidl_status)) {
+            return false;
+        }
+        hidl_status_vec->push_back(hidl_status);
+    }
+    return true;
+}
+
+bool convertLegacyWakeReasonStatsToHidl(
+    const legacy_hal::WakeReasonStats& legacy_stats,
+    WifiDebugHostWakeReasonStats* hidl_stats) {
+    if (!hidl_stats) {
+        return false;
+    }
+    *hidl_stats = {};
+    hidl_stats->totalCmdEventWakeCnt =
+        legacy_stats.wake_reason_cnt.total_cmd_event_wake;
+    hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
+    hidl_stats->totalDriverFwLocalWakeCnt =
+        legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
+    hidl_stats->driverFwLocalWakeCntPerType =
+        legacy_stats.driver_fw_local_wake_cnt;
+    hidl_stats->totalRxPacketWakeCnt =
+        legacy_stats.wake_reason_cnt.total_rx_data_wake;
+    hidl_stats->rxPktWakeDetails.rxUnicastCnt =
+        legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
+    hidl_stats->rxPktWakeDetails.rxMulticastCnt =
+        legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
+    hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
+        legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
+    hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
+        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+            .ipv4_rx_multicast_addr_cnt;
+    hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
+        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+            .ipv6_rx_multicast_addr_cnt;
+    hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
+        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+            .other_rx_multicast_addr_cnt;
+    hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
+        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
+        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
+        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
+        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
+        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
+    return true;
+}
+
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
+    V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
+    switch (hidl_scenario) {
+        // This is the only supported scenario for V1_1
+        case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
+            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+    };
+    CHECK(false);
+}
+
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+    V1_2::IWifiChip::TxPowerScenario hidl_scenario) {
+    switch (hidl_scenario) {
+        // This is the only supported scenario for V1_1
+        case V1_2::IWifiChip::TxPowerScenario::VOICE_CALL:
+            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+        // Those are the supported scenarios for V1_2
+        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+    };
+    CHECK(false);
+}
+
+legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
+    V1_3::IWifiChip::LatencyMode hidl_latency_mode) {
+    switch (hidl_latency_mode) {
+        case V1_3::IWifiChip::LatencyMode::NORMAL:
+            return legacy_hal::WIFI_LATENCY_MODE_NORMAL;
+        case V1_3::IWifiChip::LatencyMode::LOW:
+            return legacy_hal::WIFI_LATENCY_MODE_LOW;
+    }
+    CHECK(false);
+}
+
+bool convertLegacyWifiMacInfoToHidl(
+    const legacy_hal::WifiMacInfo& legacy_mac_info,
+    IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
+    if (!hidl_radio_mode_info) {
+        return false;
+    }
+    *hidl_radio_mode_info = {};
+
+    hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
+    // Convert from bitmask of bands in the legacy HAL to enum value in
+    // the HIDL interface.
+    if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
+        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND &&
+        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ_6GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
+               legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ_6GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_6GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
+               legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ;
+    } else {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED;
+    }
+    std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
+    for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
+        V1_2::IWifiChipEventCallback::IfaceInfo iface_info;
+        iface_info.name = legacy_iface_info.name;
+        iface_info.channel = legacy_iface_info.channel;
+        iface_info_vec.push_back(iface_info);
+    }
+    hidl_radio_mode_info->ifaceInfos = iface_info_vec;
+    return true;
+}
+
+bool convertLegacyWifiMacInfosToHidl(
+    const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) {
+    if (!hidl_radio_mode_infos) {
+        return false;
+    }
+    *hidl_radio_mode_infos = {};
+
+    for (const auto& legacy_mac_info : legacy_mac_infos) {
+        IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
+        if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
+                                            &hidl_radio_mode_info)) {
+            return false;
+        }
+        hidl_radio_mode_infos->push_back(hidl_radio_mode_info);
+    }
+    return true;
+}
+
+bool convertLegacyFeaturesToHidlStaCapabilities(
+    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint32_t* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+    for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
+        if (feature & legacy_logger_feature_set) {
+            *hidl_caps |=
+                convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
+        }
+    }
+    for (const auto feature :
+         {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS,
+          WIFI_FEATURE_RSSI_MONITOR, WIFI_FEATURE_CONTROL_ROAMING,
+          WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND,
+          WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO,
+          WIFI_FEATURE_TDLS, WIFI_FEATURE_TDLS_OFFCHANNEL,
+          WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) {
+        if (feature & legacy_feature_set) {
+            *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
+        }
+    }
+    // There is no flag for this one in the legacy feature set. Adding it to the
+    // set because all the current devices support it.
+    *hidl_caps |= HidlStaIfaceCaps::APF;
+    return true;
+}
+
+bool convertLegacyApfCapabilitiesToHidl(
+    const legacy_hal::PacketFilterCapabilities& legacy_caps,
+    StaApfPacketFilterCapabilities* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    hidl_caps->version = legacy_caps.version;
+    hidl_caps->maxLength = legacy_caps.max_len;
+    return true;
+}
+
+uint8_t convertHidlGscanReportEventFlagToLegacy(
+    StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
+    using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+    switch (hidl_flag) {
+        case HidlFlag::EACH_SCAN:
+            return REPORT_EVENTS_EACH_SCAN;
+        case HidlFlag::FULL_RESULTS:
+            return REPORT_EVENTS_FULL_RESULTS;
+        case HidlFlag::NO_BATCH:
+            return REPORT_EVENTS_NO_BATCH;
+    };
+    CHECK(false);
+}
+
+StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(uint8_t legacy_flag) {
+    switch (legacy_flag) {
+        case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
+            return StaScanDataFlagMask::INTERRUPTED;
+    };
+    CHECK(false) << "Unknown legacy flag: " << legacy_flag;
+    // To silence the compiler warning about reaching the end of non-void
+    // function.
+    return {};
+}
+
+bool convertLegacyGscanCapabilitiesToHidl(
+    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+    StaBackgroundScanCapabilities* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
+    hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
+    hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
+    hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
+    return true;
+}
+
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band) {
+    switch (band) {
+        case V1_0::WifiBand::BAND_UNSPECIFIED:
+            return legacy_hal::WIFI_BAND_UNSPECIFIED;
+        case V1_0::WifiBand::BAND_24GHZ:
+            return legacy_hal::WIFI_BAND_BG;
+        case V1_0::WifiBand::BAND_5GHZ:
+            return legacy_hal::WIFI_BAND_A;
+        case V1_0::WifiBand::BAND_5GHZ_DFS:
+            return legacy_hal::WIFI_BAND_A_DFS;
+        case V1_0::WifiBand::BAND_5GHZ_WITH_DFS:
+            return legacy_hal::WIFI_BAND_A_WITH_DFS;
+        case V1_0::WifiBand::BAND_24GHZ_5GHZ:
+            return legacy_hal::WIFI_BAND_ABG;
+        case V1_0::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
+            return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
+    };
+    CHECK(false);
+}
+
+bool convertHidlGscanParamsToLegacy(
+    const StaBackgroundScanParameters& hidl_scan_params,
+    legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
+    if (!legacy_scan_params) {
+        return false;
+    }
+    *legacy_scan_params = {};
+    legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
+    legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
+    legacy_scan_params->report_threshold_percent =
+        hidl_scan_params.reportThresholdPercent;
+    legacy_scan_params->report_threshold_num_scans =
+        hidl_scan_params.reportThresholdNumScans;
+    if (hidl_scan_params.buckets.size() > MAX_BUCKETS) {
+        return false;
+    }
+    legacy_scan_params->num_buckets = hidl_scan_params.buckets.size();
+    for (uint32_t bucket_idx = 0; bucket_idx < hidl_scan_params.buckets.size();
+         bucket_idx++) {
+        const StaBackgroundScanBucketParameters& hidl_bucket_spec =
+            hidl_scan_params.buckets[bucket_idx];
+        legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
+            legacy_scan_params->buckets[bucket_idx];
+        if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
+            return false;
+        }
+        legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
+        legacy_bucket_spec.band =
+            convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
+        legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
+        legacy_bucket_spec.max_period =
+            hidl_bucket_spec.exponentialMaxPeriodInMs;
+        legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
+        legacy_bucket_spec.step_count = hidl_bucket_spec.exponentialStepCount;
+        legacy_bucket_spec.report_events = 0;
+        using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+        for (const auto flag : {HidlFlag::EACH_SCAN, HidlFlag::FULL_RESULTS,
+                                HidlFlag::NO_BATCH}) {
+            if (hidl_bucket_spec.eventReportScheme &
+                static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
+                legacy_bucket_spec.report_events |=
+                    convertHidlGscanReportEventFlagToLegacy(flag);
+            }
+        }
+        if (hidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
+            return false;
+        }
+        legacy_bucket_spec.num_channels = hidl_bucket_spec.frequencies.size();
+        for (uint32_t freq_idx = 0;
+             freq_idx < hidl_bucket_spec.frequencies.size(); freq_idx++) {
+            legacy_bucket_spec.channels[freq_idx].channel =
+                hidl_bucket_spec.frequencies[freq_idx];
+        }
+    }
+    return true;
+}
+
+bool convertLegacyIeToHidl(
+    const legacy_hal::wifi_information_element& legacy_ie,
+    WifiInformationElement* hidl_ie) {
+    if (!hidl_ie) {
+        return false;
+    }
+    *hidl_ie = {};
+    hidl_ie->id = legacy_ie.id;
+    hidl_ie->data =
+        std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
+    return true;
+}
+
+bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob, uint32_t ie_blob_len,
+                               std::vector<WifiInformationElement>* hidl_ies) {
+    if (!ie_blob || !hidl_ies) {
+        return false;
+    }
+    *hidl_ies = {};
+    const uint8_t* ies_begin = ie_blob;
+    const uint8_t* ies_end = ie_blob + ie_blob_len;
+    const uint8_t* next_ie = ies_begin;
+    using wifi_ie = legacy_hal::wifi_information_element;
+    constexpr size_t kIeHeaderLen = sizeof(wifi_ie);
+    // Each IE should atleast have the header (i.e |id| & |len| fields).
+    while (next_ie + kIeHeaderLen <= ies_end) {
+        const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
+        uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
+        if (next_ie + curr_ie_len > ies_end) {
+            LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void*)next_ie
+                       << ", Curr IE len: " << curr_ie_len
+                       << ", IEs End: " << (void*)ies_end;
+            break;
+        }
+        WifiInformationElement hidl_ie;
+        if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
+            LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id
+                       << ", len: " << legacy_ie.len;
+            break;
+        }
+        hidl_ies->push_back(std::move(hidl_ie));
+        next_ie += curr_ie_len;
+    }
+    // Check if the blob has been fully consumed.
+    if (next_ie != ies_end) {
+        LOG(ERROR) << "Failed to fully parse IE blob. Next IE: "
+                   << (void*)next_ie << ", IEs End: " << (void*)ies_end;
+    }
+    return true;
+}
+
+bool convertLegacyGscanResultToHidl(
+    const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
+    StaScanResult* hidl_scan_result) {
+    if (!hidl_scan_result) {
+        return false;
+    }
+    *hidl_scan_result = {};
+    hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
+    hidl_scan_result->ssid = std::vector<uint8_t>(
+        legacy_scan_result.ssid,
+        legacy_scan_result.ssid + strnlen(legacy_scan_result.ssid,
+                                          sizeof(legacy_scan_result.ssid) - 1));
+    memcpy(hidl_scan_result->bssid.data(), legacy_scan_result.bssid,
+           hidl_scan_result->bssid.size());
+    hidl_scan_result->frequency = legacy_scan_result.channel;
+    hidl_scan_result->rssi = legacy_scan_result.rssi;
+    hidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
+    hidl_scan_result->capability = legacy_scan_result.capability;
+    if (has_ie_data) {
+        std::vector<WifiInformationElement> ies;
+        if (!convertLegacyIeBlobToHidl(
+                reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
+                legacy_scan_result.ie_length, &ies)) {
+            return false;
+        }
+        hidl_scan_result->informationElements = std::move(ies);
+    }
+    return true;
+}
+
+bool convertLegacyCachedGscanResultsToHidl(
+    const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
+    StaScanData* hidl_scan_data) {
+    if (!hidl_scan_data) {
+        return false;
+    }
+    *hidl_scan_data = {};
+    hidl_scan_data->flags = 0;
+    for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
+        if (legacy_cached_scan_result.flags & flag) {
+            hidl_scan_data->flags |=
+                static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
+                    convertLegacyGscanDataFlagToHidl(flag));
+        }
+    }
+    hidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
+
+    CHECK(legacy_cached_scan_result.num_results >= 0 &&
+          legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN);
+    std::vector<StaScanResult> hidl_scan_results;
+    for (int32_t result_idx = 0;
+         result_idx < legacy_cached_scan_result.num_results; result_idx++) {
+        StaScanResult hidl_scan_result;
+        if (!convertLegacyGscanResultToHidl(
+                legacy_cached_scan_result.results[result_idx], false,
+                &hidl_scan_result)) {
+            return false;
+        }
+        hidl_scan_results.push_back(hidl_scan_result);
+    }
+    hidl_scan_data->results = std::move(hidl_scan_results);
+    return true;
+}
+
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
+    const std::vector<legacy_hal::wifi_cached_scan_results>&
+        legacy_cached_scan_results,
+    std::vector<StaScanData>* hidl_scan_datas) {
+    if (!hidl_scan_datas) {
+        return false;
+    }
+    *hidl_scan_datas = {};
+    for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
+        StaScanData hidl_scan_data;
+        if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result,
+                                                   &hidl_scan_data)) {
+            return false;
+        }
+        hidl_scan_datas->push_back(hidl_scan_data);
+    }
+    return true;
+}
+
+WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(
+    legacy_hal::wifi_tx_packet_fate fate) {
+    switch (fate) {
+        case legacy_hal::TX_PKT_FATE_ACKED:
+            return WifiDebugTxPacketFate::ACKED;
+        case legacy_hal::TX_PKT_FATE_SENT:
+            return WifiDebugTxPacketFate::SENT;
+        case legacy_hal::TX_PKT_FATE_FW_QUEUED:
+            return WifiDebugTxPacketFate::FW_QUEUED;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
+            return WifiDebugTxPacketFate::FW_DROP_INVALID;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
+            return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
+            return WifiDebugTxPacketFate::FW_DROP_OTHER;
+        case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
+            return WifiDebugTxPacketFate::DRV_QUEUED;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
+            return WifiDebugTxPacketFate::DRV_DROP_INVALID;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
+            return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
+            return WifiDebugTxPacketFate::DRV_DROP_OTHER;
+    };
+    CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToHidl(
+    legacy_hal::wifi_rx_packet_fate fate) {
+    switch (fate) {
+        case legacy_hal::RX_PKT_FATE_SUCCESS:
+            return WifiDebugRxPacketFate::SUCCESS;
+        case legacy_hal::RX_PKT_FATE_FW_QUEUED:
+            return WifiDebugRxPacketFate::FW_QUEUED;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
+            return WifiDebugRxPacketFate::FW_DROP_FILTER;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
+            return WifiDebugRxPacketFate::FW_DROP_INVALID;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
+            return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
+            return WifiDebugRxPacketFate::FW_DROP_OTHER;
+        case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
+            return WifiDebugRxPacketFate::DRV_QUEUED;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
+            return WifiDebugRxPacketFate::DRV_DROP_FILTER;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
+            return WifiDebugRxPacketFate::DRV_DROP_INVALID;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
+            return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
+            return WifiDebugRxPacketFate::DRV_DROP_OTHER;
+    };
+    CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToHidl(
+    legacy_hal::frame_type type) {
+    switch (type) {
+        case legacy_hal::FRAME_TYPE_UNKNOWN:
+            return WifiDebugPacketFateFrameType::UNKNOWN;
+        case legacy_hal::FRAME_TYPE_ETHERNET_II:
+            return WifiDebugPacketFateFrameType::ETHERNET_II;
+        case legacy_hal::FRAME_TYPE_80211_MGMT:
+            return WifiDebugPacketFateFrameType::MGMT_80211;
+    };
+    CHECK(false) << "Unknown legacy frame type: " << type;
+}
+
+bool convertLegacyDebugPacketFateFrameToHidl(
+    const legacy_hal::frame_info& legacy_frame,
+    WifiDebugPacketFateFrameInfo* hidl_frame) {
+    if (!hidl_frame) {
+        return false;
+    }
+    *hidl_frame = {};
+    hidl_frame->frameType =
+        convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
+    hidl_frame->frameLen = legacy_frame.frame_len;
+    hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
+    hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
+    const uint8_t* frame_begin = reinterpret_cast<const uint8_t*>(
+        legacy_frame.frame_content.ethernet_ii_bytes);
+    hidl_frame->frameContent =
+        std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
+    return true;
+}
+
+bool convertLegacyDebugTxPacketFateToHidl(
+    const legacy_hal::wifi_tx_report& legacy_fate,
+    WifiDebugTxPacketFateReport* hidl_fate) {
+    if (!hidl_fate) {
+        return false;
+    }
+    *hidl_fate = {};
+    hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
+    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
+                                                   &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+    std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
+    if (!hidl_fates) {
+        return false;
+    }
+    *hidl_fates = {};
+    for (const auto& legacy_fate : legacy_fates) {
+        WifiDebugTxPacketFateReport hidl_fate;
+        if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+            return false;
+        }
+        hidl_fates->push_back(hidl_fate);
+    }
+    return true;
+}
+
+bool convertLegacyDebugRxPacketFateToHidl(
+    const legacy_hal::wifi_rx_report& legacy_fate,
+    WifiDebugRxPacketFateReport* hidl_fate) {
+    if (!hidl_fate) {
+        return false;
+    }
+    *hidl_fate = {};
+    hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
+    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
+                                                   &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+    std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
+    if (!hidl_fates) {
+        return false;
+    }
+    *hidl_fates = {};
+    for (const auto& legacy_fate : legacy_fates) {
+        WifiDebugRxPacketFateReport hidl_fate;
+        if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+            return false;
+        }
+        hidl_fates->push_back(hidl_fate);
+    }
+    return true;
+}
+
+bool convertLegacyLinkLayerRadioStatsToHidl(
+    const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
+    V1_3::StaLinkLayerRadioStats* hidl_radio_stat) {
+    if (!hidl_radio_stat) {
+        return false;
+    }
+    *hidl_radio_stat = {};
+
+    hidl_radio_stat->V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
+    hidl_radio_stat->V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
+    hidl_radio_stat->V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
+    hidl_radio_stat->V1_0.onTimeInMsForScan =
+        legacy_radio_stat.stats.on_time_scan;
+    hidl_radio_stat->V1_0.txTimeInMsPerLevel =
+        legacy_radio_stat.tx_time_per_levels;
+    hidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
+    hidl_radio_stat->onTimeInMsForBgScan =
+        legacy_radio_stat.stats.on_time_gscan;
+    hidl_radio_stat->onTimeInMsForRoamScan =
+        legacy_radio_stat.stats.on_time_roam_scan;
+    hidl_radio_stat->onTimeInMsForPnoScan =
+        legacy_radio_stat.stats.on_time_pno_scan;
+    hidl_radio_stat->onTimeInMsForHs20Scan =
+        legacy_radio_stat.stats.on_time_hs20;
+
+    std::vector<V1_3::WifiChannelStats> hidl_channel_stats;
+
+    for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
+        V1_3::WifiChannelStats hidl_channel_stat;
+        hidl_channel_stat.onTimeInMs = channel_stat.on_time;
+        hidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
+        /*
+         * TODO once b/119142899 is fixed,
+         * replace below code with convertLegacyWifiChannelInfoToHidl()
+         */
+        hidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20;
+        hidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq;
+        hidl_channel_stat.channel.centerFreq0 =
+            channel_stat.channel.center_freq0;
+        hidl_channel_stat.channel.centerFreq1 =
+            channel_stat.channel.center_freq1;
+        hidl_channel_stats.push_back(hidl_channel_stat);
+    }
+
+    hidl_radio_stat->channelStats = hidl_channel_stats;
+
+    return true;
+}
+
+bool convertLegacyLinkLayerStatsToHidl(
+    const legacy_hal::LinkLayerStats& legacy_stats,
+    V1_3::StaLinkLayerStats* hidl_stats) {
+    if (!hidl_stats) {
+        return false;
+    }
+    *hidl_stats = {};
+    // iface legacy_stats conversion.
+    hidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx;
+    hidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
+    hidl_stats->iface.wmeBePktStats.rxMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
+    hidl_stats->iface.wmeBePktStats.txMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
+    hidl_stats->iface.wmeBePktStats.lostMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
+    hidl_stats->iface.wmeBePktStats.retries =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
+    hidl_stats->iface.wmeBkPktStats.rxMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
+    hidl_stats->iface.wmeBkPktStats.txMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
+    hidl_stats->iface.wmeBkPktStats.lostMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
+    hidl_stats->iface.wmeBkPktStats.retries =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
+    hidl_stats->iface.wmeViPktStats.rxMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
+    hidl_stats->iface.wmeViPktStats.txMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
+    hidl_stats->iface.wmeViPktStats.lostMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
+    hidl_stats->iface.wmeViPktStats.retries =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
+    hidl_stats->iface.wmeVoPktStats.rxMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
+    hidl_stats->iface.wmeVoPktStats.txMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
+    hidl_stats->iface.wmeVoPktStats.lostMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
+    hidl_stats->iface.wmeVoPktStats.retries =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
+    // radio legacy_stats conversion.
+    std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
+    for (const auto& legacy_radio_stats : legacy_stats.radios) {
+        V1_3::StaLinkLayerRadioStats hidl_radio_stats;
+        if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats,
+                                                    &hidl_radio_stats)) {
+            return false;
+        }
+        hidl_radios_stats.push_back(hidl_radio_stats);
+    }
+    hidl_stats->radios = hidl_radios_stats;
+    // Timestamp in the HAL wrapper here since it's not provided in the legacy
+    // HAL API.
+    hidl_stats->timeStampInMs = uptimeMillis();
+    return true;
+}
+
+bool convertLegacyRoamingCapabilitiesToHidl(
+    const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+    StaRoamingCapabilities* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
+    hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
+    return true;
+}
+
+bool convertHidlRoamingConfigToLegacy(
+    const StaRoamingConfig& hidl_config,
+    legacy_hal::wifi_roaming_config* legacy_config) {
+    if (!legacy_config) {
+        return false;
+    }
+    *legacy_config = {};
+    if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
+        hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
+        return false;
+    }
+    legacy_config->num_blacklist_bssid = hidl_config.bssidBlacklist.size();
+    uint32_t i = 0;
+    for (const auto& bssid : hidl_config.bssidBlacklist) {
+        CHECK(bssid.size() == sizeof(legacy_hal::mac_addr));
+        memcpy(legacy_config->blacklist_bssid[i++], bssid.data(), bssid.size());
+    }
+    legacy_config->num_whitelist_ssid = hidl_config.ssidWhitelist.size();
+    i = 0;
+    for (const auto& ssid : hidl_config.ssidWhitelist) {
+        CHECK(ssid.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
+        legacy_config->whitelist_ssid[i].length = ssid.size();
+        memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data(),
+               ssid.size());
+        i++;
+    }
+    return true;
+}
+
+legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
+    StaRoamingState state) {
+    switch (state) {
+        case StaRoamingState::ENABLED:
+            return legacy_hal::ROAMING_ENABLE;
+        case StaRoamingState::DISABLED:
+            return legacy_hal::ROAMING_DISABLE;
+    };
+    CHECK(false);
+}
+
+legacy_hal::NanMatchAlg convertHidlNanMatchAlgToLegacy(NanMatchAlg type) {
+    switch (type) {
+        case NanMatchAlg::MATCH_ONCE:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
+        case NanMatchAlg::MATCH_CONTINUOUS:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
+        case NanMatchAlg::MATCH_NEVER:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanPublishType convertHidlNanPublishTypeToLegacy(
+    NanPublishType type) {
+    switch (type) {
+        case NanPublishType::UNSOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
+        case NanPublishType::SOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
+        case NanPublishType::UNSOLICITED_SOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanTxType convertHidlNanTxTypeToLegacy(NanTxType type) {
+    switch (type) {
+        case NanTxType::BROADCAST:
+            return legacy_hal::NAN_TX_TYPE_BROADCAST;
+        case NanTxType::UNICAST:
+            return legacy_hal::NAN_TX_TYPE_UNICAST;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanSubscribeType convertHidlNanSubscribeTypeToLegacy(
+    NanSubscribeType type) {
+    switch (type) {
+        case NanSubscribeType::PASSIVE:
+            return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
+        case NanSubscribeType::ACTIVE:
+            return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanSRFType convertHidlNanSrfTypeToLegacy(NanSrfType type) {
+    switch (type) {
+        case NanSrfType::BLOOM_FILTER:
+            return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
+        case NanSrfType::PARTIAL_MAC_ADDR:
+            return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanDataPathChannelCfg convertHidlNanDataPathChannelCfgToLegacy(
+    NanDataPathChannelCfg type) {
+    switch (type) {
+        case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED:
+            return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED;
+        case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP:
+            return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP;
+        case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP:
+            return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP;
+    }
+    CHECK(false);
+}
+
+NanStatusType convertLegacyNanStatusTypeToHidl(legacy_hal::NanStatusType type) {
+    switch (type) {
+        case legacy_hal::NAN_STATUS_SUCCESS:
+            return NanStatusType::SUCCESS;
+        case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
+            return NanStatusType::INTERNAL_FAILURE;
+        case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
+            return NanStatusType::PROTOCOL_FAILURE;
+        case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
+            return NanStatusType::INVALID_SESSION_ID;
+        case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
+            return NanStatusType::NO_RESOURCES_AVAILABLE;
+        case legacy_hal::NAN_STATUS_INVALID_PARAM:
+            return NanStatusType::INVALID_ARGS;
+        case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
+            return NanStatusType::INVALID_PEER_ID;
+        case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
+            return NanStatusType::INVALID_NDP_ID;
+        case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
+            return NanStatusType::NAN_NOT_ALLOWED;
+        case legacy_hal::NAN_STATUS_NO_OTA_ACK:
+            return NanStatusType::NO_OTA_ACK;
+        case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
+            return NanStatusType::ALREADY_ENABLED;
+        case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
+            return NanStatusType::FOLLOWUP_TX_QUEUE_FULL;
+        case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
+            return NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
+    }
+    CHECK(false);
+}
+
+void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
+                            size_t max_len, WifiNanStatus* wifiNanStatus) {
+    wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(type);
+    wifiNanStatus->description = safeConvertChar(str, max_len);
+}
+
+bool convertHidlNanEnableRequestToLegacy(
+    const NanEnableRequest& hidl_request,
+    legacy_hal::NanEnableRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanEnableRequestToLegacy: null legacy_request";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->config_2dot4g_support = 1;
+    legacy_request->support_2dot4g_val =
+        hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_support_5g = 1;
+    legacy_request->support_5g_val =
+        hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_hop_count_limit = 1;
+    legacy_request->hop_count_limit_val = hidl_request.hopCountMax;
+    legacy_request->master_pref = hidl_request.configParams.masterPref;
+    legacy_request->discovery_indication_cfg = 0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.configParams.disableDiscoveryAddressChangeIndication ? 0x1
+                                                                          : 0x0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
+    legacy_request->config_sid_beacon = 1;
+    if (hidl_request.configParams.numberOfPublishServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+                      "numberOfPublishServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->sid_beacon_val =
+        (hidl_request.configParams.includePublishServiceIdsInBeacon ? 0x1
+                                                                    : 0x0) |
+        (hidl_request.configParams.numberOfPublishServiceIdsInBeacon << 1);
+    legacy_request->config_subscribe_sid_beacon = 1;
+    if (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+                      "numberOfSubscribeServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->subscribe_sid_beacon_val =
+        (hidl_request.configParams.includeSubscribeServiceIdsInBeacon ? 0x1
+                                                                      : 0x0) |
+        (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
+    legacy_request->config_rssi_window_size = 1;
+    legacy_request->rssi_window_size_val =
+        hidl_request.configParams.rssiWindowSize;
+    legacy_request->config_disc_mac_addr_randomization = 1;
+    legacy_request->disc_mac_addr_rand_interval_sec =
+        hidl_request.configParams.macAddressRandomizationIntervalSec;
+    legacy_request->config_2dot4g_rssi_close = 1;
+    if (hidl_request.configParams.bandSpecificConfig.size() != 3) {
+        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+                      "bandSpecificConfig.size() != 3";
+        return false;
+    }
+    legacy_request->rssi_close_2dot4g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .rssiClose;
+    legacy_request->config_2dot4g_rssi_middle = 1;
+    legacy_request->rssi_middle_2dot4g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .rssiMiddle;
+    legacy_request->config_2dot4g_rssi_proximity = 1;
+    legacy_request->rssi_proximity_2dot4g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .rssiCloseProximity;
+    legacy_request->config_scan_params = 1;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .scanPeriodSec;
+    legacy_request->config_dw.config_2dot4g_dw_band =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_2dot4g_interval_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .discoveryWindowIntervalVal;
+    legacy_request->config_5g_rssi_close = 1;
+    legacy_request->rssi_close_5g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .rssiClose;
+    legacy_request->config_5g_rssi_middle = 1;
+    legacy_request->rssi_middle_5g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .rssiMiddle;
+    legacy_request->config_5g_rssi_close_proximity = 1;
+    legacy_request->rssi_close_proximity_5g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .rssiCloseProximity;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .scanPeriodSec;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .scanPeriodSec;
+    legacy_request->config_dw.config_5g_dw_band =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_5g_interval_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .discoveryWindowIntervalVal;
+    if (hidl_request.debugConfigs.validClusterIdVals) {
+        legacy_request->cluster_low =
+            hidl_request.debugConfigs.clusterIdBottomRangeVal;
+        legacy_request->cluster_high =
+            hidl_request.debugConfigs.clusterIdTopRangeVal;
+    } else {  // need 'else' since not configurable in legacy HAL
+        legacy_request->cluster_low = 0x0000;
+        legacy_request->cluster_high = 0xFFFF;
+    }
+    legacy_request->config_intf_addr =
+        hidl_request.debugConfigs.validIntfAddrVal;
+    memcpy(legacy_request->intf_addr_val,
+           hidl_request.debugConfigs.intfAddrVal.data(), 6);
+    legacy_request->config_oui = hidl_request.debugConfigs.validOuiVal;
+    legacy_request->oui_val = hidl_request.debugConfigs.ouiVal;
+    legacy_request->config_random_factor_force =
+        hidl_request.debugConfigs.validRandomFactorForceVal;
+    legacy_request->random_factor_force_val =
+        hidl_request.debugConfigs.randomFactorForceVal;
+    legacy_request->config_hop_count_force =
+        hidl_request.debugConfigs.validHopCountForceVal;
+    legacy_request->hop_count_force_val =
+        hidl_request.debugConfigs.hopCountForceVal;
+    legacy_request->config_24g_channel =
+        hidl_request.debugConfigs.validDiscoveryChannelVal;
+    legacy_request->channel_24g_val =
+        hidl_request.debugConfigs
+            .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_channel =
+        hidl_request.debugConfigs.validDiscoveryChannelVal;
+    legacy_request->channel_5g_val =
+        hidl_request.debugConfigs
+            .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_2dot4g_beacons =
+        hidl_request.debugConfigs.validUseBeaconsInBandVal;
+    legacy_request->beacon_2dot4g_val =
+        hidl_request.debugConfigs
+            .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_beacons =
+        hidl_request.debugConfigs.validUseBeaconsInBandVal;
+    legacy_request->beacon_5g_val =
+        hidl_request.debugConfigs
+            .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_2dot4g_sdf =
+        hidl_request.debugConfigs.validUseSdfInBandVal;
+    legacy_request->sdf_2dot4g_val =
+        hidl_request.debugConfigs
+            .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_sdf =
+        hidl_request.debugConfigs.validUseSdfInBandVal;
+    legacy_request->sdf_5g_val =
+        hidl_request.debugConfigs
+            .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+
+    /* TODO: b/145609058
+     * Missing updates needed to legacy_hal::NanEnableRequest and conversion to
+     * it for 6GHz band */
+
+    return true;
+}
+
+bool convertHidlNanEnableRequest_1_4ToLegacy(
+    const NanEnableRequest& hidl_request1,
+    const V1_2::NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanEnableRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanEnableRequest_1_4ToLegacy: null legacy_request";
+        return false;
+    }
+
+    *legacy_request = {};
+    if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
+        return false;
+    }
+
+    legacy_request->config_discovery_beacon_int = 1;
+    legacy_request->discovery_beacon_interval =
+        hidl_request2.discoveryBeaconIntervalMs;
+    legacy_request->config_nss = 1;
+    legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+    legacy_request->config_dw_early_termination = 1;
+    legacy_request->enable_dw_termination =
+        hidl_request2.enableDiscoveryWindowEarlyTermination;
+    legacy_request->config_enable_ranging = 1;
+    legacy_request->enable_ranging = hidl_request2.enableRanging;
+
+    return true;
+}
+
+bool convertHidlNanPublishRequestToLegacy(
+    const NanPublishRequest& hidl_request,
+    legacy_hal::NanPublishRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanPublishRequestToLegacy: null legacy_request";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
+    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
+    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
+    legacy_request->publish_count = hidl_request.baseConfigs.discoveryCount;
+    legacy_request->service_name_len =
+        hidl_request.baseConfigs.serviceName.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_name_len "
+                      "too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name,
+           hidl_request.baseConfigs.serviceName.data(),
+           legacy_request->service_name_len);
+    legacy_request->publish_match_indicator = convertHidlNanMatchAlgToLegacy(
+        hidl_request.baseConfigs.discoveryMatchIndicator);
+    legacy_request->service_specific_info_len =
+        hidl_request.baseConfigs.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len >
+        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info,
+           hidl_request.baseConfigs.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+        hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len >
+        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->rx_match_filter_len =
+        hidl_request.baseConfigs.rxMatchFilter.size();
+    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "rx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->rx_match_filter,
+           hidl_request.baseConfigs.rxMatchFilter.data(),
+           legacy_request->rx_match_filter_len);
+    legacy_request->tx_match_filter_len =
+        hidl_request.baseConfigs.txMatchFilter.size();
+    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "tx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->tx_match_filter,
+           hidl_request.baseConfigs.txMatchFilter.data(),
+           legacy_request->tx_match_filter_len);
+    legacy_request->rssi_threshold_flag =
+        hidl_request.baseConfigs.useRssiThreshold;
+    legacy_request->recv_indication_cfg = 0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
+                                                                       : 0x0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+    legacy_request->recv_indication_cfg |= 0x8;
+    legacy_request->cipher_type =
+        (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
+    if (hidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+            hidl_request.baseConfigs.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len !=
+            NAN_PMK_INFO_LEN) {
+            LOG(ERROR)
+                << "convertHidlNanPublishRequestToLegacy: invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               hidl_request.baseConfigs.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+            hidl_request.baseConfigs.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.baseConfigs.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->sdea_params.security_cfg =
+        (hidl_request.baseConfigs.securityConfig.securityType !=
+         NanDataPathSecurityType::OPEN)
+            ? legacy_hal::NAN_DP_CONFIG_SECURITY
+            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->sdea_params.ranging_state =
+        hidl_request.baseConfigs.rangingRequired
+            ? legacy_hal::NAN_RANGING_ENABLE
+            : legacy_hal::NAN_RANGING_DISABLE;
+    legacy_request->ranging_cfg.ranging_interval_msec =
+        hidl_request.baseConfigs.rangingIntervalMsec;
+    legacy_request->ranging_cfg.config_ranging_indications =
+        hidl_request.baseConfigs.configRangingIndications;
+    legacy_request->ranging_cfg.distance_ingress_mm =
+        hidl_request.baseConfigs.distanceIngressCm * 10;
+    legacy_request->ranging_cfg.distance_egress_mm =
+        hidl_request.baseConfigs.distanceEgressCm * 10;
+    legacy_request->ranging_auto_response =
+        hidl_request.baseConfigs.rangingRequired
+            ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+            : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+    legacy_request->sdea_params.range_report =
+        legacy_hal::NAN_DISABLE_RANGE_REPORT;
+    legacy_request->publish_type =
+        convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
+    legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
+    legacy_request->service_responder_policy =
+        hidl_request.autoAcceptDataPathRequests
+            ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
+            : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
+
+    return true;
+}
+
+bool convertHidlNanSubscribeRequestToLegacy(
+    const NanSubscribeRequest& hidl_request,
+    legacy_hal::NanSubscribeRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
+    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
+    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
+    legacy_request->subscribe_count = hidl_request.baseConfigs.discoveryCount;
+    legacy_request->service_name_len =
+        hidl_request.baseConfigs.serviceName.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name,
+           hidl_request.baseConfigs.serviceName.data(),
+           legacy_request->service_name_len);
+    legacy_request->subscribe_match_indicator = convertHidlNanMatchAlgToLegacy(
+        hidl_request.baseConfigs.discoveryMatchIndicator);
+    legacy_request->service_specific_info_len =
+        hidl_request.baseConfigs.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len >
+        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info,
+           hidl_request.baseConfigs.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+        hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len >
+        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->rx_match_filter_len =
+        hidl_request.baseConfigs.rxMatchFilter.size();
+    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "rx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->rx_match_filter,
+           hidl_request.baseConfigs.rxMatchFilter.data(),
+           legacy_request->rx_match_filter_len);
+    legacy_request->tx_match_filter_len =
+        hidl_request.baseConfigs.txMatchFilter.size();
+    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "tx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->tx_match_filter,
+           hidl_request.baseConfigs.txMatchFilter.data(),
+           legacy_request->tx_match_filter_len);
+    legacy_request->rssi_threshold_flag =
+        hidl_request.baseConfigs.useRssiThreshold;
+    legacy_request->recv_indication_cfg = 0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
+                                                                       : 0x0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+    legacy_request->cipher_type =
+        (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
+    if (hidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+            hidl_request.baseConfigs.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len !=
+            NAN_PMK_INFO_LEN) {
+            LOG(ERROR)
+                << "convertHidlNanSubscribeRequestToLegacy: invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               hidl_request.baseConfigs.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+            hidl_request.baseConfigs.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.baseConfigs.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->sdea_params.security_cfg =
+        (hidl_request.baseConfigs.securityConfig.securityType !=
+         NanDataPathSecurityType::OPEN)
+            ? legacy_hal::NAN_DP_CONFIG_SECURITY
+            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->sdea_params.ranging_state =
+        hidl_request.baseConfigs.rangingRequired
+            ? legacy_hal::NAN_RANGING_ENABLE
+            : legacy_hal::NAN_RANGING_DISABLE;
+    legacy_request->ranging_cfg.ranging_interval_msec =
+        hidl_request.baseConfigs.rangingIntervalMsec;
+    legacy_request->ranging_cfg.config_ranging_indications =
+        hidl_request.baseConfigs.configRangingIndications;
+    legacy_request->ranging_cfg.distance_ingress_mm =
+        hidl_request.baseConfigs.distanceIngressCm * 10;
+    legacy_request->ranging_cfg.distance_egress_mm =
+        hidl_request.baseConfigs.distanceEgressCm * 10;
+    legacy_request->ranging_auto_response =
+        hidl_request.baseConfigs.rangingRequired
+            ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+            : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+    legacy_request->sdea_params.range_report =
+        legacy_hal::NAN_DISABLE_RANGE_REPORT;
+    legacy_request->subscribe_type =
+        convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
+    legacy_request->serviceResponseFilter =
+        convertHidlNanSrfTypeToLegacy(hidl_request.srfType);
+    legacy_request->serviceResponseInclude =
+        hidl_request.srfRespondIfInAddressSet
+            ? legacy_hal::NAN_SRF_INCLUDE_RESPOND
+            : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
+    legacy_request->useServiceResponseFilter =
+        hidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF
+                                  : legacy_hal::NAN_DO_NOT_USE_SRF;
+    legacy_request->ssiRequiredForMatchIndication =
+        hidl_request.isSsiRequiredForMatch
+            ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND
+            : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
+    legacy_request->num_intf_addr_present = hidl_request.intfAddr.size();
+    if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "num_intf_addr_present - too many";
+        return false;
+    }
+    for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
+        memcpy(legacy_request->intf_addr[i], hidl_request.intfAddr[i].data(),
+               6);
+    }
+
+    return true;
+}
+
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+    const NanTransmitFollowupRequest& hidl_request,
+    legacy_hal::NanTransmitFollowupRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
+    legacy_request->requestor_instance_id = hidl_request.peerId;
+    memcpy(legacy_request->addr, hidl_request.addr.data(), 6);
+    legacy_request->priority = hidl_request.isHighPriority
+                                   ? legacy_hal::NAN_TX_PRIORITY_HIGH
+                                   : legacy_hal::NAN_TX_PRIORITY_NORMAL;
+    legacy_request->dw_or_faw = hidl_request.shouldUseDiscoveryWindow
+                                    ? legacy_hal::NAN_TRANSMIT_IN_DW
+                                    : legacy_hal::NAN_TRANSMIT_IN_FAW;
+    legacy_request->service_specific_info_len =
+        hidl_request.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len >
+        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info,
+           hidl_request.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+        hidl_request.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len >
+        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           hidl_request.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->recv_indication_cfg =
+        hidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
+
+    return true;
+}
+
+bool convertHidlNanConfigRequestToLegacy(
+    const NanConfigRequest& hidl_request,
+    legacy_hal::NanConfigRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown
+    // defaults
+    legacy_request->master_pref = hidl_request.masterPref;
+    legacy_request->discovery_indication_cfg = 0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.disableStartedClusterIndication ? 0x2 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.disableJoinedClusterIndication ? 0x4 : 0x0;
+    legacy_request->config_sid_beacon = 1;
+    if (hidl_request.numberOfPublishServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
+                      "numberOfPublishServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->sid_beacon =
+        (hidl_request.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
+        (hidl_request.numberOfPublishServiceIdsInBeacon << 1);
+    legacy_request->config_subscribe_sid_beacon = 1;
+    if (hidl_request.numberOfSubscribeServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
+                      "numberOfSubscribeServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->subscribe_sid_beacon_val =
+        (hidl_request.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
+        (hidl_request.numberOfSubscribeServiceIdsInBeacon << 1);
+    legacy_request->config_rssi_window_size = 1;
+    legacy_request->rssi_window_size_val = hidl_request.rssiWindowSize;
+    legacy_request->config_disc_mac_addr_randomization = 1;
+    legacy_request->disc_mac_addr_rand_interval_sec =
+        hidl_request.macAddressRandomizationIntervalSec;
+    /* TODO : missing
+    legacy_request->config_2dot4g_rssi_close = 1;
+    legacy_request->rssi_close_2dot4g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
+    legacy_request->config_2dot4g_rssi_middle = 1;
+    legacy_request->rssi_middle_2dot4g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
+    legacy_request->config_2dot4g_rssi_proximity = 1;
+    legacy_request->rssi_proximity_2dot4g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiCloseProximity;
+    */
+    legacy_request->config_scan_params = 1;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .scanPeriodSec;
+    legacy_request->config_dw.config_2dot4g_dw_band =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_2dot4g_interval_val =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .discoveryWindowIntervalVal;
+    /* TODO: missing
+    legacy_request->config_5g_rssi_close = 1;
+    legacy_request->rssi_close_5g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
+    legacy_request->config_5g_rssi_middle = 1;
+    legacy_request->rssi_middle_5g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
+    */
+    legacy_request->config_5g_rssi_close_proximity = 1;
+    legacy_request->rssi_close_proximity_5g_val =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .rssiCloseProximity;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .scanPeriodSec;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .scanPeriodSec;
+    legacy_request->config_dw.config_5g_dw_band =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_5g_interval_val =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .discoveryWindowIntervalVal;
+    /* TODO: b/145609058
+     * Missing updates needed to legacy_hal::NanConfigRequest and conversion to
+     * it for 6GHz band */
+
+    return true;
+}
+
+bool convertHidlNanConfigRequest_1_4ToLegacy(
+    const NanConfigRequest& hidl_request1,
+    const V1_2::NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanConfigRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanConfigRequest_1_4ToLegacy: legacy_request "
+                      "is null";
+        return false;
+    }
+
+    *legacy_request = {};
+    if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
+        return false;
+    }
+
+    legacy_request->config_discovery_beacon_int = 1;
+    legacy_request->discovery_beacon_interval =
+        hidl_request2.discoveryBeaconIntervalMs;
+    legacy_request->config_nss = 1;
+    legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+    legacy_request->config_dw_early_termination = 1;
+    legacy_request->enable_dw_termination =
+        hidl_request2.enableDiscoveryWindowEarlyTermination;
+    legacy_request->config_enable_ranging = 1;
+    legacy_request->enable_ranging = hidl_request2.enableRanging;
+
+    return true;
+}
+
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+    const NanInitiateDataPathRequest& hidl_request,
+    legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->requestor_instance_id = hidl_request.peerId;
+    memcpy(legacy_request->peer_disc_mac_addr,
+           hidl_request.peerDiscMacAddr.data(), 6);
+    legacy_request->channel_request_type =
+        convertHidlNanDataPathChannelCfgToLegacy(
+            hidl_request.channelRequestType);
+    legacy_request->channel = hidl_request.channel;
+    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "ifaceName too long";
+        return false;
+    }
+    strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(),
+            IFNAMSIZ + 1);
+    legacy_request->ndp_cfg.security_cfg =
+        (hidl_request.securityConfig.securityType !=
+         NanDataPathSecurityType::OPEN)
+            ? legacy_hal::NAN_DP_CONFIG_SECURITY
+            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "ndp_app_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+           legacy_request->app_info.ndp_app_info_len);
+    legacy_request->cipher_type =
+        (unsigned int)hidl_request.securityConfig.cipherType;
+    if (hidl_request.securityConfig.securityType ==
+        NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+            hidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len !=
+            NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               hidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+            hidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name,
+           hidl_request.serviceNameOutOfBand.data(),
+           legacy_request->service_name_len);
+
+    return true;
+}
+
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+    const NanRespondToDataPathIndicationRequest& hidl_request,
+    legacy_hal::NanDataPathIndicationResponse* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->rsp_code = hidl_request.acceptRequest
+                                   ? legacy_hal::NAN_DP_REQUEST_ACCEPT
+                                   : legacy_hal::NAN_DP_REQUEST_REJECT;
+    legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
+    if (strnlen(hidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "ifaceName too long";
+        return false;
+    }
+    strncpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str(),
+            IFNAMSIZ + 1);
+    legacy_request->ndp_cfg.security_cfg =
+        (hidl_request.securityConfig.securityType !=
+         NanDataPathSecurityType::OPEN)
+            ? legacy_hal::NAN_DP_CONFIG_SECURITY
+            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "ndp_app_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+           legacy_request->app_info.ndp_app_info_len);
+    legacy_request->cipher_type =
+        (unsigned int)hidl_request.securityConfig.cipherType;
+    if (hidl_request.securityConfig.securityType ==
+        NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+            hidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len !=
+            NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               hidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+            hidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name,
+           hidl_request.serviceNameOutOfBand.data(),
+           legacy_request->service_name_len);
+
+    return true;
+}
+
+bool convertLegacyNanResponseHeaderToHidl(
+    const legacy_hal::NanResponseMsg& legacy_response,
+    WifiNanStatus* wifiNanStatus) {
+    if (!wifiNanStatus) {
+        LOG(ERROR)
+            << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
+        return false;
+    }
+    *wifiNanStatus = {};
+
+    convertToWifiNanStatus(legacy_response.status, legacy_response.nan_error,
+                           sizeof(legacy_response.nan_error), wifiNanStatus);
+    return true;
+}
+
+bool convertLegacyNanCapabilitiesResponseToHidl(
+    const legacy_hal::NanCapabilities& legacy_response,
+    NanCapabilities* hidl_response) {
+    if (!hidl_response) {
+        LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: "
+                      "hidl_response is null";
+        return false;
+    }
+    *hidl_response = {};
+
+    hidl_response->maxConcurrentClusters =
+        legacy_response.max_concurrent_nan_clusters;
+    hidl_response->maxPublishes = legacy_response.max_publishes;
+    hidl_response->maxSubscribes = legacy_response.max_subscribes;
+    hidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
+    hidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
+    hidl_response->maxTotalMatchFilterLen =
+        legacy_response.max_total_match_filter_len;
+    hidl_response->maxServiceSpecificInfoLen =
+        legacy_response.max_service_specific_info_len;
+    hidl_response->maxExtendedServiceSpecificInfoLen =
+        legacy_response.max_sdea_service_specific_info_len;
+    hidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
+    hidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
+    hidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
+    hidl_response->maxQueuedTransmitFollowupMsgs =
+        legacy_response.max_queued_transmit_followup_msgs;
+    hidl_response->maxSubscribeInterfaceAddresses =
+        legacy_response.max_subscribe_address;
+    hidl_response->supportedCipherSuites =
+        legacy_response.cipher_suites_supported;
+
+    return true;
+}
+
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+                                    NanMatchInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+    hidl_ind->peerId = legacy_ind.requestor_instance_id;
+    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
+    hidl_ind->serviceSpecificInfo =
+        std::vector<uint8_t>(legacy_ind.service_specific_info,
+                             legacy_ind.service_specific_info +
+                                 legacy_ind.service_specific_info_len);
+    hidl_ind->extendedServiceSpecificInfo =
+        std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
+                             legacy_ind.sdea_service_specific_info +
+                                 legacy_ind.sdea_service_specific_info_len);
+    hidl_ind->matchFilter = std::vector<uint8_t>(
+        legacy_ind.sdf_match_filter,
+        legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
+    hidl_ind->matchOccuredInBeaconFlag = legacy_ind.match_occured_flag == 1;
+    hidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
+    hidl_ind->rssiValue = legacy_ind.rssi_value;
+    hidl_ind->peerCipherType = (NanCipherSuiteType)legacy_ind.peer_cipher_type;
+    hidl_ind->peerRequiresSecurityEnabledInNdp =
+        legacy_ind.peer_sdea_params.security_cfg ==
+        legacy_hal::NAN_DP_CONFIG_SECURITY;
+    hidl_ind->peerRequiresRanging = legacy_ind.peer_sdea_params.ranging_state ==
+                                    legacy_hal::NAN_RANGING_ENABLE;
+    hidl_ind->rangingMeasurementInCm =
+        legacy_ind.range_info.range_measurement_mm / 10;
+    hidl_ind->rangingIndicationType = legacy_ind.range_info.ranging_event_type;
+
+    return true;
+}
+
+bool convertLegacyNanFollowupIndToHidl(
+    const legacy_hal::NanFollowupInd& legacy_ind,
+    NanFollowupReceivedInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+    hidl_ind->peerId = legacy_ind.requestor_instance_id;
+    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
+    hidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
+    hidl_ind->serviceSpecificInfo =
+        std::vector<uint8_t>(legacy_ind.service_specific_info,
+                             legacy_ind.service_specific_info +
+                                 legacy_ind.service_specific_info_len);
+    hidl_ind->extendedServiceSpecificInfo =
+        std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
+                             legacy_ind.sdea_service_specific_info +
+                                 legacy_ind.sdea_service_specific_info_len);
+
+    return true;
+}
+
+bool convertLegacyNanDataPathRequestIndToHidl(
+    const legacy_hal::NanDataPathRequestInd& legacy_ind,
+    NanDataPathRequestInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR)
+            << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
+    hidl_ind->peerDiscMacAddr =
+        hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
+    hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
+    hidl_ind->securityRequired =
+        legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
+    hidl_ind->appInfo =
+        std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
+                             legacy_ind.app_info.ndp_app_info +
+                                 legacy_ind.app_info.ndp_app_info_len);
+
+    return true;
+}
+
+bool convertLegacyNdpChannelInfoToHidl(
+    const legacy_hal::NanChannelInfo& legacy_struct,
+    V1_2::NanDataPathChannelInfo* hidl_struct) {
+    if (!hidl_struct) {
+        LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
+        return false;
+    }
+    *hidl_struct = {};
+
+    hidl_struct->channelFreq = legacy_struct.channel;
+    hidl_struct->channelBandwidth = convertLegacyWifiChannelWidthToHidl(
+        (legacy_hal::wifi_channel_width)legacy_struct.bandwidth);
+    hidl_struct->numSpatialStreams = legacy_struct.nss;
+
+    return true;
+}
+
+bool convertLegacyNanDataPathConfirmIndToHidl(
+    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+    V1_2::NanDataPathConfirmInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR)
+            << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
+    hidl_ind->V1_0.dataPathSetupSuccess =
+        legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
+    hidl_ind->V1_0.peerNdiMacAddr =
+        hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
+    hidl_ind->V1_0.appInfo =
+        std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
+                             legacy_ind.app_info.ndp_app_info +
+                                 legacy_ind.app_info.ndp_app_info_len);
+    hidl_ind->V1_0.status.status =
+        convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
+    hidl_ind->V1_0.status.description = "";  // TODO: b/34059183
+
+    std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
+    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+        V1_2::NanDataPathChannelInfo hidl_struct;
+        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
+                                               &hidl_struct)) {
+            return false;
+        }
+        channelInfo.push_back(hidl_struct);
+    }
+    hidl_ind->channelInfo = channelInfo;
+
+    return true;
+}
+
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+    const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+    V1_2::NanDataPathScheduleUpdateInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
+                      "hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->peerDiscoveryAddress =
+        hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
+    std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
+    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+        V1_2::NanDataPathChannelInfo hidl_struct;
+        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
+                                               &hidl_struct)) {
+            return false;
+        }
+        channelInfo.push_back(hidl_struct);
+    }
+    hidl_ind->channelInfo = channelInfo;
+    std::vector<uint32_t> ndpInstanceIds;
+    for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
+        ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
+    }
+    hidl_ind->ndpInstanceIds = ndpInstanceIds;
+
+    return true;
+}
+
+legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(RttType type) {
+    switch (type) {
+        case RttType::ONE_SIDED:
+            return legacy_hal::RTT_TYPE_1_SIDED;
+        case RttType::TWO_SIDED:
+            return legacy_hal::RTT_TYPE_2_SIDED;
+    };
+    CHECK(false);
+}
+
+RttType convertLegacyRttTypeToHidl(legacy_hal::wifi_rtt_type type) {
+    switch (type) {
+        case legacy_hal::RTT_TYPE_1_SIDED:
+            return RttType::ONE_SIDED;
+        case legacy_hal::RTT_TYPE_2_SIDED:
+            return RttType::TWO_SIDED;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::rtt_peer_type convertHidlRttPeerTypeToLegacy(RttPeerType type) {
+    switch (type) {
+        case RttPeerType::AP:
+            return legacy_hal::RTT_PEER_AP;
+        case RttPeerType::STA:
+            return legacy_hal::RTT_PEER_STA;
+        case RttPeerType::P2P_GO:
+            return legacy_hal::RTT_PEER_P2P_GO;
+        case RttPeerType::P2P_CLIENT:
+            return legacy_hal::RTT_PEER_P2P_CLIENT;
+        case RttPeerType::NAN:
+            return legacy_hal::RTT_PEER_NAN;
+    };
+    CHECK(false);
+}
+
+legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(
+    WifiChannelWidthInMhz type) {
+    switch (type) {
+        case WifiChannelWidthInMhz::WIDTH_20:
+            return legacy_hal::WIFI_CHAN_WIDTH_20;
+        case WifiChannelWidthInMhz::WIDTH_40:
+            return legacy_hal::WIFI_CHAN_WIDTH_40;
+        case WifiChannelWidthInMhz::WIDTH_80:
+            return legacy_hal::WIFI_CHAN_WIDTH_80;
+        case WifiChannelWidthInMhz::WIDTH_160:
+            return legacy_hal::WIFI_CHAN_WIDTH_160;
+        case WifiChannelWidthInMhz::WIDTH_80P80:
+            return legacy_hal::WIFI_CHAN_WIDTH_80P80;
+        case WifiChannelWidthInMhz::WIDTH_5:
+            return legacy_hal::WIFI_CHAN_WIDTH_5;
+        case WifiChannelWidthInMhz::WIDTH_10:
+            return legacy_hal::WIFI_CHAN_WIDTH_10;
+        case WifiChannelWidthInMhz::WIDTH_INVALID:
+            return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
+    };
+    CHECK(false);
+}
+
+WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
+    legacy_hal::wifi_channel_width type) {
+    switch (type) {
+        case legacy_hal::WIFI_CHAN_WIDTH_20:
+            return WifiChannelWidthInMhz::WIDTH_20;
+        case legacy_hal::WIFI_CHAN_WIDTH_40:
+            return WifiChannelWidthInMhz::WIDTH_40;
+        case legacy_hal::WIFI_CHAN_WIDTH_80:
+            return WifiChannelWidthInMhz::WIDTH_80;
+        case legacy_hal::WIFI_CHAN_WIDTH_160:
+            return WifiChannelWidthInMhz::WIDTH_160;
+        case legacy_hal::WIFI_CHAN_WIDTH_80P80:
+            return WifiChannelWidthInMhz::WIDTH_80P80;
+        case legacy_hal::WIFI_CHAN_WIDTH_5:
+            return WifiChannelWidthInMhz::WIDTH_5;
+        case legacy_hal::WIFI_CHAN_WIDTH_10:
+            return WifiChannelWidthInMhz::WIDTH_10;
+        case legacy_hal::WIFI_CHAN_WIDTH_INVALID:
+            return WifiChannelWidthInMhz::WIDTH_INVALID;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(RttPreamble type) {
+    switch (type) {
+        case RttPreamble::LEGACY:
+            return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
+        case RttPreamble::HT:
+            return legacy_hal::WIFI_RTT_PREAMBLE_HT;
+        case RttPreamble::VHT:
+            return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
+        case RttPreamble::HE:
+            return legacy_hal::WIFI_RTT_PREAMBLE_HE;
+    };
+    CHECK(false);
+}
+
+RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
+    switch (type) {
+        case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
+            return RttPreamble::LEGACY;
+        case legacy_hal::WIFI_RTT_PREAMBLE_HT:
+            return RttPreamble::HT;
+        case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
+            return RttPreamble::VHT;
+        case legacy_hal::WIFI_RTT_PREAMBLE_HE:
+            return RttPreamble::HE;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(RttBw type) {
+    switch (type) {
+        case RttBw::BW_5MHZ:
+            return legacy_hal::WIFI_RTT_BW_5;
+        case RttBw::BW_10MHZ:
+            return legacy_hal::WIFI_RTT_BW_10;
+        case RttBw::BW_20MHZ:
+            return legacy_hal::WIFI_RTT_BW_20;
+        case RttBw::BW_40MHZ:
+            return legacy_hal::WIFI_RTT_BW_40;
+        case RttBw::BW_80MHZ:
+            return legacy_hal::WIFI_RTT_BW_80;
+        case RttBw::BW_160MHZ:
+            return legacy_hal::WIFI_RTT_BW_160;
+    };
+    CHECK(false);
+}
+
+RttBw convertLegacyRttBwToHidl(legacy_hal::wifi_rtt_bw type) {
+    switch (type) {
+        case legacy_hal::WIFI_RTT_BW_5:
+            return RttBw::BW_5MHZ;
+        case legacy_hal::WIFI_RTT_BW_10:
+            return RttBw::BW_10MHZ;
+        case legacy_hal::WIFI_RTT_BW_20:
+            return RttBw::BW_20MHZ;
+        case legacy_hal::WIFI_RTT_BW_40:
+            return RttBw::BW_40MHZ;
+        case legacy_hal::WIFI_RTT_BW_80:
+            return RttBw::BW_80MHZ;
+        case legacy_hal::WIFI_RTT_BW_160:
+            return RttBw::BW_160MHZ;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(
+    RttMotionPattern type) {
+    switch (type) {
+        case RttMotionPattern::NOT_EXPECTED:
+            return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
+        case RttMotionPattern::EXPECTED:
+            return legacy_hal::WIFI_MOTION_EXPECTED;
+        case RttMotionPattern::UNKNOWN:
+            return legacy_hal::WIFI_MOTION_UNKNOWN;
+    };
+    CHECK(false);
+}
+
+WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
+    switch (preamble) {
+        case 0:
+            return WifiRatePreamble::OFDM;
+        case 1:
+            return WifiRatePreamble::CCK;
+        case 2:
+            return WifiRatePreamble::HT;
+        case 3:
+            return WifiRatePreamble::VHT;
+        case 4:
+            return WifiRatePreamble::HE;
+        default:
+            return WifiRatePreamble::RESERVED;
+    };
+    CHECK(false) << "Unknown legacy preamble: " << preamble;
+}
+
+WifiRateNss convertLegacyWifiRateNssToHidl(uint8_t nss) {
+    switch (nss) {
+        case 0:
+            return WifiRateNss::NSS_1x1;
+        case 1:
+            return WifiRateNss::NSS_2x2;
+        case 2:
+            return WifiRateNss::NSS_3x3;
+        case 3:
+            return WifiRateNss::NSS_4x4;
+    };
+    CHECK(false) << "Unknown legacy nss: " << nss;
+    return {};
+}
+
+RttStatus convertLegacyRttStatusToHidl(legacy_hal::wifi_rtt_status status) {
+    switch (status) {
+        case legacy_hal::RTT_STATUS_SUCCESS:
+            return RttStatus::SUCCESS;
+        case legacy_hal::RTT_STATUS_FAILURE:
+            return RttStatus::FAILURE;
+        case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
+            return RttStatus::FAIL_NO_RSP;
+        case legacy_hal::RTT_STATUS_FAIL_REJECTED:
+            return RttStatus::FAIL_REJECTED;
+        case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
+            return RttStatus::FAIL_NOT_SCHEDULED_YET;
+        case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
+            return RttStatus::FAIL_TM_TIMEOUT;
+        case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
+            return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
+        case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
+            return RttStatus::FAIL_NO_CAPABILITY;
+        case legacy_hal::RTT_STATUS_ABORTED:
+            return RttStatus::ABORTED;
+        case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
+            return RttStatus::FAIL_INVALID_TS;
+        case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
+            return RttStatus::FAIL_PROTOCOL;
+        case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
+            return RttStatus::FAIL_SCHEDULE;
+        case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
+            return RttStatus::FAIL_BUSY_TRY_LATER;
+        case legacy_hal::RTT_STATUS_INVALID_REQ:
+            return RttStatus::INVALID_REQ;
+        case legacy_hal::RTT_STATUS_NO_WIFI:
+            return RttStatus::NO_WIFI;
+        case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
+            return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
+        case legacy_hal::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE:
+            return RttStatus::FAILURE;  // TODO: add HIDL enumeration
+        case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED:
+            return RttStatus::FAILURE;  // TODO: add HIDL enumeration
+    };
+    CHECK(false) << "Unknown legacy status: " << status;
+}
+
+bool convertHidlWifiChannelInfoToLegacy(
+    const WifiChannelInfo& hidl_info,
+    legacy_hal::wifi_channel_info* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
+    legacy_info->center_freq = hidl_info.centerFreq;
+    legacy_info->center_freq0 = hidl_info.centerFreq0;
+    legacy_info->center_freq1 = hidl_info.centerFreq1;
+    return true;
+}
+
+bool convertLegacyWifiChannelInfoToHidl(
+    const legacy_hal::wifi_channel_info& legacy_info,
+    WifiChannelInfo* hidl_info) {
+    if (!hidl_info) {
+        return false;
+    }
+    *hidl_info = {};
+    hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
+    hidl_info->centerFreq = legacy_info.center_freq;
+    hidl_info->centerFreq0 = legacy_info.center_freq0;
+    hidl_info->centerFreq1 = legacy_info.center_freq1;
+    return true;
+}
+
+bool convertHidlRttConfigToLegacy(const RttConfig& hidl_config,
+                                  legacy_hal::wifi_rtt_config* legacy_config) {
+    if (!legacy_config) {
+        return false;
+    }
+    *legacy_config = {};
+    CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
+    memcpy(legacy_config->addr, hidl_config.addr.data(),
+           hidl_config.addr.size());
+    legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
+    legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
+    if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel,
+                                            &legacy_config->channel)) {
+        return false;
+    }
+    legacy_config->burst_period = hidl_config.burstPeriod;
+    legacy_config->num_burst = hidl_config.numBurst;
+    legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
+    legacy_config->num_retries_per_rtt_frame =
+        hidl_config.numRetriesPerRttFrame;
+    legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
+    legacy_config->LCI_request = hidl_config.mustRequestLci;
+    legacy_config->LCR_request = hidl_config.mustRequestLcr;
+    legacy_config->burst_duration = hidl_config.burstDuration;
+    legacy_config->preamble =
+        convertHidlRttPreambleToLegacy(hidl_config.preamble);
+    legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
+    return true;
+}
+
+bool convertHidlVectorOfRttConfigToLegacy(
+    const std::vector<RttConfig>& hidl_configs,
+    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
+    if (!legacy_configs) {
+        return false;
+    }
+    *legacy_configs = {};
+    for (const auto& hidl_config : hidl_configs) {
+        legacy_hal::wifi_rtt_config legacy_config;
+        if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
+            return false;
+        }
+        legacy_configs->push_back(legacy_config);
+    }
+    return true;
+}
+
+bool convertHidlRttLciInformationToLegacy(
+    const RttLciInformation& hidl_info,
+    legacy_hal::wifi_lci_information* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    legacy_info->latitude = hidl_info.latitude;
+    legacy_info->longitude = hidl_info.longitude;
+    legacy_info->altitude = hidl_info.altitude;
+    legacy_info->latitude_unc = hidl_info.latitudeUnc;
+    legacy_info->longitude_unc = hidl_info.longitudeUnc;
+    legacy_info->altitude_unc = hidl_info.altitudeUnc;
+    legacy_info->motion_pattern =
+        convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
+    legacy_info->floor = hidl_info.floor;
+    legacy_info->height_above_floor = hidl_info.heightAboveFloor;
+    legacy_info->height_unc = hidl_info.heightUnc;
+    return true;
+}
+
+bool convertHidlRttLcrInformationToLegacy(
+    const RttLcrInformation& hidl_info,
+    legacy_hal::wifi_lcr_information* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
+    memcpy(legacy_info->country_code, hidl_info.countryCode.data(),
+           hidl_info.countryCode.size());
+    if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
+        return false;
+    }
+    legacy_info->length = hidl_info.civicInfo.size();
+    memcpy(legacy_info->civic_info, hidl_info.civicInfo.c_str(),
+           hidl_info.civicInfo.size());
+    return true;
+}
+
+bool convertHidlRttResponderToLegacy(
+    const RttResponder& hidl_responder,
+    legacy_hal::wifi_rtt_responder* legacy_responder) {
+    if (!legacy_responder) {
+        return false;
+    }
+    *legacy_responder = {};
+    if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel,
+                                            &legacy_responder->channel)) {
+        return false;
+    }
+    legacy_responder->preamble =
+        convertHidlRttPreambleToLegacy(hidl_responder.preamble);
+    return true;
+}
+
+bool convertLegacyRttResponderToHidl(
+    const legacy_hal::wifi_rtt_responder& legacy_responder,
+    RttResponder* hidl_responder) {
+    if (!hidl_responder) {
+        return false;
+    }
+    *hidl_responder = {};
+    if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel,
+                                            &hidl_responder->channel)) {
+        return false;
+    }
+    hidl_responder->preamble =
+        convertLegacyRttPreambleToHidl(legacy_responder.preamble);
+    return true;
+}
+
+bool convertLegacyRttCapabilitiesToHidl(
+    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+    RttCapabilities* hidl_capabilities) {
+    if (!hidl_capabilities) {
+        return false;
+    }
+    *hidl_capabilities = {};
+    hidl_capabilities->rttOneSidedSupported =
+        legacy_capabilities.rtt_one_sided_supported;
+    hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
+    hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
+    hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
+    hidl_capabilities->responderSupported =
+        legacy_capabilities.responder_supported;
+    hidl_capabilities->preambleSupport = 0;
+    for (const auto flag :
+         {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY,
+          legacy_hal::WIFI_RTT_PREAMBLE_HT, legacy_hal::WIFI_RTT_PREAMBLE_VHT,
+          legacy_hal::WIFI_RTT_PREAMBLE_HE}) {
+        if (legacy_capabilities.preamble_support & flag) {
+            hidl_capabilities->preambleSupport |=
+                static_cast<std::underlying_type<RttPreamble>::type>(
+                    convertLegacyRttPreambleToHidl(flag));
+        }
+    }
+    hidl_capabilities->bwSupport = 0;
+    for (const auto flag :
+         {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10,
+          legacy_hal::WIFI_RTT_BW_20, legacy_hal::WIFI_RTT_BW_40,
+          legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160}) {
+        if (legacy_capabilities.bw_support & flag) {
+            hidl_capabilities->bwSupport |=
+                static_cast<std::underlying_type<RttBw>::type>(
+                    convertLegacyRttBwToHidl(flag));
+        }
+    }
+    hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
+    return true;
+}
+
+bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
+                                     WifiRateInfo* hidl_rate) {
+    if (!hidl_rate) {
+        return false;
+    }
+    *hidl_rate = {};
+    hidl_rate->preamble =
+        convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
+    hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
+    hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
+        static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
+    hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
+    hidl_rate->bitRateInKbps = legacy_rate.bitrate;
+    return true;
+}
+
+bool convertLegacyRttResultToHidl(
+    const legacy_hal::wifi_rtt_result& legacy_result, RttResult* hidl_result) {
+    if (!hidl_result) {
+        return false;
+    }
+    *hidl_result = {};
+    CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
+    memcpy(hidl_result->addr.data(), legacy_result.addr,
+           sizeof(legacy_result.addr));
+    hidl_result->burstNum = legacy_result.burst_num;
+    hidl_result->measurementNumber = legacy_result.measurement_number;
+    hidl_result->successNumber = legacy_result.success_number;
+    hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
+    hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
+    hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
+    hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
+    hidl_result->rssi = legacy_result.rssi;
+    hidl_result->rssiSpread = legacy_result.rssi_spread;
+    if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate,
+                                         &hidl_result->txRate)) {
+        return false;
+    }
+    if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate,
+                                         &hidl_result->rxRate)) {
+        return false;
+    }
+    hidl_result->rtt = legacy_result.rtt;
+    hidl_result->rttSd = legacy_result.rtt_sd;
+    hidl_result->rttSpread = legacy_result.rtt_spread;
+    hidl_result->distanceInMm = legacy_result.distance_mm;
+    hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
+    hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
+    hidl_result->timeStampInUs = legacy_result.ts;
+    hidl_result->burstDurationInMs = legacy_result.burst_duration;
+    hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
+    if (legacy_result.LCI &&
+        !convertLegacyIeToHidl(*legacy_result.LCI, &hidl_result->lci)) {
+        return false;
+    }
+    if (legacy_result.LCR &&
+        !convertLegacyIeToHidl(*legacy_result.LCR, &hidl_result->lcr)) {
+        return false;
+    }
+    return true;
+}
+
+bool convertLegacyVectorOfRttResultToHidl(
+    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+    std::vector<RttResult>* hidl_results) {
+    if (!hidl_results) {
+        return false;
+    }
+    *hidl_results = {};
+    for (const auto legacy_result : legacy_results) {
+        RttResult hidl_result;
+        if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
+            return false;
+        }
+        hidl_results->push_back(hidl_result);
+    }
+    return true;
+}
+
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
+    IfaceType hidl_interface_type) {
+    switch (hidl_interface_type) {
+        case IfaceType::STA:
+            return legacy_hal::WIFI_INTERFACE_TYPE_STA;
+        case IfaceType::AP:
+            return legacy_hal::WIFI_INTERFACE_TYPE_AP;
+        case IfaceType::P2P:
+            return legacy_hal::WIFI_INTERFACE_TYPE_P2P;
+        case IfaceType::NAN:
+            return legacy_hal::WIFI_INTERFACE_TYPE_NAN;
+    }
+    CHECK(false);
+}
+}  // namespace hidl_struct_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h
new file mode 100644
index 0000000..929f877
--- /dev/null
+++ b/wifi/1.4/default/hidl_struct_util.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 HIDL_STRUCT_UTIL_H_
+#define HIDL_STRUCT_UTIL_H_
+
+#include <vector>
+
+#include <android/hardware/wifi/1.0/IWifiChip.h>
+#include <android/hardware/wifi/1.0/types.h>
+#include <android/hardware/wifi/1.2/types.h>
+#include <android/hardware/wifi/1.3/IWifiChip.h>
+#include <android/hardware/wifi/1.3/types.h>
+#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
+#include <android/hardware/wifi/1.4/types.h>
+
+#include "wifi_legacy_hal.h"
+
+/**
+ * This file contains a bunch of functions to convert structs from the legacy
+ * HAL to HIDL and vice versa.
+ * TODO(b/32093047): Add unit tests for these conversion methods in the VTS test
+ * suite.
+ */
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_struct_util {
+using namespace android::hardware::wifi::V1_0;
+
+// Chip conversion methods.
+bool convertLegacyFeaturesToHidlChipCapabilities(
+    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint32_t* hidl_caps);
+bool convertLegacyDebugRingBufferStatusToHidl(
+    const legacy_hal::wifi_ring_buffer_status& legacy_status,
+    WifiDebugRingBufferStatus* hidl_status);
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
+bool convertLegacyWakeReasonStatsToHidl(
+    const legacy_hal::WakeReasonStats& legacy_stats,
+    WifiDebugHostWakeReasonStats* hidl_stats);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
+    V1_1::IWifiChip::TxPowerScenario hidl_scenario);
+legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
+    V1_3::IWifiChip::LatencyMode hidl_latency_mode);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+    V1_2::IWifiChip::TxPowerScenario hidl_scenario);
+bool convertLegacyWifiMacInfosToHidl(
+    const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
+    IfaceType hidl_interface_type);
+
+// STA iface conversion methods.
+bool convertLegacyFeaturesToHidlStaCapabilities(
+    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint32_t* hidl_caps);
+bool convertLegacyApfCapabilitiesToHidl(
+    const legacy_hal::PacketFilterCapabilities& legacy_caps,
+    StaApfPacketFilterCapabilities* hidl_caps);
+bool convertLegacyGscanCapabilitiesToHidl(
+    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+    StaBackgroundScanCapabilities* hidl_caps);
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band);
+bool convertHidlGscanParamsToLegacy(
+    const StaBackgroundScanParameters& hidl_scan_params,
+    legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
+// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
+// Information Elements (IEs)
+bool convertLegacyGscanResultToHidl(
+    const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
+    StaScanResult* hidl_scan_result);
+// |cached_results| is assumed to not include IEs.
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
+    const std::vector<legacy_hal::wifi_cached_scan_results>&
+        legacy_cached_scan_results,
+    std::vector<StaScanData>* hidl_scan_datas);
+bool convertLegacyLinkLayerStatsToHidl(
+    const legacy_hal::LinkLayerStats& legacy_stats,
+    V1_3::StaLinkLayerStats* hidl_stats);
+bool convertLegacyRoamingCapabilitiesToHidl(
+    const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+    StaRoamingCapabilities* hidl_caps);
+bool convertHidlRoamingConfigToLegacy(
+    const StaRoamingConfig& hidl_config,
+    legacy_hal::wifi_roaming_config* legacy_config);
+legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
+    StaRoamingState state);
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+    std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+    std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
+
+// NAN iface conversion methods.
+void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
+                            size_t max_len, WifiNanStatus* wifiNanStatus);
+bool convertHidlNanEnableRequestToLegacy(
+    const NanEnableRequest& hidl_request,
+    legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequestToLegacy(
+    const NanConfigRequest& hidl_request,
+    legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanEnableRequest_1_4ToLegacy(
+    const NanEnableRequest& hidl_request1,
+    const V1_2::NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequest_1_4ToLegacy(
+    const NanConfigRequest& hidl_request1,
+    const V1_2::NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanPublishRequestToLegacy(
+    const NanPublishRequest& hidl_request,
+    legacy_hal::NanPublishRequest* legacy_request);
+bool convertHidlNanSubscribeRequestToLegacy(
+    const NanSubscribeRequest& hidl_request,
+    legacy_hal::NanSubscribeRequest* legacy_request);
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+    const NanTransmitFollowupRequest& hidl_request,
+    legacy_hal::NanTransmitFollowupRequest* legacy_request);
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+    const NanInitiateDataPathRequest& hidl_request,
+    legacy_hal::NanDataPathInitiatorRequest* legacy_request);
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+    const NanRespondToDataPathIndicationRequest& hidl_response,
+    legacy_hal::NanDataPathIndicationResponse* legacy_response);
+bool convertLegacyNanResponseHeaderToHidl(
+    const legacy_hal::NanResponseMsg& legacy_response,
+    WifiNanStatus* wifiNanStatus);
+bool convertLegacyNanCapabilitiesResponseToHidl(
+    const legacy_hal::NanCapabilities& legacy_response,
+    NanCapabilities* hidl_response);
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+                                    NanMatchInd* hidl_ind);
+bool convertLegacyNanFollowupIndToHidl(
+    const legacy_hal::NanFollowupInd& legacy_ind,
+    NanFollowupReceivedInd* hidl_ind);
+bool convertLegacyNanDataPathRequestIndToHidl(
+    const legacy_hal::NanDataPathRequestInd& legacy_ind,
+    NanDataPathRequestInd* hidl_ind);
+bool convertLegacyNanDataPathConfirmIndToHidl(
+    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+    V1_2::NanDataPathConfirmInd* hidl_ind);
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+    const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+    V1_2::NanDataPathScheduleUpdateInd* hidl_ind);
+
+// RTT controller conversion methods.
+bool convertHidlVectorOfRttConfigToLegacy(
+    const std::vector<RttConfig>& hidl_configs,
+    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
+bool convertHidlRttLciInformationToLegacy(
+    const RttLciInformation& hidl_info,
+    legacy_hal::wifi_lci_information* legacy_info);
+bool convertHidlRttLcrInformationToLegacy(
+    const RttLcrInformation& hidl_info,
+    legacy_hal::wifi_lcr_information* legacy_info);
+bool convertHidlRttResponderToLegacy(
+    const RttResponder& hidl_responder,
+    legacy_hal::wifi_rtt_responder* legacy_responder);
+bool convertHidlWifiChannelInfoToLegacy(
+    const WifiChannelInfo& hidl_info,
+    legacy_hal::wifi_channel_info* legacy_info);
+bool convertLegacyRttResponderToHidl(
+    const legacy_hal::wifi_rtt_responder& legacy_responder,
+    RttResponder* hidl_responder);
+bool convertLegacyRttCapabilitiesToHidl(
+    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+    RttCapabilities* hidl_capabilities);
+bool convertLegacyVectorOfRttResultToHidl(
+    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+    std::vector<RttResult>* hidl_results);
+}  // namespace hidl_struct_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_STRUCT_UTIL_H_
diff --git a/wifi/1.4/default/hidl_sync_util.cpp b/wifi/1.4/default/hidl_sync_util.cpp
new file mode 100644
index 0000000..593a3bc
--- /dev/null
+++ b/wifi/1.4/default/hidl_sync_util.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "hidl_sync_util.h"
+
+namespace {
+std::recursive_mutex g_mutex;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_sync_util {
+
+std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
+    return std::unique_lock<std::recursive_mutex>{g_mutex};
+}
+
+}  // namespace hidl_sync_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/hidl_sync_util.h b/wifi/1.4/default/hidl_sync_util.h
new file mode 100644
index 0000000..0244421
--- /dev/null
+++ b/wifi/1.4/default/hidl_sync_util.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 HIDL_SYNC_UTIL_H_
+#define HIDL_SYNC_UTIL_H_
+
+#include <mutex>
+
+// Utility that provides a global lock to synchronize access between
+// the HIDL thread and the legacy HAL's event loop.
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace hidl_sync_util {
+std::unique_lock<std::recursive_mutex> acquireGlobalLock();
+}  // namespace hidl_sync_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+#endif  // HIDL_SYNC_UTIL_H_
diff --git a/wifi/1.4/default/ringbuffer.cpp b/wifi/1.4/default/ringbuffer.cpp
new file mode 100644
index 0000000..0fe8ef4
--- /dev/null
+++ b/wifi/1.4/default/ringbuffer.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 <android-base/logging.h>
+
+#include "ringbuffer.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
+
+void Ringbuffer::append(const std::vector<uint8_t>& input) {
+    if (input.size() == 0) {
+        return;
+    }
+    if (input.size() > maxSize_) {
+        LOG(INFO) << "Oversized message of " << input.size()
+                  << " bytes is dropped";
+        return;
+    }
+    data_.push_back(input);
+    size_ += input.size() * sizeof(input[0]);
+    while (size_ > maxSize_) {
+        size_ -= data_.front().size() * sizeof(data_.front()[0]);
+        data_.pop_front();
+    }
+}
+
+const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
+    return data_;
+}
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/ringbuffer.h b/wifi/1.4/default/ringbuffer.h
new file mode 100644
index 0000000..ddce648
--- /dev/null
+++ b/wifi/1.4/default/ringbuffer.h
@@ -0,0 +1,53 @@
+/*
+ * 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 RINGBUFFER_H_
+#define RINGBUFFER_H_
+
+#include <list>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+/**
+ * Ringbuffer object used to store debug data.
+ */
+class Ringbuffer {
+   public:
+    explicit Ringbuffer(size_t maxSize);
+
+    // Appends the data buffer and deletes from the front until buffer is
+    // within |maxSize_|.
+    void append(const std::vector<uint8_t>& input);
+    const std::list<std::vector<uint8_t>>& getData() const;
+
+   private:
+    std::list<std::vector<uint8_t>> data_;
+    size_t size_;
+    size_t maxSize_;
+};
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // RINGBUFFER_H_
diff --git a/wifi/1.4/default/service.cpp b/wifi/1.4/default/service.cpp
new file mode 100644
index 0000000..3f7f609
--- /dev/null
+++ b/wifi/1.4/default/service.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+#include "wifi.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::wifi::V1_4::implementation::feature_flags::
+    WifiFeatureFlags;
+using android::hardware::wifi::V1_4::implementation::iface_util::WifiIfaceUtil;
+using android::hardware::wifi::V1_4::implementation::legacy_hal::WifiLegacyHal;
+using android::hardware::wifi::V1_4::implementation::mode_controller::
+    WifiModeController;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main(int /*argc*/, char** argv) {
+    android::base::InitLogging(
+        argv, android::base::LogdLogger(android::base::SYSTEM));
+    LOG(INFO) << "Wifi Hal is booting up...";
+
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    const auto iface_tool =
+        std::make_shared<android::wifi_system::InterfaceTool>();
+    // Setup hwbinder service
+    android::sp<android::hardware::wifi::V1_4::IWifi> service =
+        new android::hardware::wifi::V1_4::implementation::Wifi(
+            iface_tool, std::make_shared<WifiLegacyHal>(iface_tool),
+            std::make_shared<WifiModeController>(),
+            std::make_shared<WifiIfaceUtil>(iface_tool),
+            std::make_shared<WifiFeatureFlags>());
+    if (kLazyService) {
+        auto registrar = LazyServiceRegistrar::getInstance();
+        CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
+            << "Failed to register wifi HAL";
+    } else {
+        CHECK_EQ(service->registerAsService(), android::NO_ERROR)
+            << "Failed to register wifi HAL";
+    }
+
+    joinRpcThreadpool();
+
+    LOG(INFO) << "Wifi Hal is terminating...";
+    return 0;
+}
diff --git a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
new file mode 100644
index 0000000..b71d549
--- /dev/null
+++ b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "hidl_struct_util.h"
+
+using testing::Test;
+
+namespace {
+constexpr uint32_t kMacId1 = 1;
+constexpr uint32_t kMacId2 = 2;
+constexpr uint32_t kIfaceChannel1 = 3;
+constexpr uint32_t kIfaceChannel2 = 5;
+constexpr char kIfaceName1[] = "wlan0";
+constexpr char kIfaceName2[] = "wlan1";
+}  // namespace
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
+
+class HidlStructUtilTest : public Test {};
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {
+        .wlan_mac_id = kMacId1,
+        .mac_band =
+            legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
+                                                    .channel = kIfaceChannel1};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
+                                                    .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+
+    std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+        legacy_mac_infos, &hidl_radio_mode_infos));
+
+    ASSERT_EQ(1u, hidl_radio_mode_infos.size());
+    auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
+    EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
+    EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
+    ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
+    auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
+              hidl_iface_info1.channel);
+    auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
+    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
+              hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {
+        .wlan_mac_id = kMacId1, .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
+                                                    .channel = kIfaceChannel1};
+    legacy_hal::WifiMacInfo legacy_mac_info2 = {
+        .wlan_mac_id = kMacId2, .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
+                                                    .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+    legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info2);
+
+    std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+        legacy_mac_infos, &hidl_radio_mode_infos));
+
+    ASSERT_EQ(2u, hidl_radio_mode_infos.size());
+
+    // Find mac info 1.
+    const auto hidl_radio_mode_info1 = std::find_if(
+        hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+        [&legacy_mac_info1](const IWifiChipEventCallback::RadioModeInfo& x) {
+            return x.radioId == legacy_mac_info1.wlan_mac_id;
+        });
+    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
+    EXPECT_EQ(WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
+    ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
+    auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
+              hidl_iface_info1.channel);
+
+    // Find mac info 2.
+    const auto hidl_radio_mode_info2 = std::find_if(
+        hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+        [&legacy_mac_info2](const IWifiChipEventCallback::RadioModeInfo& x) {
+            return x.radioId == legacy_mac_info2.wlan_mac_id;
+        });
+    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
+    EXPECT_EQ(WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
+    ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
+    auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
+              hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) {
+    legacy_hal::LinkLayerStats legacy_stats{};
+    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.iface.beacon_rx = rand();
+    legacy_stats.iface.rssi_mgmt = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
+
+    for (auto& radio : legacy_stats.radios) {
+        radio.stats.on_time = rand();
+        radio.stats.tx_time = rand();
+        radio.stats.rx_time = rand();
+        radio.stats.on_time_scan = rand();
+        radio.stats.on_time_nbd = rand();
+        radio.stats.on_time_gscan = rand();
+        radio.stats.on_time_roam_scan = rand();
+        radio.stats.on_time_pno_scan = rand();
+        radio.stats.on_time_hs20 = rand();
+        for (int i = 0; i < 4; i++) {
+            radio.tx_time_per_levels.push_back(rand());
+        }
+
+        legacy_hal::wifi_channel_stat channel_stat1 = {
+            .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+            .on_time = 0x1111,
+            .cca_busy_time = 0x55,
+        };
+        legacy_hal::wifi_channel_stat channel_stat2 = {
+            .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+            .on_time = 0x2222,
+            .cca_busy_time = 0x66,
+        };
+        radio.channel_stats.push_back(channel_stat1);
+        radio.channel_stats.push_back(channel_stat2);
+    }
+
+    V1_3::StaLinkLayerStats converted{};
+    hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
+                                                        &converted);
+    EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.beaconRx);
+    EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
+              converted.iface.wmeBePktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
+              converted.iface.wmeBePktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
+              converted.iface.wmeBePktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
+              converted.iface.wmeBePktStats.retries);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
+              converted.iface.wmeBkPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
+              converted.iface.wmeBkPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
+              converted.iface.wmeBkPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
+              converted.iface.wmeBkPktStats.retries);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
+              converted.iface.wmeViPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
+              converted.iface.wmeViPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
+              converted.iface.wmeViPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
+              converted.iface.wmeViPktStats.retries);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
+              converted.iface.wmeVoPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
+              converted.iface.wmeVoPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
+              converted.iface.wmeVoPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
+              converted.iface.wmeVoPktStats.retries);
+
+    EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
+    for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time,
+                  converted.radios[i].V1_0.onTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.tx_time,
+                  converted.radios[i].V1_0.txTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.rx_time,
+                  converted.radios[i].V1_0.rxTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
+                  converted.radios[i].V1_0.onTimeInMsForScan);
+        EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
+                  converted.radios[i].V1_0.txTimeInMsPerLevel.size());
+        for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size();
+             j++) {
+            EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
+                      converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
+        }
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
+                  converted.radios[i].onTimeInMsForNanScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
+                  converted.radios[i].onTimeInMsForBgScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
+                  converted.radios[i].onTimeInMsForRoamScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
+                  converted.radios[i].onTimeInMsForPnoScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
+                  converted.radios[i].onTimeInMsForHs20Scan);
+        EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
+                  converted.radios[i].channelStats.size());
+        for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size();
+             k++) {
+            auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
+            EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
+                      converted.radios[i].channelStats[k].channel.width);
+            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq),
+                      converted.radios[i].channelStats[k].channel.centerFreq);
+            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
+                      converted.radios[i].channelStats[k].channel.centerFreq0);
+            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
+                      converted.radios[i].channelStats[k].channel.centerFreq1);
+            EXPECT_EQ(legacy_channel_st.cca_busy_time,
+                      converted.radios[i].channelStats[k].ccaBusyTimeInMs);
+            EXPECT_EQ(legacy_channel_st.on_time,
+                      converted.radios[i].channelStats[k].onTimeInMs);
+        }
+    }
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) {
+    using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
+
+    uint32_t hidle_caps;
+
+    uint32_t legacy_feature_set =
+        WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
+    uint32_t legacy_logger_feature_set =
+        legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
+
+    ASSERT_TRUE(hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
+        legacy_feature_set, legacy_logger_feature_set, &hidle_caps));
+
+    EXPECT_EQ(HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA |
+                  HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS |
+                  HidlChipCaps::DEBUG_ERROR_ALERTS | HidlChipCaps::D2D_RTT |
+                  HidlChipCaps::SET_LATENCY_MODE |
+                  HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP,
+              hidle_caps);
+}
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.3/default/tests/main.cpp b/wifi/1.4/default/tests/main.cpp
similarity index 100%
rename from wifi/1.3/default/tests/main.cpp
rename to wifi/1.4/default/tests/main.cpp
diff --git a/wifi/1.3/default/tests/mock_interface_tool.cpp b/wifi/1.4/default/tests/mock_interface_tool.cpp
similarity index 100%
rename from wifi/1.3/default/tests/mock_interface_tool.cpp
rename to wifi/1.4/default/tests/mock_interface_tool.cpp
diff --git a/wifi/1.3/default/tests/mock_interface_tool.h b/wifi/1.4/default/tests/mock_interface_tool.h
similarity index 100%
rename from wifi/1.3/default/tests/mock_interface_tool.h
rename to wifi/1.4/default/tests/mock_interface_tool.h
diff --git a/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
new file mode 100644
index 0000000..b1fa432
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+
+#include "mock_wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace feature_flags {
+
+MockWifiFeatureFlags::MockWifiFeatureFlags() {}
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_feature_flags.h b/wifi/1.4/default/tests/mock_wifi_feature_flags.h
new file mode 100644
index 0000000..72d2304
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_feature_flags.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_FEATURE_FLAGS_H_
+#define MOCK_WIFI_FEATURE_FLAGS_H_
+
+#include <gmock/gmock.h>
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+
+#include "wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace feature_flags {
+
+class MockWifiFeatureFlags : public WifiFeatureFlags {
+   public:
+    MockWifiFeatureFlags();
+
+    MOCK_METHOD0(getChipModes, std::vector<V1_0::IWifiChip::ChipMode>());
+    MOCK_METHOD0(isApMacRandomizationDisabled, bool());
+};
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.4/default/tests/mock_wifi_iface_util.cpp b/wifi/1.4/default/tests/mock_wifi_iface_util.cpp
new file mode 100644
index 0000000..0968569
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_iface_util.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_iface_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace iface_util {
+
+MockWifiIfaceUtil::MockWifiIfaceUtil(
+    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+    : WifiIfaceUtil(iface_tool) {}
+}  // namespace iface_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_iface_util.h b/wifi/1.4/default/tests/mock_wifi_iface_util.h
new file mode 100644
index 0000000..8d77a7d
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_iface_util.h
@@ -0,0 +1,53 @@
+/*
+ * 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 MOCK_WIFI_IFACE_UTIL_H_
+#define MOCK_WIFI_IFACE_UTIL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_iface_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace iface_util {
+
+class MockWifiIfaceUtil : public WifiIfaceUtil {
+   public:
+    MockWifiIfaceUtil(
+        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+    MOCK_METHOD1(getFactoryMacAddress,
+                 std::array<uint8_t, 6>(const std::string&));
+    MOCK_METHOD2(setMacAddress,
+                 bool(const std::string&, const std::array<uint8_t, 6>&));
+    MOCK_METHOD0(getOrCreateRandomMacAddress, std::array<uint8_t, 6>());
+    MOCK_METHOD2(registerIfaceEventHandlers,
+                 void(const std::string&, IfaceEventHandlers));
+    MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&));
+    MOCK_METHOD2(setUpState, bool(const std::string&, bool));
+    MOCK_METHOD1(ifNameToIndex, unsigned(const std::string&));
+};
+}  // namespace iface_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
new file mode 100644
index 0000000..8d65c59
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace legacy_hal {
+
+MockWifiLegacyHal::MockWifiLegacyHal(
+    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+    : WifiLegacyHal(iface_tool) {}
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_legacy_hal.h b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h
new file mode 100644
index 0000000..3bb7b54
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_LEGACY_HAL_H_
+#define MOCK_WIFI_LEGACY_HAL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace legacy_hal {
+
+class MockWifiLegacyHal : public WifiLegacyHal {
+   public:
+    MockWifiLegacyHal(
+        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+    MOCK_METHOD0(initialize, wifi_error());
+    MOCK_METHOD0(start, wifi_error());
+    MOCK_METHOD2(stop, wifi_error(std::unique_lock<std::recursive_mutex>*,
+                                  const std::function<void()>&));
+    MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool));
+    MOCK_METHOD2(registerRadioModeChangeCallbackHandler,
+                 wifi_error(const std::string&,
+                            const on_radio_mode_change_callback&));
+    MOCK_METHOD1(getFirmwareVersion, std::pair<wifi_error, std::string>(
+                                         const std::string& iface_name));
+    MOCK_METHOD1(getDriverVersion, std::pair<wifi_error, std::string>(
+                                       const std::string& iface_name));
+
+    MOCK_METHOD2(selectTxPowerScenario,
+                 wifi_error(const std::string& iface_name,
+                            wifi_power_scenario scenario));
+    MOCK_METHOD1(resetTxPowerScenario,
+                 wifi_error(const std::string& iface_name));
+    MOCK_METHOD2(nanRegisterCallbackHandlers,
+                 wifi_error(const std::string&, const NanCallbackHandlers&));
+    MOCK_METHOD2(nanDisableRequest,
+                 wifi_error(const std::string&, transaction_id));
+    MOCK_METHOD3(nanDataInterfaceDelete,
+                 wifi_error(const std::string&, transaction_id,
+                            const std::string&));
+    MOCK_METHOD2(createVirtualInterface,
+                 wifi_error(const std::string& ifname,
+                            wifi_interface_type iftype));
+    MOCK_METHOD1(deleteVirtualInterface, wifi_error(const std::string& ifname));
+};
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
new file mode 100644
index 0000000..ee09029
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace mode_controller {
+
+MockWifiModeController::MockWifiModeController() : WifiModeController() {}
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_mode_controller.h b/wifi/1.4/default/tests/mock_wifi_mode_controller.h
new file mode 100644
index 0000000..1e1ce69
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_mode_controller.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_MODE_CONTROLLER_H_
+#define MOCK_WIFI_MODE_CONTROLLER_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace mode_controller {
+
+class MockWifiModeController : public WifiModeController {
+   public:
+    MockWifiModeController();
+    MOCK_METHOD0(initialize, bool());
+    MOCK_METHOD1(changeFirmwareMode, bool(IfaceType));
+    MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType));
+    MOCK_METHOD0(deinitialize, bool());
+};
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
new file mode 100644
index 0000000..a65347f
--- /dev/null
+++ b/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 <gmock/gmock.h>
+
+#include "ringbuffer.h"
+
+using testing::Return;
+using testing::Test;
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+class RingbufferTest : public Test {
+   public:
+    const uint32_t maxBufferSize_ = 10;
+    Ringbuffer buffer_{maxBufferSize_};
+};
+
+TEST_F(RingbufferTest, CreateEmptyBuffer) {
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, CanUseFullBufferCapacity) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    buffer_.append(input);
+    buffer_.append(input2);
+    ASSERT_EQ(2u, buffer_.getData().size());
+    EXPECT_EQ(input, buffer_.getData().front());
+    EXPECT_EQ(input2, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    const std::vector<uint8_t> input3 = {'G'};
+    buffer_.append(input);
+    buffer_.append(input2);
+    buffer_.append(input3);
+    ASSERT_EQ(2u, buffer_.getData().size());
+    EXPECT_EQ(input2, buffer_.getData().front());
+    EXPECT_EQ(input3, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    const std::vector<uint8_t> input3(maxBufferSize_, '2');
+    buffer_.append(input);
+    buffer_.append(input2);
+    buffer_.append(input3);
+    ASSERT_EQ(1u, buffer_.getData().size());
+    EXPECT_EQ(input3, buffer_.getData().front());
+}
+
+TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) {
+    const std::vector<uint8_t> input = {};
+    buffer_.append(input);
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendIsDropped) {
+    const std::vector<uint8_t> input(maxBufferSize_ + 1, '0');
+    buffer_.append(input);
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) {
+    const std::vector<uint8_t> input(maxBufferSize_, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ + 1, '1');
+    buffer_.append(input);
+    buffer_.append(input2);
+    ASSERT_EQ(1u, buffer_.getData().size());
+    EXPECT_EQ(input, buffer_.getData().front());
+}
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.3/default/tests/runtests.sh b/wifi/1.4/default/tests/runtests.sh
similarity index 100%
rename from wifi/1.3/default/tests/runtests.sh
rename to wifi/1.4/default/tests/runtests.sh
diff --git a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
new file mode 100644
index 0000000..323d2ff
--- /dev/null
+++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
@@ -0,0 +1,900 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "wifi_chip.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+#include "mock_wifi_mode_controller.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+using android::hardware::wifi::V1_0::ChipId;
+
+constexpr ChipId kFakeChipId = 5;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+class WifiChipTest : public Test {
+   protected:
+    void setupV1IfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
+            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P}, 1}}}
+        };
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
+            {{{{IfaceType::AP}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
+            {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes())
+            .WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV1_AwareIfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
+            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+        };
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsAp = {
+            {{{{IfaceType::AP}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
+            {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes())
+            .WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV1_AwareDisabledApIfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinationsSta = {
+            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes())
+            .WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV2_AwareIfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
+            {{{{IfaceType::STA}, 1}, {{IfaceType::AP}, 1}}},
+            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV3, combinations}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes())
+            .WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV2_AwareDisabledApIfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
+            {{{{IfaceType::STA}, 1}, {{IfaceType::P2P, IfaceType::NAN}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV3, combinations}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes())
+            .WillRepeatedly(testing::Return(modes));
+    }
+
+    void setup_MultiIfaceCombination() {
+        // clang-format off
+        const hidl_vec<V1_0::IWifiChip::ChipIfaceCombination> combinations = {
+            {{{{IfaceType::STA}, 3}, {{IfaceType::AP}, 1}}}
+        };
+        const std::vector<V1_0::IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV3, combinations}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes())
+            .WillRepeatedly(testing::Return(modes));
+    }
+
+    void assertNumberOfModes(uint32_t num_modes) {
+        chip_->getAvailableModes(
+            [num_modes](const WifiStatus& status,
+                        const std::vector<WifiChip::ChipMode>& modes) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                // V2_Aware has 1 mode of operation.
+                ASSERT_EQ(num_modes, modes.size());
+            });
+    }
+
+    void findModeAndConfigureForIfaceType(const IfaceType& type) {
+        // This should be aligned with kInvalidModeId in wifi_chip.cpp.
+        ChipModeId mode_id = UINT32_MAX;
+        chip_->getAvailableModes(
+            [&mode_id, &type](const WifiStatus& status,
+                              const std::vector<WifiChip::ChipMode>& modes) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                for (const auto& mode : modes) {
+                    for (const auto& combination : mode.availableCombinations) {
+                        for (const auto& limit : combination.limits) {
+                            if (limit.types.end() !=
+                                std::find(limit.types.begin(),
+                                          limit.types.end(), type)) {
+                                mode_id = mode.id;
+                            }
+                        }
+                    }
+                }
+            });
+        ASSERT_NE(UINT32_MAX, mode_id);
+
+        chip_->configureChip(mode_id, [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+    }
+
+    // Returns an empty string on error.
+    std::string createIface(const IfaceType& type) {
+        std::string iface_name;
+        if (type == IfaceType::AP) {
+            chip_->createApIface([&iface_name](
+                                     const WifiStatus& status,
+                                     const sp<V1_0::IWifiApIface>& iface) {
+                if (WifiStatusCode::SUCCESS == status.code) {
+                    ASSERT_NE(iface.get(), nullptr);
+                    iface->getName([&iface_name](const WifiStatus& status,
+                                                 const hidl_string& name) {
+                        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                        iface_name = name.c_str();
+                    });
+                }
+            });
+        } else if (type == IfaceType::NAN) {
+            chip_->createNanIface(
+                [&iface_name](
+                    const WifiStatus& status,
+                    const sp<android::hardware::wifi::V1_0::IWifiNanIface>&
+                        iface) {
+                    if (WifiStatusCode::SUCCESS == status.code) {
+                        ASSERT_NE(iface.get(), nullptr);
+                        iface->getName([&iface_name](const WifiStatus& status,
+                                                     const hidl_string& name) {
+                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                            iface_name = name.c_str();
+                        });
+                    }
+                });
+        } else if (type == IfaceType::P2P) {
+            chip_->createP2pIface(
+                [&iface_name](const WifiStatus& status,
+                              const sp<IWifiP2pIface>& iface) {
+                    if (WifiStatusCode::SUCCESS == status.code) {
+                        ASSERT_NE(iface.get(), nullptr);
+                        iface->getName([&iface_name](const WifiStatus& status,
+                                                     const hidl_string& name) {
+                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                            iface_name = name.c_str();
+                        });
+                    }
+                });
+        } else if (type == IfaceType::STA) {
+            chip_->createStaIface(
+                [&iface_name](const WifiStatus& status,
+                              const sp<V1_0::IWifiStaIface>& iface) {
+                    if (WifiStatusCode::SUCCESS == status.code) {
+                        ASSERT_NE(iface.get(), nullptr);
+                        iface->getName([&iface_name](const WifiStatus& status,
+                                                     const hidl_string& name) {
+                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                            iface_name = name.c_str();
+                        });
+                    }
+                });
+        }
+        return iface_name;
+    }
+
+    void removeIface(const IfaceType& type, const std::string& iface_name) {
+        if (type == IfaceType::AP) {
+            chip_->removeApIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        } else if (type == IfaceType::NAN) {
+            chip_->removeNanIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        } else if (type == IfaceType::P2P) {
+            chip_->removeP2pIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        } else if (type == IfaceType::STA) {
+            chip_->removeStaIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        }
+    }
+
+    bool createRttController() {
+        bool success = false;
+        chip_->createRttController_1_4(
+            NULL, [&success](const WifiStatus& status,
+                             const sp<IWifiRttController>& rtt) {
+                if (WifiStatusCode::SUCCESS == status.code) {
+                    ASSERT_NE(rtt.get(), nullptr);
+                    success = true;
+                }
+            });
+        return success;
+    }
+
+    sp<WifiChip> chip_;
+    ChipId chip_id_ = kFakeChipId;
+    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+        new NiceMock<wifi_system::MockInterfaceTool>};
+    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
+    std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
+        mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
+    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+        new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
+    std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
+        feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
+
+   public:
+    void SetUp() override {
+        chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_,
+                             iface_util_, feature_flags_);
+
+        EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
+            .WillRepeatedly(testing::Return(true));
+        EXPECT_CALL(*legacy_hal_, start())
+            .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
+    }
+
+    void TearDown() override {
+        // Restore default system iface names (This should ideally be using a
+        // mock).
+        property_set("wifi.interface", "wlan0");
+        property_set("wifi.concurrent.interface", "wlan1");
+        property_set("wifi.aware.interface", nullptr);
+    }
+};
+
+////////// V1 Iface Combinations ////////////
+// Mode 1 - STA + P2P
+// Mode 2 - AP
+class WifiChipV1IfaceCombinationTest : public WifiChipTest {
+   public:
+    void SetUp() override {
+        setupV1IfaceCombination();
+        WifiChipTest::SetUp();
+        // V1 has 2 modes of operation.
+        assertNumberOfModes(2u);
+    }
+};
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+////////// V1 + Aware Iface Combinations ////////////
+// Mode 1 - STA + P2P/NAN
+// Mode 2 - AP
+class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest {
+   public:
+    void SetUp() override {
+        setupV1_AwareIfaceCombination();
+        WifiChipTest::SetUp();
+        // V1_Aware has 2 modes of operation.
+        assertNumberOfModes(2u);
+    }
+};
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+       StaMode_CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+       StaMode_CreateStaNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+       StaMode_CreateStaP2PNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+       StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+       StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto nan_iface_name = createIface(IfaceType::NAN);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    const auto ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(ap_iface_name.empty());
+    ASSERT_FALSE(createRttController());
+
+    removeIface(IfaceType::AP, ap_iface_name);
+
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+        [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+        [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+}
+
+////////// V2 + Aware Iface Combinations ////////////
+// Mode 1 - STA + STA/AP
+//        - STA + P2P/NAN
+class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest {
+   public:
+    void SetUp() override {
+        setupV2_AwareIfaceCombination();
+        WifiChipTest::SetUp();
+        // V2_Aware has 1 mode of operation.
+        assertNumberOfModes(1u);
+    }
+};
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       CreateSta_AfterStaApRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    const auto sta_iface_name = createIface(IfaceType::STA);
+    ASSERT_FALSE(sta_iface_name.empty());
+    const auto ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(ap_iface_name.empty());
+
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+
+    // After removing AP & STA iface, STA iface creation should succeed.
+    removeIface(IfaceType::STA, sta_iface_name);
+    removeIface(IfaceType::AP, ap_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto nan_iface_name = createIface(IfaceType::NAN);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto nan_iface_name = createIface(IfaceType::NAN);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       CreateStaAp_EnsureDifferentIfaceNames) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    const auto sta_iface_name = createIface(IfaceType::STA);
+    const auto ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(sta_iface_name.empty());
+    ASSERT_FALSE(ap_iface_name.empty());
+    ASSERT_NE(sta_iface_name, ap_iface_name);
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+        [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_))
+        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    chip_->selectTxPowerScenario_1_2(
+        V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF,
+        [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       InvalidateAndRemoveNanOnStaRemove) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+
+    // Create NAN iface
+    ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
+
+    // We should have 1 nan iface.
+    chip_->getNanIfaceNames(
+        [](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            ASSERT_EQ(iface_names.size(), 1u);
+            ASSERT_EQ(iface_names[0], "wlan0");
+        });
+    // Retrieve the exact iface object.
+    sp<android::hardware::wifi::V1_0::IWifiNanIface> nan_iface;
+    chip_->getNanIface(
+        "wlan0",
+        [&nan_iface](
+            const WifiStatus& status,
+            const sp<android::hardware::wifi::V1_0::IWifiNanIface>& iface) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            ASSERT_NE(iface.get(), nullptr);
+            nan_iface = iface;
+        });
+
+    // Remove the STA iface.
+    removeIface(IfaceType::STA, "wlan0");
+    // We should have 0 nan iface now.
+    chip_->getNanIfaceNames(
+        [](const WifiStatus& status, const hidl_vec<hidl_string>& iface_names) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            ASSERT_EQ(iface_names.size(), 0u);
+        });
+    // Any operation on the nan iface object should return error now.
+    nan_iface->getName(
+        [](const WifiStatus& status, const std::string& /* iface_name */) {
+            ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, status.code);
+        });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       InvalidateAndRemoveRttControllerOnStaRemove) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+
+    // Create RTT controller
+    sp<IWifiRttController> rtt_controller;
+    chip_->createRttController_1_4(
+        NULL, [&rtt_controller](const WifiStatus& status,
+                                const sp<IWifiRttController>& rtt) {
+            if (WifiStatusCode::SUCCESS == status.code) {
+                ASSERT_NE(rtt.get(), nullptr);
+                rtt_controller = rtt;
+            }
+        });
+
+    // Remove the STA iface.
+    removeIface(IfaceType::STA, "wlan0");
+
+    // Any operation on the rtt controller object should return error now.
+    rtt_controller->getBoundIface(
+        [](const WifiStatus& status, const sp<IWifiIface>& /* iface */) {
+            ASSERT_EQ(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                      status.code);
+        });
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithSharedNanIface) {
+    property_set("wifi.aware.interface", nullptr);
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::NAN), "wlan0");
+    removeIface(IfaceType::NAN, "wlan0");
+    EXPECT_CALL(*iface_util_, setUpState(testing::_, testing::_)).Times(0);
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithDedicatedNanIface) {
+    property_set("wifi.aware.interface", "aware0");
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*iface_util_, ifNameToIndex("aware0"))
+        .WillOnce(testing::Return(4));
+    EXPECT_CALL(*iface_util_, setUpState("aware0", true))
+        .WillOnce(testing::Return(true));
+    ASSERT_EQ(createIface(IfaceType::NAN), "aware0");
+
+    EXPECT_CALL(*iface_util_, setUpState("aware0", false))
+        .WillOnce(testing::Return(true));
+    removeIface(IfaceType::NAN, "aware0");
+}
+
+////////// V1 Iface Combinations when AP creation is disabled //////////
+class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+   public:
+    void SetUp() override {
+        setupV1_AwareDisabledApIfaceCombination();
+        WifiChipTest::SetUp();
+    }
+};
+
+TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest,
+       StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+////////// V2 Iface Combinations when AP creation is disabled //////////
+class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+   public:
+    void SetUp() override {
+        setupV2_AwareDisabledApIfaceCombination();
+        WifiChipTest::SetUp();
+    }
+};
+
+TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest,
+       CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+////////// Hypothetical Iface Combination with multiple ifaces //////////
+class WifiChip_MultiIfaceTest : public WifiChipTest {
+   public:
+    void SetUp() override {
+        setup_MultiIfaceCombination();
+        WifiChipTest::SetUp();
+    }
+};
+
+TEST_F(WifiChip_MultiIfaceTest, Create3Sta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithDefaultNames) {
+    property_set("wifi.interface.0", "");
+    property_set("wifi.interface.1", "");
+    property_set("wifi.interface.2", "");
+    property_set("wifi.interface", "");
+    property_set("wifi.concurrent.interface", "");
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomNames) {
+    property_set("wifi.interface.0", "test0");
+    property_set("wifi.interface.1", "test1");
+    property_set("wifi.interface.2", "test2");
+    property_set("wifi.interface", "bad0");
+    property_set("wifi.concurrent.interface", "bad1");
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "bad0");
+    ASSERT_EQ(createIface(IfaceType::STA), "bad1");
+    ASSERT_EQ(createIface(IfaceType::STA), "test2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomAltNames) {
+    property_set("wifi.interface.0", "");
+    property_set("wifi.interface.1", "");
+    property_set("wifi.interface.2", "");
+    property_set("wifi.interface", "testA0");
+    property_set("wifi.concurrent.interface", "testA1");
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "testA0");
+    ASSERT_EQ(createIface(IfaceType::STA), "testA1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    // First AP will be slotted to wlan1.
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    // First STA will be slotted to wlan0.
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    // All further STA will be slotted to the remaining free indices.
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
+}
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
new file mode 100644
index 0000000..03394bc
--- /dev/null
+++ b/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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 <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "wifi_iface_util.h"
+
+#include "mock_interface_tool.h"
+
+using testing::NiceMock;
+using testing::Test;
+
+namespace {
+constexpr uint8_t kValidUnicastLocallyAssignedMacAddressMask = 0x02;
+constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
+constexpr char kIfaceName[] = "test-wlan0";
+
+bool isValidUnicastLocallyAssignedMacAddress(
+    const std::array<uint8_t, 6>& mac_address) {
+    uint8_t first_byte = mac_address[0];
+    return (first_byte & 0x3) == kValidUnicastLocallyAssignedMacAddressMask;
+}
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace iface_util {
+class WifiIfaceUtilTest : public Test {
+   protected:
+    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+        new NiceMock<wifi_system::MockInterfaceTool>};
+    WifiIfaceUtil* iface_util_ = new WifiIfaceUtil(iface_tool_);
+};
+
+TEST_F(WifiIfaceUtilTest, GetOrCreateRandomMacAddress) {
+    auto mac_address = iface_util_->getOrCreateRandomMacAddress();
+    ASSERT_TRUE(isValidUnicastLocallyAssignedMacAddress(mac_address));
+
+    // All further calls should return the same MAC address.
+    ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
+    ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
+}
+
+TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) {
+    std::array<uint8_t, 6> mac_address = {};
+    std::copy(std::begin(kMacAddress), std::end(kMacAddress),
+              std::begin(mac_address));
+    EXPECT_CALL(*iface_tool_, SetMacAddress(testing::_, testing::_))
+        .WillRepeatedly(testing::Return(true));
+    EXPECT_CALL(*iface_tool_, SetUpState(testing::_, testing::_))
+        .WillRepeatedly(testing::Return(true));
+
+    // Register for iface state toggle events.
+    bool callback_invoked = false;
+    iface_util::IfaceEventHandlers event_handlers = {};
+    event_handlers.on_state_toggle_off_on =
+        [&callback_invoked](const std::string& /* iface_name */) {
+            callback_invoked = true;
+        };
+    iface_util_->registerIfaceEventHandlers(kIfaceName, event_handlers);
+    // Invoke setMacAddress and ensure that the cb is invoked.
+    ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
+    ASSERT_TRUE(callback_invoked);
+
+    // Unregister for iface state toggle events.
+    callback_invoked = false;
+    iface_util_->unregisterIfaceEventHandlers(kIfaceName);
+    // Invoke setMacAddress and ensure that the cb is not invoked.
+    ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
+    ASSERT_FALSE(callback_invoked);
+}
+}  // namespace iface_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
new file mode 100644
index 0000000..70424db
--- /dev/null
+++ b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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 <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "wifi_nan_iface.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+constexpr char kIfaceName[] = "mockWlan0";
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+using android::hardware::wifi::V1_2::IWifiNanIfaceEventCallback;
+using android::hardware::wifi::V1_2::NanDataPathConfirmInd;
+
+bool CaptureIfaceEventHandlers(
+    const std::string& /* iface_name*/,
+    iface_util::IfaceEventHandlers in_iface_event_handlers,
+    iface_util::IfaceEventHandlers* out_iface_event_handlers) {
+    *out_iface_event_handlers = in_iface_event_handlers;
+    return true;
+}
+
+class MockNanIfaceEventCallback : public IWifiNanIfaceEventCallback {
+   public:
+    MockNanIfaceEventCallback() = default;
+
+    MOCK_METHOD3(notifyCapabilitiesResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&,
+                              const NanCapabilities&));
+    MOCK_METHOD2(notifyEnableResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyConfigResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyDisableResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD3(notifyStartPublishResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
+    MOCK_METHOD2(notifyStopPublishResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD3(notifyStartSubscribeResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&, uint8_t));
+    MOCK_METHOD2(notifyStopSubscribeResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyTransmitFollowupResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyCreateDataInterfaceResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyDeleteDataInterfaceResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD3(notifyInitiateDataPathResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&, uint32_t));
+    MOCK_METHOD2(notifyRespondToDataPathIndicationResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD2(notifyTerminateDataPathResponse,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD1(eventClusterEvent, Return<void>(const NanClusterEventInd&));
+    MOCK_METHOD1(eventDisabled, Return<void>(const WifiNanStatus&));
+    MOCK_METHOD2(eventPublishTerminated,
+                 Return<void>(uint8_t, const WifiNanStatus&));
+    MOCK_METHOD2(eventSubscribeTerminated,
+                 Return<void>(uint8_t, const WifiNanStatus&));
+    MOCK_METHOD1(eventMatch, Return<void>(const NanMatchInd&));
+    MOCK_METHOD2(eventMatchExpired, Return<void>(uint8_t, uint32_t));
+    MOCK_METHOD1(eventFollowupReceived,
+                 Return<void>(const NanFollowupReceivedInd&));
+    MOCK_METHOD2(eventTransmitFollowup,
+                 Return<void>(uint16_t, const WifiNanStatus&));
+    MOCK_METHOD1(eventDataPathRequest,
+                 Return<void>(const NanDataPathRequestInd&));
+    MOCK_METHOD1(
+        eventDataPathConfirm,
+        Return<void>(
+            const android::hardware::wifi::V1_0::NanDataPathConfirmInd&));
+    MOCK_METHOD1(eventDataPathTerminated, Return<void>(uint32_t));
+    MOCK_METHOD1(eventDataPathConfirm_1_2,
+                 Return<void>(const NanDataPathConfirmInd&));
+    MOCK_METHOD1(eventDataPathScheduleUpdate,
+                 Return<void>(const NanDataPathScheduleUpdateInd&));
+};
+
+class WifiNanIfaceTest : public Test {
+   protected:
+    std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
+        new NiceMock<wifi_system::MockInterfaceTool>};
+    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
+    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+        new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
+};
+
+TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) {
+    iface_util::IfaceEventHandlers captured_iface_event_handlers = {};
+    EXPECT_CALL(*legacy_hal_,
+                nanRegisterCallbackHandlers(testing::_, testing::_))
+        .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    EXPECT_CALL(*iface_util_,
+                registerIfaceEventHandlers(testing::_, testing::_))
+        .WillOnce(testing::Invoke(
+            bind(CaptureIfaceEventHandlers, std::placeholders::_1,
+                 std::placeholders::_2, &captured_iface_event_handlers)));
+    sp<WifiNanIface> nan_iface =
+        new WifiNanIface(kIfaceName, false, legacy_hal_, iface_util_);
+
+    // Register a mock nan event callback.
+    sp<NiceMock<MockNanIfaceEventCallback>> mock_event_callback{
+        new NiceMock<MockNanIfaceEventCallback>};
+    nan_iface->registerEventCallback(
+        mock_event_callback, [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+    // Ensure that the eventDisabled() function in mock callback will be
+    // invoked.
+    WifiNanStatus expected_nan_status = {
+        NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
+    EXPECT_CALL(*mock_event_callback, eventDisabled(expected_nan_status))
+        .Times(1);
+
+    // Trigger the iface state toggle callback.
+    captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
+}
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi.cpp b/wifi/1.4/default/wifi.cpp
new file mode 100644
index 0000000..9c6b0f0
--- /dev/null
+++ b/wifi/1.4/default/wifi.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_return_util.h"
+#include "wifi.h"
+#include "wifi_status_util.h"
+
+namespace {
+// Chip ID to use for the only supported chip.
+static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
+
+Wifi::Wifi(
+    const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
+    const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
+    const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+    const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+    : iface_tool_(iface_tool),
+      legacy_hal_(legacy_hal),
+      mode_controller_(mode_controller),
+      iface_util_(iface_util),
+      feature_flags_(feature_flags),
+      run_state_(RunState::STOPPED) {}
+
+bool Wifi::isValid() {
+    // This object is always valid.
+    return true;
+}
+
+Return<void> Wifi::registerEventCallback(
+    const sp<IWifiEventCallback>& event_callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::registerEventCallbackInternal, hidl_status_cb,
+                           event_callback);
+}
+
+Return<bool> Wifi::isStarted() { return run_state_ != RunState::STOPPED; }
+
+Return<void> Wifi::start(start_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::startInternal, hidl_status_cb);
+}
+
+Return<void> Wifi::stop(stop_cb hidl_status_cb) {
+    return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN,
+                                   &Wifi::stopInternal, hidl_status_cb);
+}
+
+Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::getChipIdsInternal, hidl_status_cb);
+}
+
+Return<void> Wifi::getChip(ChipId chip_id, getChip_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::getChipInternal, hidl_status_cb, chip_id);
+}
+
+Return<void> Wifi::debug(const hidl_handle& handle,
+                         const hidl_vec<hidl_string>&) {
+    LOG(INFO) << "-----------Debug is called----------------";
+    if (!chip_.get()) {
+        return Void();
+    }
+    return chip_->debug(handle, {});
+}
+
+WifiStatus Wifi::registerEventCallbackInternal(
+    const sp<IWifiEventCallback>& event_callback) {
+    if (!event_cb_handler_.addCallback(event_callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::startInternal() {
+    if (run_state_ == RunState::STARTED) {
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    } else if (run_state_ == RunState::STOPPING) {
+        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
+                                "HAL is stopping");
+    }
+    WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
+    if (wifi_status.code == WifiStatusCode::SUCCESS) {
+        // Create the chip instance once the HAL is started.
+        chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
+                             iface_util_, feature_flags_);
+        run_state_ = RunState::STARTED;
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onStart().isOk()) {
+                LOG(ERROR) << "Failed to invoke onStart callback";
+            };
+        }
+        LOG(INFO) << "Wifi HAL started";
+    } else {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onFailure(wifi_status).isOk()) {
+                LOG(ERROR) << "Failed to invoke onFailure callback";
+            }
+        }
+        LOG(ERROR) << "Wifi HAL start failed";
+        // Clear the event callback objects since the HAL start failed.
+        event_cb_handler_.invalidate();
+    }
+    return wifi_status;
+}
+
+WifiStatus Wifi::stopInternal(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+    if (run_state_ == RunState::STOPPED) {
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    } else if (run_state_ == RunState::STOPPING) {
+        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
+                                "HAL is stopping");
+    }
+    // Clear the chip object and its child objects since the HAL is now
+    // stopped.
+    if (chip_.get()) {
+        chip_->invalidate();
+        chip_.clear();
+    }
+    WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
+    if (wifi_status.code == WifiStatusCode::SUCCESS) {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onStop().isOk()) {
+                LOG(ERROR) << "Failed to invoke onStop callback";
+            };
+        }
+        LOG(INFO) << "Wifi HAL stopped";
+    } else {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onFailure(wifi_status).isOk()) {
+                LOG(ERROR) << "Failed to invoke onFailure callback";
+            }
+        }
+        LOG(ERROR) << "Wifi HAL stop failed";
+    }
+    // Clear the event callback objects since the HAL is now stopped.
+    event_cb_handler_.invalidate();
+    return wifi_status;
+}
+
+std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
+    std::vector<ChipId> chip_ids;
+    if (chip_.get()) {
+        chip_ids.emplace_back(kChipId);
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
+}
+
+std::pair<WifiStatus, sp<IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
+    if (!chip_.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_STARTED), nullptr};
+    }
+    if (chip_id != kChipId) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
+}
+
+WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
+    if (!mode_controller_->initialize()) {
+        LOG(ERROR) << "Failed to initialize firmware mode controller";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to initialize legacy HAL: "
+                   << legacyErrorToString(legacy_status);
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+    run_state_ = RunState::STOPPING;
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; });
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to stop legacy HAL: "
+                   << legacyErrorToString(legacy_status);
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    if (!mode_controller_->deinitialize()) {
+        LOG(ERROR) << "Failed to deinitialize firmware mode controller";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi.h b/wifi/1.4/default/wifi.h
new file mode 100644
index 0000000..087d6f7
--- /dev/null
+++ b/wifi/1.4/default/wifi.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_H_
+#define WIFI_H_
+
+#include <functional>
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.4/IWifi.h>
+#include <utils/Looper.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_chip.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+/**
+ * Root HIDL interface object used to control the Wifi HAL.
+ */
+class Wifi : public V1_4::IWifi {
+   public:
+    Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
+         const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+         const std::shared_ptr<mode_controller::WifiModeController>
+             mode_controller,
+         const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+         const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+
+    bool isValid();
+
+    // HIDL methods exposed.
+    Return<void> registerEventCallback(
+        const sp<IWifiEventCallback>& event_callback,
+        registerEventCallback_cb hidl_status_cb) override;
+    Return<bool> isStarted() override;
+    Return<void> start(start_cb hidl_status_cb) override;
+    Return<void> stop(stop_cb hidl_status_cb) override;
+    Return<void> getChipIds(getChipIds_cb hidl_status_cb) override;
+    Return<void> getChip(ChipId chip_id, getChip_cb hidl_status_cb) override;
+    Return<void> debug(const hidl_handle& handle,
+                       const hidl_vec<hidl_string>& options) override;
+
+   private:
+    enum class RunState { STOPPED, STARTED, STOPPING };
+
+    // Corresponding worker functions for the HIDL methods.
+    WifiStatus registerEventCallbackInternal(
+        const sp<IWifiEventCallback>& event_callback);
+    WifiStatus startInternal();
+    WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
+    std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
+    std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
+
+    WifiStatus initializeModeControllerAndLegacyHal();
+    WifiStatus stopLegacyHalAndDeinitializeModeController(
+        std::unique_lock<std::recursive_mutex>* lock);
+
+    // Instance is created in this root level |IWifi| HIDL interface object
+    // and shared with all the child HIDL interface objects.
+    std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
+    std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
+    std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
+    RunState run_state_;
+    sp<WifiChip> chip_;
+    hidl_callback_util::HidlCallbackHandler<IWifiEventCallback>
+        event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(Wifi);
+};
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_H_
diff --git a/wifi/1.4/default/wifi_ap_iface.cpp b/wifi/1.4/default/wifi_ap_iface.cpp
new file mode 100644
index 0000000..8777a4c
--- /dev/null
+++ b/wifi/1.4/default/wifi_ap_iface.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_ap_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiApIface::WifiApIface(
+    const std::string& ifname,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+    : ifname_(ifname),
+      legacy_hal_(legacy_hal),
+      iface_util_(iface_util),
+      is_valid_(true) {}
+
+void WifiApIface::invalidate() {
+    legacy_hal_.reset();
+    is_valid_ = false;
+}
+
+bool WifiApIface::isValid() { return is_valid_; }
+
+std::string WifiApIface::getName() { return ifname_; }
+
+Return<void> WifiApIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::setCountryCode(const hidl_array<int8_t, 2>& code,
+                                         setCountryCode_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::setCountryCodeInternal, hidl_status_cb,
+                           code);
+}
+
+Return<void> WifiApIface::getValidFrequenciesForBand(
+    V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getValidFrequenciesForBandInternal,
+                           hidl_status_cb, band);
+}
+
+Return<void> WifiApIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                                        setMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::setMacAddressInternal, hidl_status_cb,
+                           mac);
+}
+
+Return<void> WifiApIface::getFactoryMacAddress(
+    getFactoryMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getFactoryMacAddressInternal,
+                           hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiApIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::AP};
+}
+
+WifiStatus WifiApIface::setCountryCodeInternal(
+    const std::array<int8_t, 2>& code) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setCountryCode(ifname_, code);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+WifiApIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
+    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
+                  "Size mismatch");
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint32_t> valid_frequencies;
+    std::tie(legacy_status, valid_frequencies) =
+        legacy_hal_.lock()->getValidFrequenciesForBand(
+            ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
+    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
+}
+
+WifiStatus WifiApIface::setMacAddressInternal(
+    const std::array<uint8_t, 6>& mac) {
+    bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
+    if (!status) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::array<uint8_t, 6>>
+WifiApIface::getFactoryMacAddressInternal() {
+    std::array<uint8_t, 6> mac =
+        iface_util_.lock()->getFactoryMacAddress(ifname_);
+    if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 &&
+        mac[4] == 0 && mac[5] == 0) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
+}
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_ap_iface.h b/wifi/1.4/default/wifi_ap_iface.h
new file mode 100644
index 0000000..bf16d5e
--- /dev/null
+++ b/wifi/1.4/default/wifi_ap_iface.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_AP_IFACE_H_
+#define WIFI_AP_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.4/IWifiApIface.h>
+
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a AP Iface instance.
+ */
+class WifiApIface : public V1_4::IWifiApIface {
+   public:
+    WifiApIface(const std::string& ifname,
+                const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+    Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
+                                setCountryCode_cb hidl_status_cb) override;
+    Return<void> getValidFrequenciesForBand(
+        V1_0::WifiBand band,
+        getValidFrequenciesForBand_cb hidl_status_cb) override;
+    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                               setMacAddress_cb hidl_status_cb) override;
+    Return<void> getFactoryMacAddress(
+        getFactoryMacAddress_cb hidl_status_cb) override;
+
+   private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+    WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
+    std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+    getValidFrequenciesForBandInternal(V1_0::WifiBand band);
+    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+    std::pair<WifiStatus, std::array<uint8_t, 6>>
+    getFactoryMacAddressInternal();
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiApIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_AP_IFACE_H_
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
new file mode 100644
index 0000000..8747e61
--- /dev/null
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -0,0 +1,1649 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <fcntl.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <cutils/properties.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_chip.h"
+#include "wifi_status_util.h"
+
+namespace {
+using android::sp;
+using android::base::unique_fd;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::wifi::V1_0::ChipModeId;
+using android::hardware::wifi::V1_0::IfaceType;
+using android::hardware::wifi::V1_0::IWifiChip;
+
+constexpr char kCpioMagic[] = "070701";
+constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3;
+constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
+constexpr uint32_t kMaxRingBufferFileNum = 20;
+constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
+constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
+constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
+constexpr unsigned kMaxWlanIfaces = 5;
+
+template <typename Iface>
+void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
+    iface->invalidate();
+    ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface),
+                 ifaces.end());
+}
+
+template <typename Iface>
+void invalidateAndClearAll(std::vector<sp<Iface>>& ifaces) {
+    for (const auto& iface : ifaces) {
+        iface->invalidate();
+    }
+    ifaces.clear();
+}
+
+template <typename Iface>
+std::vector<hidl_string> getNames(std::vector<sp<Iface>>& ifaces) {
+    std::vector<hidl_string> names;
+    for (const auto& iface : ifaces) {
+        names.emplace_back(iface->getName());
+    }
+    return names;
+}
+
+template <typename Iface>
+sp<Iface> findUsingName(std::vector<sp<Iface>>& ifaces,
+                        const std::string& name) {
+    std::vector<hidl_string> names;
+    for (const auto& iface : ifaces) {
+        if (name == iface->getName()) {
+            return iface;
+        }
+    }
+    return nullptr;
+}
+
+std::string getWlanIfaceName(unsigned idx) {
+    if (idx >= kMaxWlanIfaces) {
+        CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces;
+        return {};
+    }
+
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    if (idx == 0 || idx == 1) {
+        const char* altPropName =
+            (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface";
+        auto res = property_get(altPropName, buffer.data(), nullptr);
+        if (res > 0) return buffer.data();
+    }
+    std::string propName = "wifi.interface." + std::to_string(idx);
+    auto res = property_get(propName.c_str(), buffer.data(), nullptr);
+    if (res > 0) return buffer.data();
+
+    return "wlan" + std::to_string(idx);
+}
+
+// Returns the dedicated iface name if one is defined.
+std::string getApIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    if (property_get("ro.vendor.wifi.sap.interface", buffer.data(), nullptr) ==
+        0) {
+        return {};
+    }
+    return buffer.data();
+}
+
+std::string getP2pIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    property_get("wifi.direct.interface", buffer.data(), "p2p0");
+    return buffer.data();
+}
+
+// Returns the dedicated iface name if one is defined.
+std::string getNanIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    if (property_get("wifi.aware.interface", buffer.data(), nullptr) == 0) {
+        return {};
+    }
+    return buffer.data();
+}
+
+void setActiveWlanIfaceNameProperty(const std::string& ifname) {
+    auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data());
+    if (res != 0) {
+        PLOG(ERROR) << "Failed to set active wlan iface name property";
+    }
+}
+
+// delete files that meet either conditions:
+// 1. older than a predefined time in the wifi tombstone dir.
+// 2. Files in excess to a predefined amount, starting from the oldest ones
+bool removeOldFilesInternal() {
+    time_t now = time(0);
+    const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(
+        opendir(kTombstoneFolderPath), closedir);
+    if (!dir_dump) {
+        PLOG(ERROR) << "Failed to open directory";
+        return false;
+    }
+    struct dirent* dp;
+    bool success = true;
+    std::list<std::pair<const time_t, std::string>> valid_files;
+    while ((dp = readdir(dir_dump.get()))) {
+        if (dp->d_type != DT_REG) {
+            continue;
+        }
+        std::string cur_file_name(dp->d_name);
+        struct stat cur_file_stat;
+        std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+        if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
+            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+            success = false;
+            continue;
+        }
+        const time_t cur_file_time = cur_file_stat.st_mtime;
+        valid_files.push_back(
+            std::pair<const time_t, std::string>(cur_file_time, cur_file_path));
+    }
+    valid_files.sort();  // sort the list of files by last modified time from
+                         // small to big.
+    uint32_t cur_file_count = valid_files.size();
+    for (auto cur_file : valid_files) {
+        if (cur_file_count > kMaxRingBufferFileNum ||
+            cur_file.first < delete_files_before) {
+            if (unlink(cur_file.second.c_str()) != 0) {
+                PLOG(ERROR) << "Error deleting file";
+                success = false;
+            }
+            cur_file_count--;
+        } else {
+            break;
+        }
+    }
+    return success;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name,
+                     size_t file_name_len) {
+    std::array<char, 32 * 1024> read_buf;
+    ssize_t llen =
+        sprintf(read_buf.data(),
+                "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
+                kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid,
+                st.st_gid, static_cast<int>(st.st_nlink),
+                static_cast<int>(st.st_mtime), static_cast<int>(st.st_size),
+                major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
+                minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
+    if (write(out_fd, read_buf.data(), llen) == -1) {
+        PLOG(ERROR) << "Error writing cpio header to file " << file_name;
+        return false;
+    }
+    if (write(out_fd, file_name, file_name_len) == -1) {
+        PLOG(ERROR) << "Error writing filename to file " << file_name;
+        return false;
+    }
+
+    // NUL Pad header up to 4 multiple bytes.
+    llen = (llen + file_name_len) % 4;
+    if (llen != 0) {
+        const uint32_t zero = 0;
+        if (write(out_fd, &zero, 4 - llen) == -1) {
+            PLOG(ERROR) << "Error padding 0s to file " << file_name;
+            return false;
+        }
+    }
+    return true;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
+    // writing content of file
+    std::array<char, 32 * 1024> read_buf;
+    ssize_t llen = st.st_size;
+    size_t n_error = 0;
+    while (llen > 0) {
+        ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
+        if (bytes_read == -1) {
+            PLOG(ERROR) << "Error reading file";
+            return ++n_error;
+        }
+        llen -= bytes_read;
+        if (write(out_fd, read_buf.data(), bytes_read) == -1) {
+            PLOG(ERROR) << "Error writing data to file";
+            return ++n_error;
+        }
+        if (bytes_read == 0) {  // this should never happen, but just in case
+                                // to unstuck from while loop
+            PLOG(ERROR) << "Unexpected read result";
+            n_error++;
+            break;
+        }
+    }
+    llen = st.st_size % 4;
+    if (llen != 0) {
+        const uint32_t zero = 0;
+        if (write(out_fd, &zero, 4 - llen) == -1) {
+            PLOG(ERROR) << "Error padding 0s to file";
+            return ++n_error;
+        }
+    }
+    return n_error;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteFileTrailer(int out_fd) {
+    std::array<char, 4096> read_buf;
+    read_buf.fill(0);
+    if (write(out_fd, read_buf.data(),
+              sprintf(read_buf.data(), "070701%040X%056X%08XTRAILER!!!", 1,
+                      0x0b, 0) +
+                  4) == -1) {
+        PLOG(ERROR) << "Error writing trailing bytes";
+        return false;
+    }
+    return true;
+}
+
+// Archives all files in |input_dir| and writes result into |out_fd|
+// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
+// portion
+size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
+    struct dirent* dp;
+    size_t n_error = 0;
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir),
+                                                       closedir);
+    if (!dir_dump) {
+        PLOG(ERROR) << "Failed to open directory";
+        return ++n_error;
+    }
+    while ((dp = readdir(dir_dump.get()))) {
+        if (dp->d_type != DT_REG) {
+            continue;
+        }
+        std::string cur_file_name(dp->d_name);
+        // string.size() does not include the null terminator. The cpio FreeBSD
+        // file header expects the null character to be included in the length.
+        const size_t file_name_len = cur_file_name.size() + 1;
+        struct stat st;
+        const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+        if (stat(cur_file_path.c_str(), &st) == -1) {
+            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+            n_error++;
+            continue;
+        }
+        const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
+        if (fd_read == -1) {
+            PLOG(ERROR) << "Failed to open file " << cur_file_path;
+            n_error++;
+            continue;
+        }
+        unique_fd file_auto_closer(fd_read);
+        if (!cpioWriteHeader(out_fd, st, cur_file_name.c_str(),
+                             file_name_len)) {
+            return ++n_error;
+        }
+        size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
+        if (write_error) {
+            return n_error + write_error;
+        }
+    }
+    if (!cpioWriteFileTrailer(out_fd)) {
+        return ++n_error;
+    }
+    return n_error;
+}
+
+// Helper function to create a non-const char*.
+std::vector<char> makeCharVec(const std::string& str) {
+    std::vector<char> vec(str.size() + 1);
+    vec.assign(str.begin(), str.end());
+    vec.push_back('\0');
+    return vec;
+}
+
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
+
+WifiChip::WifiChip(
+    ChipId chip_id, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
+    const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+    : chip_id_(chip_id),
+      legacy_hal_(legacy_hal),
+      mode_controller_(mode_controller),
+      iface_util_(iface_util),
+      is_valid_(true),
+      current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
+      modes_(feature_flags.lock()->getChipModes()),
+      debug_ring_buffer_cb_registered_(false) {
+    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+}
+
+void WifiChip::invalidate() {
+    if (!writeRingbufferFilesInternal()) {
+        LOG(ERROR) << "Error writing files to flash";
+    }
+    invalidateAndRemoveAllIfaces();
+    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    is_valid_ = false;
+}
+
+bool WifiChip::isValid() { return is_valid_; }
+
+std::set<sp<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getIdInternal, hidl_status_cb);
+}
+
+// Deprecated support for this callback
+Return<void> WifiChip::registerEventCallback(
+    const sp<V1_0::IWifiChipEventCallback>& event_callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::registerEventCallbackInternal,
+                           hidl_status_cb, event_callback);
+}
+
+Return<void> WifiChip::getCapabilities(getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getAvailableModes(getAvailableModes_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getAvailableModesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::configureChip(ChipModeId mode_id,
+                                     configureChip_cb hidl_status_cb) {
+    return validateAndCallWithLock(
+        this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+        &WifiChip::configureChipInternal, hidl_status_cb, mode_id);
+}
+
+Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getModeInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::requestChipDebugInfo(
+    requestChipDebugInfo_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestChipDebugInfoInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::requestDriverDebugDump(
+    requestDriverDebugDump_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestDriverDebugDumpInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::requestFirmwareDebugDump(
+    requestFirmwareDebugDump_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestFirmwareDebugDumpInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::createApIface(createApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createApIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getApIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getApIface(const hidl_string& ifname,
+                                  getApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getApIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::removeApIface(const hidl_string& ifname,
+                                     removeApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeApIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createNanIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getNanIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getNanIface(const hidl_string& ifname,
+                                   getNanIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getNanIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::removeNanIface(const hidl_string& ifname,
+                                      removeNanIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeNanIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::createP2pIface(createP2pIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createP2pIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getP2pIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getP2pIface(const hidl_string& ifname,
+                                   getP2pIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getP2pIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::removeP2pIface(const hidl_string& ifname,
+                                      removeP2pIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeP2pIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createStaIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getStaIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getStaIface(const hidl_string& ifname,
+                                   getStaIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getStaIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::removeStaIface(const hidl_string& ifname,
+                                      removeStaIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeStaIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::createRttController(
+    const sp<IWifiIface>& bound_iface, createRttController_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createRttControllerInternal,
+                           hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::getDebugRingBuffersStatus(
+    getDebugRingBuffersStatus_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getDebugRingBuffersStatusInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::startLoggingToDebugRingBuffer(
+    const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+    uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
+    startLoggingToDebugRingBuffer_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::startLoggingToDebugRingBufferInternal,
+                           hidl_status_cb, ring_name, verbose_level,
+                           max_interval_in_sec, min_data_size_in_bytes);
+}
+
+Return<void> WifiChip::forceDumpToDebugRingBuffer(
+    const hidl_string& ring_name,
+    forceDumpToDebugRingBuffer_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::forceDumpToDebugRingBufferInternal,
+                           hidl_status_cb, ring_name);
+}
+
+Return<void> WifiChip::flushRingBufferToFile(
+    flushRingBufferToFile_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::flushRingBufferToFileInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::stopLoggingToDebugRingBuffer(
+    stopLoggingToDebugRingBuffer_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::stopLoggingToDebugRingBufferInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::getDebugHostWakeReasonStats(
+    getDebugHostWakeReasonStats_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getDebugHostWakeReasonStatsInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::enableDebugErrorAlerts(
+    bool enable, enableDebugErrorAlerts_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::enableDebugErrorAlertsInternal,
+                           hidl_status_cb, enable);
+}
+
+Return<void> WifiChip::selectTxPowerScenario(
+    V1_1::IWifiChip::TxPowerScenario scenario,
+    selectTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::selectTxPowerScenarioInternal,
+                           hidl_status_cb, scenario);
+}
+
+Return<void> WifiChip::resetTxPowerScenario(
+    resetTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::resetTxPowerScenarioInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::setLatencyMode(LatencyMode mode,
+                                      setLatencyMode_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setLatencyModeInternal, hidl_status_cb,
+                           mode);
+}
+
+Return<void> WifiChip::registerEventCallback_1_2(
+    const sp<V1_2::IWifiChipEventCallback>& event_callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::registerEventCallbackInternal_1_2,
+                           hidl_status_cb, event_callback);
+}
+
+Return<void> WifiChip::selectTxPowerScenario_1_2(
+    TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::selectTxPowerScenarioInternal_1_2,
+                           hidl_status_cb, scenario);
+}
+
+Return<void> WifiChip::getCapabilities_1_3(getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getCapabilitiesInternal_1_3,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::debug(const hidl_handle& handle,
+                             const hidl_vec<hidl_string>&) {
+    if (handle != nullptr && handle->numFds >= 1) {
+        int fd = handle->data[0];
+        if (!writeRingbufferFilesInternal()) {
+            LOG(ERROR) << "Error writing files to flash";
+        }
+        uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
+        if (n_error != 0) {
+            LOG(ERROR) << n_error << " errors occured in cpio function";
+        }
+        fsync(fd);
+    } else {
+        LOG(ERROR) << "File handle error";
+    }
+    return Void();
+}
+
+Return<void> WifiChip::createRttController_1_4(
+    const sp<IWifiIface>& bound_iface,
+    createRttController_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createRttControllerInternal_1_4,
+                           hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::registerEventCallback_1_4(
+    const sp<IWifiChipEventCallback>& event_callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::registerEventCallbackInternal_1_4,
+                           hidl_status_cb, event_callback);
+}
+
+void WifiChip::invalidateAndRemoveAllIfaces() {
+    invalidateAndClearAll(ap_ifaces_);
+    invalidateAndClearAll(nan_ifaces_);
+    invalidateAndClearAll(p2p_ifaces_);
+    invalidateAndClearAll(sta_ifaces_);
+    // Since all the ifaces are invalid now, all RTT controller objects
+    // using those ifaces also need to be invalidated.
+    for (const auto& rtt : rtt_controllers_) {
+        rtt->invalidate();
+    }
+    rtt_controllers_.clear();
+}
+
+void WifiChip::invalidateAndRemoveDependencies(
+    const std::string& removed_iface_name) {
+    for (const auto& nan_iface : nan_ifaces_) {
+        if (nan_iface->getName() == removed_iface_name) {
+            invalidateAndClear(nan_ifaces_, nan_iface);
+            for (const auto& callback : event_cb_handler_.getCallbacks()) {
+                if (!callback
+                         ->onIfaceRemoved(IfaceType::NAN, removed_iface_name)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+                }
+            }
+        }
+    }
+    for (const auto& rtt : rtt_controllers_) {
+        if (rtt->getIfaceName() == removed_iface_name) {
+            invalidateAndClear(rtt_controllers_, rtt);
+        }
+    }
+}
+
+std::pair<WifiStatus, ChipId> WifiChip::getIdInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_};
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal(
+    const sp<V1_0::IWifiChipEventCallback>& /* event_callback */) {
+    // Deprecated support for this callback.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
+    // Deprecated support for this callback.
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
+}
+
+std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
+WifiChip::getAvailableModesInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
+}
+
+WifiStatus WifiChip::configureChipInternal(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+    ChipModeId mode_id) {
+    if (!isValidModeId(mode_id)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    if (mode_id == current_mode_id_) {
+        LOG(DEBUG) << "Already in the specified mode " << mode_id;
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    }
+    WifiStatus status = handleChipConfiguration(lock, mode_id);
+    if (status.code != WifiStatusCode::SUCCESS) {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onChipReconfigureFailure(status).isOk()) {
+                LOG(ERROR)
+                    << "Failed to invoke onChipReconfigureFailure callback";
+            }
+        }
+        return status;
+    }
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onChipReconfigured(mode_id).isOk()) {
+            LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
+        }
+    }
+    current_mode_id_ = mode_id;
+    LOG(INFO) << "Configured chip in mode " << mode_id;
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return status;
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
+    if (!isValidModeId(current_mode_id_)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
+                current_mode_id_};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
+}
+
+std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
+WifiChip::requestChipDebugInfoInternal() {
+    IWifiChip::ChipDebugInfo result;
+    legacy_hal::wifi_error legacy_status;
+    std::string driver_desc;
+    const auto ifname = getFirstActiveWlanIfaceName();
+    std::tie(legacy_status, driver_desc) =
+        legacy_hal_.lock()->getDriverVersion(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get driver version: "
+                   << legacyErrorToString(legacy_status);
+        WifiStatus status = createWifiStatusFromLegacyError(
+            legacy_status, "failed to get driver version");
+        return {status, result};
+    }
+    result.driverDescription = driver_desc.c_str();
+
+    std::string firmware_desc;
+    std::tie(legacy_status, firmware_desc) =
+        legacy_hal_.lock()->getFirmwareVersion(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get firmware version: "
+                   << legacyErrorToString(legacy_status);
+        WifiStatus status = createWifiStatusFromLegacyError(
+            legacy_status, "failed to get firmware version");
+        return {status, result};
+    }
+    result.firmwareDescription = firmware_desc.c_str();
+
+    return {createWifiStatus(WifiStatusCode::SUCCESS), result};
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>>
+WifiChip::requestDriverDebugDumpInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint8_t> driver_dump;
+    std::tie(legacy_status, driver_dump) =
+        legacy_hal_.lock()->requestDriverMemoryDump(
+            getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get driver debug dump: "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status),
+                std::vector<uint8_t>()};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), driver_dump};
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>>
+WifiChip::requestFirmwareDebugDumpInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint8_t> firmware_dump;
+    std::tie(legacy_status, firmware_dump) =
+        legacy_hal_.lock()->requestFirmwareMemoryDump(
+            getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get firmware debug dump: "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
+}
+
+std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::string ifname = allocateApIfaceName();
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->createVirtualInterface(
+            ifname,
+            hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to add interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_, iface_util_);
+    ap_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getApIfaceNamesInternal() {
+    if (ap_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::getApIfaceInternal(
+    const std::string& ifname) {
+    const auto iface = findUsingName(ap_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(ap_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    // Invalidate & remove any dependent objects first.
+    // Note: This is probably not required because we never create
+    // nan/rtt objects over AP iface. But, there is no harm to do it
+    // here and not make that assumption all over the place.
+    invalidateAndRemoveDependencies(ifname);
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->deleteVirtualInterface(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+    }
+    invalidateAndClear(ap_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    bool is_dedicated_iface = true;
+    std::string ifname = getNanIfaceName();
+    if (ifname.empty() || !iface_util_.lock()->ifNameToIndex(ifname)) {
+        // Use the first shared STA iface (wlan0) if a dedicated aware iface is
+        // not defined.
+        ifname = getFirstActiveWlanIfaceName();
+        is_dedicated_iface = false;
+    }
+    sp<WifiNanIface> iface =
+        new WifiNanIface(ifname, is_dedicated_iface, legacy_hal_, iface_util_);
+    nan_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getNanIfaceNamesInternal() {
+    if (nan_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::getNanIfaceInternal(
+    const std::string& ifname) {
+    const auto iface = findUsingName(nan_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(nan_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    invalidateAndClear(nan_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::P2P)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::string ifname = getP2pIfaceName();
+    sp<WifiP2pIface> iface = new WifiP2pIface(ifname, legacy_hal_);
+    p2p_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getP2pIfaceNamesInternal() {
+    if (p2p_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::getP2pIfaceInternal(
+    const std::string& ifname) {
+    const auto iface = findUsingName(p2p_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(p2p_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    invalidateAndClear(p2p_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<V1_3::IWifiStaIface>>
+WifiChip::createStaIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::string ifname = allocateStaIfaceName();
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->createVirtualInterface(
+            ifname,
+            hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::STA));
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to add interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
+    sta_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getStaIfaceNamesInternal() {
+    if (sta_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> WifiChip::getStaIfaceInternal(
+    const std::string& ifname) {
+    const auto iface = findUsingName(sta_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(sta_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    // Invalidate & remove any dependent objects first.
+    invalidateAndRemoveDependencies(ifname);
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->deleteVirtualInterface(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+    }
+    invalidateAndClear(sta_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<V1_0::IWifiRttController>>
+WifiChip::createRttControllerInternal(const sp<IWifiIface>& /*bound_iface*/) {
+    LOG(ERROR) << "createRttController is not supported on this HAL";
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
+WifiChip::getDebugRingBuffersStatusInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_ring_buffer_status>
+        legacy_ring_buffer_status_vec;
+    std::tie(legacy_status, legacy_ring_buffer_status_vec) =
+        legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
+    if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
+            legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS),
+            hidl_ring_buffer_status_vec};
+}
+
+WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
+    const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+    uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
+    WifiStatus status = registerDebugRingBufferCallback();
+    if (status.code != WifiStatusCode::SUCCESS) {
+        return status;
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->startRingBufferLogging(
+            getFirstActiveWlanIfaceName(), ring_name,
+            static_cast<
+                std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(
+                verbose_level),
+            max_interval_in_sec, min_data_size_in_bytes);
+    ringbuffer_map_.insert(std::pair<std::string, Ringbuffer>(
+        ring_name, Ringbuffer(kMaxBufferSizeBytes)));
+    // if verbose logging enabled, turn up HAL daemon logging as well.
+    if (verbose_level < WifiDebugRingBufferVerboseLevel::VERBOSE) {
+        android::base::SetMinimumLogSeverity(android::base::DEBUG);
+    } else {
+        android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(
+    const hidl_string& ring_name) {
+    WifiStatus status = registerDebugRingBufferCallback();
+    if (status.code != WifiStatusCode::SUCCESS) {
+        return status;
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(),
+                                              ring_name);
+
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::flushRingBufferToFileInternal() {
+    if (!writeRingbufferFilesInternal()) {
+        LOG(ERROR) << "Error writing files to flash";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->deregisterRingBufferCallbackHandler(
+            getFirstActiveWlanIfaceName());
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
+WifiChip::getDebugHostWakeReasonStatsInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::WakeReasonStats legacy_stats;
+    std::tie(legacy_status, legacy_stats) =
+        legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    WifiDebugHostWakeReasonStats hidl_stats;
+    if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats,
+                                                              &hidl_stats)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
+    legacy_hal::wifi_error legacy_status;
+    if (enable) {
+        android::wp<WifiChip> weak_ptr_this(this);
+        const auto& on_alert_callback = [weak_ptr_this](
+                                            int32_t error_code,
+                                            std::vector<uint8_t> debug_data) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onDebugErrorAlert(error_code, debug_data)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
+                }
+            }
+        };
+        legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
+            getFirstActiveWlanIfaceName(), on_alert_callback);
+    } else {
+        legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
+            getFirstActiveWlanIfaceName());
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal(
+    V1_1::IWifiChip::TxPowerScenario scenario) {
+    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+        getFirstActiveWlanIfaceName(),
+        hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::resetTxPowerScenarioInternal() {
+    auto legacy_status =
+        legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::setLatencyModeInternal(LatencyMode mode) {
+    auto legacy_status = legacy_hal_.lock()->setLatencyMode(
+        getFirstActiveWlanIfaceName(),
+        hidl_struct_util::convertHidlLatencyModeToLegacy(mode));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal_1_2(
+    const sp<V1_2::IWifiChipEventCallback>& /* event_callback */) {
+    // Deprecated support for this callback.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(
+    TxPowerScenario scenario) {
+    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+        getFirstActiveWlanIfaceName(),
+        hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() {
+    legacy_hal::wifi_error legacy_status;
+    uint32_t legacy_feature_set;
+    uint32_t legacy_logger_feature_set;
+    const auto ifname = getFirstActiveWlanIfaceName();
+    std::tie(legacy_status, legacy_feature_set) =
+        legacy_hal_.lock()->getSupportedFeatureSet(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), 0};
+    }
+    std::tie(legacy_status, legacy_logger_feature_set) =
+        legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        // some devices don't support querying logger feature set
+        legacy_logger_feature_set = 0;
+    }
+    uint32_t hidl_caps;
+    if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
+            legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, sp<IWifiRttController>>
+WifiChip::createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface) {
+    if (sta_ifaces_.size() == 0 &&
+        !canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
+        LOG(ERROR)
+            << "createRttControllerInternal_1_4: Chip cannot support STAs "
+               "(and RTT by extension)";
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    sp<WifiRttController> rtt = new WifiRttController(
+        getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
+    rtt_controllers_.emplace_back(rtt);
+    return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal_1_4(
+    const sp<IWifiChipEventCallback>& event_callback) {
+    if (!event_cb_handler_.addCallback(event_callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::handleChipConfiguration(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+    ChipModeId mode_id) {
+    // If the chip is already configured in a different mode, stop
+    // the legacy HAL and then start it after firmware mode change.
+    if (isValidModeId(current_mode_id_)) {
+        LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_
+                  << " to mode " << mode_id;
+        invalidateAndRemoveAllIfaces();
+        legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->stop(lock, []() {});
+        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "Failed to stop legacy HAL: "
+                       << legacyErrorToString(legacy_status);
+            return createWifiStatusFromLegacyError(legacy_status);
+        }
+    }
+    // Firmware mode change not needed for V2 devices.
+    bool success = true;
+    if (mode_id == feature_flags::chip_mode_ids::kV1Sta) {
+        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
+    } else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) {
+        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
+    }
+    if (!success) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to start legacy HAL: "
+                   << legacyErrorToString(legacy_status);
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    // Every time the HAL is restarted, we need to register the
+    // radio mode change callback.
+    WifiStatus status = registerRadioModeChangeCallback();
+    if (status.code != WifiStatusCode::SUCCESS) {
+        // This probably is not a critical failure?
+        LOG(ERROR) << "Failed to register radio mode change callback";
+    }
+    // Extract and save the version information into property.
+    std::pair<WifiStatus, IWifiChip::ChipDebugInfo> version_info;
+    version_info = WifiChip::requestChipDebugInfoInternal();
+    if (WifiStatusCode::SUCCESS == version_info.first.code) {
+        property_set("vendor.wlan.firmware.version",
+                     version_info.second.firmwareDescription.c_str());
+        property_set("vendor.wlan.driver.version",
+                     version_info.second.driverDescription.c_str());
+    }
+
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::registerDebugRingBufferCallback() {
+    if (debug_ring_buffer_cb_registered_) {
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    }
+
+    android::wp<WifiChip> weak_ptr_this(this);
+    const auto& on_ring_buffer_data_callback =
+        [weak_ptr_this](const std::string& name,
+                        const std::vector<uint8_t>& data,
+                        const legacy_hal::wifi_ring_buffer_status& status) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            WifiDebugRingBufferStatus hidl_status;
+            if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(
+                    status, &hidl_status)) {
+                LOG(ERROR) << "Error converting ring buffer status";
+                return;
+            }
+            {
+                std::unique_lock<std::mutex> lk(shared_ptr_this->lock_t);
+                const auto& target =
+                    shared_ptr_this->ringbuffer_map_.find(name);
+                if (target != shared_ptr_this->ringbuffer_map_.end()) {
+                    Ringbuffer& cur_buffer = target->second;
+                    cur_buffer.append(data);
+                } else {
+                    LOG(ERROR) << "Ringname " << name << " not found";
+                    return;
+                }
+                // unlock
+            }
+        };
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->registerRingBufferCallbackHandler(
+            getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
+
+    if (legacy_status == legacy_hal::WIFI_SUCCESS) {
+        debug_ring_buffer_cb_registered_ = true;
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::registerRadioModeChangeCallback() {
+    android::wp<WifiChip> weak_ptr_this(this);
+    const auto& on_radio_mode_change_callback =
+        [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            std::vector<IWifiChipEventCallback::RadioModeInfo>
+                hidl_radio_mode_infos;
+            if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+                    mac_infos, &hidl_radio_mode_infos)) {
+                LOG(ERROR) << "Error converting wifi mac info";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onRadioModeChange_1_4(hidl_radio_mode_infos)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke onRadioModeChange_1_4"
+                               << " callback on: " << toString(callback);
+                }
+            }
+        };
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
+            getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::vector<IWifiChip::ChipIfaceCombination>
+WifiChip::getCurrentModeIfaceCombinations() {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return {};
+    }
+    for (const auto& mode : modes_) {
+        if (mode.id == current_mode_id_) {
+            return mode.availableCombinations;
+        }
+    }
+    CHECK(0) << "Expected to find iface combinations for current mode!";
+    return {};
+}
+
+// Returns a map indexed by IfaceType with the number of ifaces currently
+// created of the corresponding type.
+std::map<IfaceType, size_t> WifiChip::getCurrentIfaceCombination() {
+    std::map<IfaceType, size_t> iface_counts;
+    iface_counts[IfaceType::AP] = ap_ifaces_.size();
+    iface_counts[IfaceType::NAN] = nan_ifaces_.size();
+    iface_counts[IfaceType::P2P] = p2p_ifaces_.size();
+    iface_counts[IfaceType::STA] = sta_ifaces_.size();
+    return iface_counts;
+}
+
+// This expands the provided iface combinations to a more parseable
+// form. Returns a vector of available combinations possible with the number
+// of ifaces of each type in the combination.
+// This method is a port of HalDeviceManager.expandIfaceCombos() from framework.
+std::vector<std::map<IfaceType, size_t>> WifiChip::expandIfaceCombinations(
+    const IWifiChip::ChipIfaceCombination& combination) {
+    uint32_t num_expanded_combos = 1;
+    for (const auto& limit : combination.limits) {
+        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+            num_expanded_combos *= limit.types.size();
+        }
+    }
+
+    // Allocate the vector of expanded combos and reset all iface counts to 0
+    // in each combo.
+    std::vector<std::map<IfaceType, size_t>> expanded_combos;
+    expanded_combos.resize(num_expanded_combos);
+    for (auto& expanded_combo : expanded_combos) {
+        for (const auto type :
+             {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+            expanded_combo[type] = 0;
+        }
+    }
+    uint32_t span = num_expanded_combos;
+    for (const auto& limit : combination.limits) {
+        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+            span /= limit.types.size();
+            for (uint32_t k = 0; k < num_expanded_combos; ++k) {
+                const auto iface_type =
+                    limit.types[(k / span) % limit.types.size()];
+                expanded_combos[k][iface_type]++;
+            }
+        }
+    }
+    return expanded_combos;
+}
+
+bool WifiChip::canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+    const std::map<IfaceType, size_t>& expanded_combo,
+    IfaceType requested_type) {
+    const auto current_combo = getCurrentIfaceCombination();
+
+    // Check if we have space for 1 more iface of |type| in this combo
+    for (const auto type :
+         {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+        size_t num_ifaces_needed = current_combo.at(type);
+        if (type == requested_type) {
+            num_ifaces_needed++;
+        }
+        size_t num_ifaces_allowed = expanded_combo.at(type);
+        if (num_ifaces_needed > num_ifaces_allowed) {
+            return false;
+        }
+    }
+    return true;
+}
+
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+//    ChipIfaceCombination.
+// b) Check if the requested iface type can be added to the current mode
+//    with the iface combination that is already active.
+bool WifiChip::canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
+    IfaceType requested_type) {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return false;
+    }
+    const auto combinations = getCurrentModeIfaceCombinations();
+    for (const auto& combination : combinations) {
+        const auto expanded_combos = expandIfaceCombinations(combination);
+        for (const auto& expanded_combo : expanded_combos) {
+            if (canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+                    expanded_combo, requested_type)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// Note: This does not consider ifaces already active. It only checks if the
+// provided expanded iface combination can support the requested combo.
+bool WifiChip::canExpandedIfaceComboSupportIfaceCombo(
+    const std::map<IfaceType, size_t>& expanded_combo,
+    const std::map<IfaceType, size_t>& req_combo) {
+    // Check if we have space for 1 more iface of |type| in this combo
+    for (const auto type :
+         {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+        if (req_combo.count(type) == 0) {
+            // Iface of "type" not in the req_combo.
+            continue;
+        }
+        size_t num_ifaces_needed = req_combo.at(type);
+        size_t num_ifaces_allowed = expanded_combo.at(type);
+        if (num_ifaces_needed > num_ifaces_allowed) {
+            return false;
+        }
+    }
+    return true;
+}
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+//    ChipIfaceCombination.
+// b) Check if the requested iface combo can be added to the current mode.
+// Note: This does not consider ifaces already active. It only checks if the
+// current mode can support the requested combo.
+bool WifiChip::canCurrentModeSupportIfaceCombo(
+    const std::map<IfaceType, size_t>& req_combo) {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return false;
+    }
+    const auto combinations = getCurrentModeIfaceCombinations();
+    for (const auto& combination : combinations) {
+        const auto expanded_combos = expandIfaceCombinations(combination);
+        for (const auto& expanded_combo : expanded_combos) {
+            if (canExpandedIfaceComboSupportIfaceCombo(expanded_combo,
+                                                       req_combo)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+//    ChipIfaceCombination.
+// b) Check if the requested iface type can be added to the current mode.
+bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType requested_type) {
+    // Check if we can support atleast 1 iface of type.
+    std::map<IfaceType, size_t> req_iface_combo;
+    req_iface_combo[requested_type] = 1;
+    return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+bool WifiChip::isValidModeId(ChipModeId mode_id) {
+    for (const auto& mode : modes_) {
+        if (mode.id == mode_id) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
+    // Check if we can support atleast 1 STA & 1 AP concurrently.
+    std::map<IfaceType, size_t> req_iface_combo;
+    req_iface_combo[IfaceType::AP] = 1;
+    req_iface_combo[IfaceType::STA] = 1;
+    return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+bool WifiChip::isDualApAllowedInCurrentMode() {
+    // Check if we can support atleast 1 STA & 1 AP concurrently.
+    std::map<IfaceType, size_t> req_iface_combo;
+    req_iface_combo[IfaceType::AP] = 2;
+    return canCurrentModeSupportIfaceCombo(req_iface_combo);
+}
+
+std::string WifiChip::getFirstActiveWlanIfaceName() {
+    if (sta_ifaces_.size() > 0) return sta_ifaces_[0]->getName();
+    if (ap_ifaces_.size() > 0) return ap_ifaces_[0]->getName();
+    // This could happen if the chip call is made before any STA/AP
+    // iface is created. Default to wlan0 for such cases.
+    LOG(WARNING) << "No active wlan interfaces in use! Using default";
+    return getWlanIfaceName(0);
+}
+
+// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
+// not already in use.
+// Note: This doesn't check the actual presence of these interfaces.
+std::string WifiChip::allocateApOrStaIfaceName(uint32_t start_idx) {
+    for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
+        const auto ifname = getWlanIfaceName(idx);
+        if (findUsingName(ap_ifaces_, ifname)) continue;
+        if (findUsingName(sta_ifaces_, ifname)) continue;
+        return ifname;
+    }
+    // This should never happen. We screwed up somewhere if it did.
+    CHECK(false) << "All wlan interfaces in use already!";
+    return {};
+}
+
+// AP iface names start with idx 1 for modes supporting
+// concurrent STA and not dual AP, else start with idx 0.
+std::string WifiChip::allocateApIfaceName() {
+    // Check if we have a dedicated iface for AP.
+    std::string ifname = getApIfaceName();
+    if (!ifname.empty()) {
+        return ifname;
+    }
+    return allocateApOrStaIfaceName((isStaApConcurrencyAllowedInCurrentMode() &&
+                                     !isDualApAllowedInCurrentMode())
+                                        ? 1
+                                        : 0);
+}
+
+// STA iface names start with idx 0.
+// Primary STA iface will always be 0.
+std::string WifiChip::allocateStaIfaceName() {
+    return allocateApOrStaIfaceName(0);
+}
+
+bool WifiChip::writeRingbufferFilesInternal() {
+    if (!removeOldFilesInternal()) {
+        LOG(ERROR) << "Error occurred while deleting old tombstone files";
+        return false;
+    }
+    // write ringbuffers to file
+    {
+        std::unique_lock<std::mutex> lk(lock_t);
+        for (const auto& item : ringbuffer_map_) {
+            const Ringbuffer& cur_buffer = item.second;
+            if (cur_buffer.getData().empty()) {
+                continue;
+            }
+            const std::string file_path_raw =
+                kTombstoneFolderPath + item.first + "XXXXXXXXXX";
+            const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
+            if (dump_fd == -1) {
+                PLOG(ERROR) << "create file failed";
+                return false;
+            }
+            unique_fd file_auto_closer(dump_fd);
+            for (const auto& cur_block : cur_buffer.getData()) {
+                if (write(dump_fd, cur_block.data(),
+                          sizeof(cur_block[0]) * cur_block.size()) == -1) {
+                    PLOG(ERROR) << "Error writing to file";
+                }
+            }
+        }
+        // unlock
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h
new file mode 100644
index 0000000..98e18bb
--- /dev/null
+++ b/wifi/1.4/default/wifi_chip.h
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_CHIP_H_
+#define WIFI_CHIP_H_
+
+#include <list>
+#include <map>
+#include <mutex>
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.4/IWifiChip.h>
+#include <android/hardware/wifi/1.4/IWifiRttController.h>
+
+#include "hidl_callback_util.h"
+#include "ringbuffer.h"
+#include "wifi_ap_iface.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+#include "wifi_nan_iface.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_sta_iface.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a Wifi HAL chip instance.
+ * Since there is only a single chip instance used today, there is no
+ * identifying handle information stored here.
+ */
+class WifiChip : public V1_4::IWifiChip {
+   public:
+    WifiChip(
+        ChipId chip_id,
+        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+        const std::weak_ptr<mode_controller::WifiModeController>
+            mode_controller,
+        const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
+        const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+    // HIDL does not provide a built-in mechanism to let the server invalidate
+    // a HIDL interface object after creation. If any client process holds onto
+    // a reference to the object in their context, any method calls on that
+    // reference will continue to be directed to the server.
+    //
+    // However Wifi HAL needs to control the lifetime of these objects. So, add
+    // a public |invalidate| method to |WifiChip| and it's child objects. This
+    // will be used to mark an object invalid when either:
+    // a) Wifi HAL is stopped, or
+    // b) Wifi Chip is reconfigured.
+    //
+    // All HIDL method implementations should check if the object is still
+    // marked valid before processing them.
+    void invalidate();
+    bool isValid();
+    std::set<sp<IWifiChipEventCallback>> getEventCallbacks();
+
+    // HIDL methods exposed.
+    Return<void> getId(getId_cb hidl_status_cb) override;
+    // Deprecated support for this callback
+    Return<void> registerEventCallback(
+        const sp<V1_0::IWifiChipEventCallback>& event_callback,
+        registerEventCallback_cb hidl_status_cb) override;
+    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+    Return<void> getAvailableModes(
+        getAvailableModes_cb hidl_status_cb) override;
+    Return<void> configureChip(ChipModeId mode_id,
+                               configureChip_cb hidl_status_cb) override;
+    Return<void> getMode(getMode_cb hidl_status_cb) override;
+    Return<void> requestChipDebugInfo(
+        requestChipDebugInfo_cb hidl_status_cb) override;
+    Return<void> requestDriverDebugDump(
+        requestDriverDebugDump_cb hidl_status_cb) override;
+    Return<void> requestFirmwareDebugDump(
+        requestFirmwareDebugDump_cb hidl_status_cb) override;
+    Return<void> createApIface(createApIface_cb hidl_status_cb) override;
+    Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
+    Return<void> getApIface(const hidl_string& ifname,
+                            getApIface_cb hidl_status_cb) override;
+    Return<void> removeApIface(const hidl_string& ifname,
+                               removeApIface_cb hidl_status_cb) override;
+    Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
+    Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
+    Return<void> getNanIface(const hidl_string& ifname,
+                             getNanIface_cb hidl_status_cb) override;
+    Return<void> removeNanIface(const hidl_string& ifname,
+                                removeNanIface_cb hidl_status_cb) override;
+    Return<void> createP2pIface(createP2pIface_cb hidl_status_cb) override;
+    Return<void> getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) override;
+    Return<void> getP2pIface(const hidl_string& ifname,
+                             getP2pIface_cb hidl_status_cb) override;
+    Return<void> removeP2pIface(const hidl_string& ifname,
+                                removeP2pIface_cb hidl_status_cb) override;
+    Return<void> createStaIface(createStaIface_cb hidl_status_cb) override;
+    Return<void> getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) override;
+    Return<void> getStaIface(const hidl_string& ifname,
+                             getStaIface_cb hidl_status_cb) override;
+    Return<void> removeStaIface(const hidl_string& ifname,
+                                removeStaIface_cb hidl_status_cb) override;
+    Return<void> createRttController(
+        const sp<IWifiIface>& bound_iface,
+        createRttController_cb hidl_status_cb) override;
+    Return<void> getDebugRingBuffersStatus(
+        getDebugRingBuffersStatus_cb hidl_status_cb) override;
+    Return<void> startLoggingToDebugRingBuffer(
+        const hidl_string& ring_name,
+        WifiDebugRingBufferVerboseLevel verbose_level,
+        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
+        startLoggingToDebugRingBuffer_cb hidl_status_cb) override;
+    Return<void> forceDumpToDebugRingBuffer(
+        const hidl_string& ring_name,
+        forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
+    Return<void> flushRingBufferToFile(
+        flushRingBufferToFile_cb hidl_status_cb) override;
+    Return<void> stopLoggingToDebugRingBuffer(
+        stopLoggingToDebugRingBuffer_cb hidl_status_cb) override;
+    Return<void> getDebugHostWakeReasonStats(
+        getDebugHostWakeReasonStats_cb hidl_status_cb) override;
+    Return<void> enableDebugErrorAlerts(
+        bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
+    Return<void> selectTxPowerScenario(
+        V1_1::IWifiChip::TxPowerScenario scenario,
+        selectTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> resetTxPowerScenario(
+        resetTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> setLatencyMode(LatencyMode mode,
+                                setLatencyMode_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_2(
+        const sp<V1_2::IWifiChipEventCallback>& event_callback,
+        registerEventCallback_1_2_cb hidl_status_cb) override;
+    Return<void> selectTxPowerScenario_1_2(
+        TxPowerScenario scenario,
+        selectTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> getCapabilities_1_3(
+        getCapabilities_cb hidl_status_cb) override;
+    Return<void> debug(const hidl_handle& handle,
+                       const hidl_vec<hidl_string>& options) override;
+    Return<void> createRttController_1_4(
+        const sp<IWifiIface>& bound_iface,
+        createRttController_1_4_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_4(
+        const sp<IWifiChipEventCallback>& event_callback,
+        registerEventCallback_1_4_cb hidl_status_cb) override;
+
+   private:
+    void invalidateAndRemoveAllIfaces();
+    // When a STA iface is removed any dependent NAN-ifaces/RTT-controllers are
+    // invalidated & removed.
+    void invalidateAndRemoveDependencies(const std::string& removed_iface_name);
+
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, ChipId> getIdInternal();
+    // Deprecated support for this callback
+    WifiStatus registerEventCallbackInternal(
+        const sp<V1_0::IWifiChipEventCallback>& event_callback);
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
+    std::pair<WifiStatus, std::vector<ChipMode>> getAvailableModesInternal();
+    WifiStatus configureChipInternal(
+        std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
+    std::pair<WifiStatus, uint32_t> getModeInternal();
+    std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
+    requestChipDebugInfoInternal();
+    std::pair<WifiStatus, std::vector<uint8_t>>
+    requestDriverDebugDumpInternal();
+    std::pair<WifiStatus, std::vector<uint8_t>>
+    requestFirmwareDebugDumpInternal();
+    std::pair<WifiStatus, sp<IWifiApIface>> createApIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
+    std::pair<WifiStatus, sp<IWifiApIface>> getApIfaceInternal(
+        const std::string& ifname);
+    WifiStatus removeApIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<IWifiNanIface>> createNanIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
+    std::pair<WifiStatus, sp<IWifiNanIface>> getNanIfaceInternal(
+        const std::string& ifname);
+    WifiStatus removeNanIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
+    std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(
+        const std::string& ifname);
+    WifiStatus removeP2pIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> createStaIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
+    std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> getStaIfaceInternal(
+        const std::string& ifname);
+    WifiStatus removeStaIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<V1_0::IWifiRttController>>
+    createRttControllerInternal(const sp<IWifiIface>& bound_iface);
+    std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
+    getDebugRingBuffersStatusInternal();
+    WifiStatus startLoggingToDebugRingBufferInternal(
+        const hidl_string& ring_name,
+        WifiDebugRingBufferVerboseLevel verbose_level,
+        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes);
+    WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
+    WifiStatus flushRingBufferToFileInternal();
+    WifiStatus stopLoggingToDebugRingBufferInternal();
+    std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
+    getDebugHostWakeReasonStatsInternal();
+    WifiStatus enableDebugErrorAlertsInternal(bool enable);
+    WifiStatus selectTxPowerScenarioInternal(
+        V1_1::IWifiChip::TxPowerScenario scenario);
+    WifiStatus resetTxPowerScenarioInternal();
+    WifiStatus setLatencyModeInternal(LatencyMode mode);
+    WifiStatus registerEventCallbackInternal_1_2(
+        const sp<V1_2::IWifiChipEventCallback>& event_callback);
+    WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3();
+    std::pair<WifiStatus, sp<IWifiRttController>>
+    createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface);
+    WifiStatus registerEventCallbackInternal_1_4(
+        const sp<IWifiChipEventCallback>& event_callback);
+
+    WifiStatus handleChipConfiguration(
+        std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
+    WifiStatus registerDebugRingBufferCallback();
+    WifiStatus registerRadioModeChangeCallback();
+
+    std::vector<IWifiChip::ChipIfaceCombination>
+    getCurrentModeIfaceCombinations();
+    std::map<IfaceType, size_t> getCurrentIfaceCombination();
+    std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
+        const IWifiChip::ChipIfaceCombination& combination);
+    bool canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
+        const std::map<IfaceType, size_t>& expanded_combo,
+        IfaceType requested_type);
+    bool canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(
+        IfaceType requested_type);
+    bool canExpandedIfaceComboSupportIfaceCombo(
+        const std::map<IfaceType, size_t>& expanded_combo,
+        const std::map<IfaceType, size_t>& req_combo);
+    bool canCurrentModeSupportIfaceCombo(
+        const std::map<IfaceType, size_t>& req_combo);
+    bool canCurrentModeSupportIfaceOfType(IfaceType requested_type);
+    bool isValidModeId(ChipModeId mode_id);
+    bool isStaApConcurrencyAllowedInCurrentMode();
+    bool isDualApAllowedInCurrentMode();
+    std::string getFirstActiveWlanIfaceName();
+    std::string allocateApOrStaIfaceName(uint32_t start_idx);
+    std::string allocateApIfaceName();
+    std::string allocateStaIfaceName();
+    bool writeRingbufferFilesInternal();
+
+    ChipId chip_id_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
+    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    std::vector<sp<WifiApIface>> ap_ifaces_;
+    std::vector<sp<WifiNanIface>> nan_ifaces_;
+    std::vector<sp<WifiP2pIface>> p2p_ifaces_;
+    std::vector<sp<WifiStaIface>> sta_ifaces_;
+    std::vector<sp<WifiRttController>> rtt_controllers_;
+    std::map<std::string, Ringbuffer> ringbuffer_map_;
+    bool is_valid_;
+    // Members pertaining to chip configuration.
+    uint32_t current_mode_id_;
+    std::mutex lock_t;
+    std::vector<IWifiChip::ChipMode> modes_;
+    // The legacy ring buffer callback API has only a global callback
+    // registration mechanism. Use this to check if we have already
+    // registered a callback.
+    bool debug_ring_buffer_cb_registered_;
+    hidl_callback_util::HidlCallbackHandler<IWifiChipEventCallback>
+        event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiChip);
+};
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_CHIP_H_
diff --git a/wifi/1.4/default/wifi_feature_flags.cpp b/wifi/1.4/default/wifi_feature_flags.cpp
new file mode 100644
index 0000000..195b460
--- /dev/null
+++ b/wifi/1.4/default/wifi_feature_flags.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace feature_flags {
+
+using V1_0::ChipModeId;
+using V1_0::IfaceType;
+using V1_0::IWifiChip;
+
+/* The chip may either have a single mode supporting any number of combinations,
+ * or a fixed dual-mode (so it involves firmware loading to switch between
+ * modes) setting. If there is a need to support more modes, it needs to be
+ * implemented manually in WiFi HAL (see changeFirmwareMode in
+ * WifiChip::handleChipConfiguration).
+ *
+ * Supported combinations are defined in device's makefile, for example:
+ *    WIFI_HAL_INTERFACE_COMBINATIONS := {{{STA, AP}, 1}, {{P2P, NAN}, 1}},
+ *    WIFI_HAL_INTERFACE_COMBINATIONS += {{{STA}, 1}, {{AP}, 2}}
+ * What means:
+ *    Interface combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface
+ *                             operations.
+ *    Interface combination 2: 1 STA and 2 AP concurrent iface operations.
+ *
+ * For backward compatibility, the following makefile flags can be used to
+ * generate combinations list:
+ *  - WIFI_HIDL_FEATURE_DUAL_INTERFACE
+ *  - WIFI_HIDL_FEATURE_DISABLE_AP
+ *  - WIFI_HIDL_FEATURE_AWARE
+ * However, they are ignored if WIFI_HAL_INTERFACE_COMBINATIONS was provided.
+ * With WIFI_HIDL_FEATURE_DUAL_INTERFACE flag set, there is a single mode with
+ * two interface combinations:
+ *    Interface Combination 1: Will support 1 STA and 1 P2P or NAN (optional)
+ *                             concurrent iface operations.
+ *    Interface Combination 2: Will support 1 STA and 1 AP concurrent
+ *                             iface operations.
+ *
+ * The only dual-mode configuration supported is for alternating STA and AP
+ * mode, that may involve firmware reloading. In such case, there are 2 separate
+ * modes of operation with 1 interface combination each:
+ *    Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN (optional)
+ *                       concurrent iface operations.
+ *    Mode 2 (AP mode): Will support 1 AP iface operation.
+ *
+ * If Aware is enabled, the iface combination will be modified to support either
+ * P2P or NAN in place of just P2P.
+ */
+// clang-format off
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
+#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE)
+// former V2 (fixed dual interface) setup expressed as V3
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV3;
+#  ifdef WIFI_HIDL_FEATURE_DISABLE_AP
+#    ifdef WIFI_HIDL_FEATURE_AWARE
+//     1 STA + 1 of (P2P or NAN)
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
+#    else
+//     1 STA + 1 P2P
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
+#    endif
+#  else
+#    ifdef WIFI_HIDL_FEATURE_AWARE
+//     (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
+                                              {{{STA}, 1}, {{P2P, NAN}, 1}}
+#    else
+//     (1 STA + 1 AP) or (1 STA + 1 P2P)
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
+                                              {{{STA}, 1}, {{P2P}, 1}}
+#    endif
+#  endif
+#else
+// V1 (fixed single interface, dual-mode chip)
+constexpr ChipModeId kMainModeId = chip_mode_ids::kV1Sta;
+#  ifdef WIFI_HIDL_FEATURE_AWARE
+//   1 STA + 1 of (P2P or NAN)
+#    define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
+#  else
+//   1 STA + 1 P2P
+#    define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
+#  endif
+
+#  ifndef WIFI_HIDL_FEATURE_DISABLE_AP
+#    define WIFI_HAL_INTERFACE_COMBINATIONS_AP {{{AP}, 1}}
+#  endif
+#endif
+// clang-format on
+
+/**
+ * Helper class to convert a collection of combination limits to a combination.
+ *
+ * The main point here is to simplify the syntax required by
+ * WIFI_HAL_INTERFACE_COMBINATIONS.
+ */
+struct ChipIfaceCombination
+    : public hidl_vec<IWifiChip::ChipIfaceCombinationLimit> {
+    ChipIfaceCombination(
+        const std::initializer_list<IWifiChip::ChipIfaceCombinationLimit> list)
+        : hidl_vec(list) {}
+
+    operator IWifiChip::ChipIfaceCombination() const { return {*this}; }
+
+    static hidl_vec<IWifiChip::ChipIfaceCombination> make_vec(
+        const std::initializer_list<ChipIfaceCombination> list) {
+        return hidl_vec<IWifiChip::ChipIfaceCombination>(  //
+            std::begin(list), std::end(list));
+    }
+};
+
+#define STA IfaceType::STA
+#define AP IfaceType::AP
+#define P2P IfaceType::P2P
+#define NAN IfaceType::NAN
+static const std::vector<IWifiChip::ChipMode> kChipModes{
+    {kMainModeId,
+     ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS})},
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
+    {chip_mode_ids::kV1Ap,
+     ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
+#endif
+};
+#undef STA
+#undef AP
+#undef P2P
+#undef NAN
+
+#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+#pragma message                                                               \
+    "WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \
+    "'config_wifi_ap_randomization_supported' in "                            \
+    "frameworks/base/core/res/res/values/config.xml in the device overlay "   \
+    "instead"
+#endif  // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+
+WifiFeatureFlags::WifiFeatureFlags() {}
+
+std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes() {
+    return kChipModes;
+}
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_feature_flags.h b/wifi/1.4/default/wifi_feature_flags.h
new file mode 100644
index 0000000..292dedf
--- /dev/null
+++ b/wifi/1.4/default/wifi_feature_flags.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_FEATURE_FLAGS_H_
+#define WIFI_FEATURE_FLAGS_H_
+
+#include <android/hardware/wifi/1.2/IWifiChip.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace feature_flags {
+
+namespace chip_mode_ids {
+// These mode ID's should be unique (even across combo versions). Refer to
+// handleChipConfiguration() for it's usage.
+constexpr V1_0::ChipModeId kInvalid = UINT32_MAX;
+// Mode ID's for V1
+constexpr V1_0::ChipModeId kV1Sta = 0;
+constexpr V1_0::ChipModeId kV1Ap = 1;
+// Mode ID for V3
+constexpr V1_0::ChipModeId kV3 = 3;
+}  // namespace chip_mode_ids
+
+class WifiFeatureFlags {
+   public:
+    WifiFeatureFlags();
+    virtual ~WifiFeatureFlags() = default;
+
+    virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
+};
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.4/default/wifi_iface_util.cpp b/wifi/1.4/default/wifi_iface_util.cpp
new file mode 100644
index 0000000..49b7674
--- /dev/null
+++ b/wifi/1.4/default/wifi_iface_util.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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 <net/if.h>
+#include <cstddef>
+#include <iostream>
+#include <limits>
+#include <random>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#undef NAN
+#include "wifi_iface_util.h"
+
+namespace {
+// Constants to set the local bit & clear the multicast bit.
+constexpr uint8_t kMacAddressMulticastMask = 0x01;
+constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace iface_util {
+
+WifiIfaceUtil::WifiIfaceUtil(
+    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+    : iface_tool_(iface_tool),
+      random_mac_address_(nullptr),
+      event_handlers_map_() {}
+
+std::array<uint8_t, 6> WifiIfaceUtil::getFactoryMacAddress(
+    const std::string& iface_name) {
+    return iface_tool_.lock()->GetFactoryMacAddress(iface_name.c_str());
+}
+
+bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
+                                  const std::array<uint8_t, 6>& mac) {
+#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+    if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
+        LOG(ERROR) << "SetUpState(false) failed.";
+        return false;
+    }
+#endif
+    if (!iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac)) {
+        LOG(ERROR) << "SetMacAddress failed.";
+        return false;
+    }
+#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+    if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
+        LOG(ERROR) << "SetUpState(true) failed.";
+        return false;
+    }
+#endif
+    IfaceEventHandlers event_handlers = {};
+    const auto it = event_handlers_map_.find(iface_name);
+    if (it != event_handlers_map_.end()) {
+        event_handlers = it->second;
+    }
+    if (event_handlers.on_state_toggle_off_on != nullptr) {
+        event_handlers.on_state_toggle_off_on(iface_name);
+    }
+    LOG(DEBUG) << "Successfully SetMacAddress.";
+    return true;
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::getOrCreateRandomMacAddress() {
+    if (random_mac_address_) {
+        return *random_mac_address_.get();
+    }
+    random_mac_address_ =
+        std::make_unique<std::array<uint8_t, 6>>(createRandomMacAddress());
+    return *random_mac_address_.get();
+}
+
+void WifiIfaceUtil::registerIfaceEventHandlers(const std::string& iface_name,
+                                               IfaceEventHandlers handlers) {
+    event_handlers_map_[iface_name] = handlers;
+}
+
+void WifiIfaceUtil::unregisterIfaceEventHandlers(
+    const std::string& iface_name) {
+    event_handlers_map_.erase(iface_name);
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::createRandomMacAddress() {
+    std::array<uint8_t, 6> address = {};
+    std::random_device rd;
+    std::default_random_engine engine(rd());
+    std::uniform_int_distribution<uint8_t> dist(
+        std::numeric_limits<uint8_t>::min(),
+        std::numeric_limits<uint8_t>::max());
+    for (size_t i = 0; i < address.size(); i++) {
+        address[i] = dist(engine);
+    }
+    // Set the local bit and clear the multicast bit.
+    address[0] |= kMacAddressLocallyAssignedMask;
+    address[0] &= ~kMacAddressMulticastMask;
+    return address;
+}
+
+bool WifiIfaceUtil::setUpState(const std::string& iface_name, bool request_up) {
+    if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), request_up)) {
+        LOG(ERROR) << "SetUpState to " << request_up << " failed";
+        return false;
+    }
+    return true;
+}
+
+unsigned WifiIfaceUtil::ifNameToIndex(const std::string& iface_name) {
+    return if_nametoindex(iface_name.c_str());
+}
+}  // namespace iface_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_iface_util.h b/wifi/1.4/default/wifi_iface_util.h
new file mode 100644
index 0000000..126b6ca
--- /dev/null
+++ b/wifi/1.4/default/wifi_iface_util.h
@@ -0,0 +1,77 @@
+/*
+ * 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 WIFI_IFACE_UTIL_H_
+#define WIFI_IFACE_UTIL_H_
+
+#include <wifi_system/interface_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace iface_util {
+
+// Iface event handlers.
+struct IfaceEventHandlers {
+    // Callback to be invoked when the iface is set down & up for MAC address
+    // change.
+    std::function<void(const std::string& iface_name)> on_state_toggle_off_on;
+};
+
+/**
+ * Util class for common iface operations.
+ */
+class WifiIfaceUtil {
+   public:
+    WifiIfaceUtil(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+    virtual ~WifiIfaceUtil() = default;
+
+    virtual std::array<uint8_t, 6> getFactoryMacAddress(
+        const std::string& iface_name);
+    virtual bool setMacAddress(const std::string& iface_name,
+                               const std::array<uint8_t, 6>& mac);
+    // Get or create a random MAC address. The MAC address returned from
+    // this method will remain the same throughout the lifetime of the HAL
+    // daemon. (So, changes on every reboot)
+    virtual std::array<uint8_t, 6> getOrCreateRandomMacAddress();
+
+    // Register for any iface event callbacks for the provided interface.
+    virtual void registerIfaceEventHandlers(const std::string& iface_name,
+                                            IfaceEventHandlers handlers);
+    virtual void unregisterIfaceEventHandlers(const std::string& iface_name);
+    virtual bool setUpState(const std::string& iface_name, bool request_up);
+    virtual unsigned ifNameToIndex(const std::string& iface_name);
+
+   private:
+    std::array<uint8_t, 6> createRandomMacAddress();
+
+    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+    std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;
+    std::map<std::string, IfaceEventHandlers> event_handlers_map_;
+};
+
+}  // namespace iface_util
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_IFACE_UTIL_H_
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
new file mode 100644
index 0000000..29123bf
--- /dev/null
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -0,0 +1,1499 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <array>
+#include <chrono>
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+#include <net/if.h>
+
+#include "hidl_sync_util.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+// Constants ported over from the legacy HAL calling code
+// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
+// away when this shim layer is replaced by the real vendor
+// implementation.
+static constexpr uint32_t kMaxVersionStringLength = 256;
+static constexpr uint32_t kMaxCachedGscanResults = 64;
+static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
+static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
+static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
+static constexpr uint32_t kMaxRingBuffers = 10;
+static constexpr uint32_t kMaxStopCompleteWaitMs = 100;
+static constexpr char kDriverPropName[] = "wlan.driver.status";
+
+// Helper function to create a non-const char* for legacy Hal API's.
+std::vector<char> makeCharVec(const std::string& str) {
+    std::vector<char> vec(str.size() + 1);
+    vec.assign(str.begin(), str.end());
+    vec.push_back('\0');
+    return vec;
+}
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace legacy_hal {
+// Legacy HAL functions accept "C" style function pointers, so use global
+// functions to pass to the legacy HAL function and store the corresponding
+// std::function methods to be invoked.
+//
+// Callback to be invoked once |stop| is complete
+std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
+void onAsyncStopComplete(wifi_handle handle) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_stop_complete_internal_callback) {
+        on_stop_complete_internal_callback(handle);
+        // Invalidate this callback since we don't want this firing again.
+        on_stop_complete_internal_callback = nullptr;
+    }
+}
+
+// Callback to be invoked for driver dump.
+std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
+void onSyncDriverMemoryDump(char* buffer, int buffer_size) {
+    if (on_driver_memory_dump_internal_callback) {
+        on_driver_memory_dump_internal_callback(buffer, buffer_size);
+    }
+}
+
+// Callback to be invoked for firmware dump.
+std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
+void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) {
+    if (on_firmware_memory_dump_internal_callback) {
+        on_firmware_memory_dump_internal_callback(buffer, buffer_size);
+    }
+}
+
+// Callback to be invoked for Gscan events.
+std::function<void(wifi_request_id, wifi_scan_event)>
+    on_gscan_event_internal_callback;
+void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_gscan_event_internal_callback) {
+        on_gscan_event_internal_callback(id, event);
+    }
+}
+
+// Callback to be invoked for Gscan full results.
+std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
+    on_gscan_full_result_internal_callback;
+void onAsyncGscanFullResult(wifi_request_id id, wifi_scan_result* result,
+                            uint32_t buckets_scanned) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_gscan_full_result_internal_callback) {
+        on_gscan_full_result_internal_callback(id, result, buckets_scanned);
+    }
+}
+
+// Callback to be invoked for link layer stats results.
+std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
+    on_link_layer_stats_result_internal_callback;
+void onSyncLinkLayerStatsResult(wifi_request_id id, wifi_iface_stat* iface_stat,
+                                int num_radios, wifi_radio_stat* radio_stat) {
+    if (on_link_layer_stats_result_internal_callback) {
+        on_link_layer_stats_result_internal_callback(id, iface_stat, num_radios,
+                                                     radio_stat);
+    }
+}
+
+// Callback to be invoked for rssi threshold breach.
+std::function<void((wifi_request_id, uint8_t*, int8_t))>
+    on_rssi_threshold_breached_internal_callback;
+void onAsyncRssiThresholdBreached(wifi_request_id id, uint8_t* bssid,
+                                  int8_t rssi) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_rssi_threshold_breached_internal_callback) {
+        on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
+    }
+}
+
+// Callback to be invoked for ring buffer data indication.
+std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
+    on_ring_buffer_data_internal_callback;
+void onAsyncRingBufferData(char* ring_name, char* buffer, int buffer_size,
+                           wifi_ring_buffer_status* status) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_ring_buffer_data_internal_callback) {
+        on_ring_buffer_data_internal_callback(ring_name, buffer, buffer_size,
+                                              status);
+    }
+}
+
+// Callback to be invoked for error alert indication.
+std::function<void(wifi_request_id, char*, int, int)>
+    on_error_alert_internal_callback;
+void onAsyncErrorAlert(wifi_request_id id, char* buffer, int buffer_size,
+                       int err_code) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_error_alert_internal_callback) {
+        on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
+    }
+}
+
+// Callback to be invoked for radio mode change indication.
+std::function<void(wifi_request_id, uint32_t, wifi_mac_info*)>
+    on_radio_mode_change_internal_callback;
+void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs,
+                            wifi_mac_info* mac_infos) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_radio_mode_change_internal_callback) {
+        on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
+    }
+}
+
+// Callback to be invoked for rtt results results.
+std::function<void(wifi_request_id, unsigned num_results,
+                   wifi_rtt_result* rtt_results[])>
+    on_rtt_results_internal_callback;
+void onAsyncRttResults(wifi_request_id id, unsigned num_results,
+                       wifi_rtt_result* rtt_results[]) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_rtt_results_internal_callback) {
+        on_rtt_results_internal_callback(id, num_results, rtt_results);
+        on_rtt_results_internal_callback = nullptr;
+    }
+}
+
+// Callbacks for the various NAN operations.
+// NOTE: These have very little conversions to perform before invoking the user
+// callbacks.
+// So, handle all of them here directly to avoid adding an unnecessary layer.
+std::function<void(transaction_id, const NanResponseMsg&)>
+    on_nan_notify_response_user_callback;
+void onAysncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_notify_response_user_callback && msg) {
+        on_nan_notify_response_user_callback(id, *msg);
+    }
+}
+
+std::function<void(const NanPublishRepliedInd&)>
+    on_nan_event_publish_replied_user_callback;
+void onAysncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
+    LOG(ERROR) << "onAysncNanEventPublishReplied triggered";
+}
+
+std::function<void(const NanPublishTerminatedInd&)>
+    on_nan_event_publish_terminated_user_callback;
+void onAysncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_publish_terminated_user_callback && event) {
+        on_nan_event_publish_terminated_user_callback(*event);
+    }
+}
+
+std::function<void(const NanMatchInd&)> on_nan_event_match_user_callback;
+void onAysncNanEventMatch(NanMatchInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_match_user_callback && event) {
+        on_nan_event_match_user_callback(*event);
+    }
+}
+
+std::function<void(const NanMatchExpiredInd&)>
+    on_nan_event_match_expired_user_callback;
+void onAysncNanEventMatchExpired(NanMatchExpiredInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_match_expired_user_callback && event) {
+        on_nan_event_match_expired_user_callback(*event);
+    }
+}
+
+std::function<void(const NanSubscribeTerminatedInd&)>
+    on_nan_event_subscribe_terminated_user_callback;
+void onAysncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_subscribe_terminated_user_callback && event) {
+        on_nan_event_subscribe_terminated_user_callback(*event);
+    }
+}
+
+std::function<void(const NanFollowupInd&)> on_nan_event_followup_user_callback;
+void onAysncNanEventFollowup(NanFollowupInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_followup_user_callback && event) {
+        on_nan_event_followup_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDiscEngEventInd&)>
+    on_nan_event_disc_eng_event_user_callback;
+void onAysncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_disc_eng_event_user_callback && event) {
+        on_nan_event_disc_eng_event_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDisabledInd&)> on_nan_event_disabled_user_callback;
+void onAysncNanEventDisabled(NanDisabledInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_disabled_user_callback && event) {
+        on_nan_event_disabled_user_callback(*event);
+    }
+}
+
+std::function<void(const NanTCAInd&)> on_nan_event_tca_user_callback;
+void onAysncNanEventTca(NanTCAInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_tca_user_callback && event) {
+        on_nan_event_tca_user_callback(*event);
+    }
+}
+
+std::function<void(const NanBeaconSdfPayloadInd&)>
+    on_nan_event_beacon_sdf_payload_user_callback;
+void onAysncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_beacon_sdf_payload_user_callback && event) {
+        on_nan_event_beacon_sdf_payload_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathRequestInd&)>
+    on_nan_event_data_path_request_user_callback;
+void onAysncNanEventDataPathRequest(NanDataPathRequestInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_request_user_callback && event) {
+        on_nan_event_data_path_request_user_callback(*event);
+    }
+}
+std::function<void(const NanDataPathConfirmInd&)>
+    on_nan_event_data_path_confirm_user_callback;
+void onAysncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_confirm_user_callback && event) {
+        on_nan_event_data_path_confirm_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathEndInd&)>
+    on_nan_event_data_path_end_user_callback;
+void onAysncNanEventDataPathEnd(NanDataPathEndInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_end_user_callback && event) {
+        on_nan_event_data_path_end_user_callback(*event);
+    }
+}
+
+std::function<void(const NanTransmitFollowupInd&)>
+    on_nan_event_transmit_follow_up_user_callback;
+void onAysncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_transmit_follow_up_user_callback && event) {
+        on_nan_event_transmit_follow_up_user_callback(*event);
+    }
+}
+
+std::function<void(const NanRangeRequestInd&)>
+    on_nan_event_range_request_user_callback;
+void onAysncNanEventRangeRequest(NanRangeRequestInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_range_request_user_callback && event) {
+        on_nan_event_range_request_user_callback(*event);
+    }
+}
+
+std::function<void(const NanRangeReportInd&)>
+    on_nan_event_range_report_user_callback;
+void onAysncNanEventRangeReport(NanRangeReportInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_range_report_user_callback && event) {
+        on_nan_event_range_report_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathScheduleUpdateInd&)>
+    on_nan_event_schedule_update_user_callback;
+void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_schedule_update_user_callback && event) {
+        on_nan_event_schedule_update_user_callback(*event);
+    }
+}
+// End of the free-standing "C" style callbacks.
+
+WifiLegacyHal::WifiLegacyHal(
+    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+    : global_handle_(nullptr),
+      awaiting_event_loop_termination_(false),
+      is_started_(false),
+      iface_tool_(iface_tool) {}
+
+wifi_error WifiLegacyHal::initialize() {
+    LOG(DEBUG) << "Initialize legacy HAL";
+    // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
+    // for now is this function call which we can directly call.
+    if (!initHalFuncTableWithStubs(&global_func_table_)) {
+        LOG(ERROR)
+            << "Failed to initialize legacy hal function table with stubs";
+        return WIFI_ERROR_UNKNOWN;
+    }
+    wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
+    if (status != WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to initialize legacy hal function table";
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::start() {
+    // Ensure that we're starting in a good state.
+    CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
+          iface_name_to_handle_.empty() && !awaiting_event_loop_termination_);
+    if (is_started_) {
+        LOG(DEBUG) << "Legacy HAL already started";
+        return WIFI_SUCCESS;
+    }
+    LOG(DEBUG) << "Waiting for the driver ready";
+    wifi_error status = global_func_table_.wifi_wait_for_driver_ready();
+    if (status == WIFI_ERROR_TIMED_OUT) {
+        LOG(ERROR) << "Timed out awaiting driver ready";
+        return status;
+    }
+    property_set(kDriverPropName, "ok");
+
+    LOG(DEBUG) << "Starting legacy HAL";
+    if (!iface_tool_.lock()->SetWifiUpState(true)) {
+        LOG(ERROR) << "Failed to set WiFi interface up";
+        return WIFI_ERROR_UNKNOWN;
+    }
+    status = global_func_table_.wifi_initialize(&global_handle_);
+    if (status != WIFI_SUCCESS || !global_handle_) {
+        LOG(ERROR) << "Failed to retrieve global handle";
+        return status;
+    }
+    std::thread(&WifiLegacyHal::runEventLoop, this).detach();
+    status = retrieveIfaceHandles();
+    if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) {
+        LOG(ERROR) << "Failed to retrieve wlan interface handle";
+        return status;
+    }
+    LOG(DEBUG) << "Legacy HAL start complete";
+    is_started_ = true;
+    return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::stop(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+    const std::function<void()>& on_stop_complete_user_callback) {
+    if (!is_started_) {
+        LOG(DEBUG) << "Legacy HAL already stopped";
+        on_stop_complete_user_callback();
+        return WIFI_SUCCESS;
+    }
+    LOG(DEBUG) << "Stopping legacy HAL";
+    on_stop_complete_internal_callback = [on_stop_complete_user_callback,
+                                          this](wifi_handle handle) {
+        CHECK_EQ(global_handle_, handle) << "Handle mismatch";
+        LOG(INFO) << "Legacy HAL stop complete callback received";
+        // Invalidate all the internal pointers now that the HAL is
+        // stopped.
+        invalidate();
+        iface_tool_.lock()->SetWifiUpState(false);
+        on_stop_complete_user_callback();
+        is_started_ = false;
+    };
+    awaiting_event_loop_termination_ = true;
+    global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete);
+    const auto status = stop_wait_cv_.wait_for(
+        *lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs),
+        [this] { return !awaiting_event_loop_termination_; });
+    if (!status) {
+        LOG(ERROR) << "Legacy HAL stop failed or timed out";
+        return WIFI_ERROR_UNKNOWN;
+    }
+    LOG(DEBUG) << "Legacy HAL stop complete";
+    return WIFI_SUCCESS;
+}
+
+bool WifiLegacyHal::isStarted() { return is_started_; }
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion(
+    const std::string& iface_name) {
+    std::array<char, kMaxVersionStringLength> buffer;
+    buffer.fill(0);
+    wifi_error status = global_func_table_.wifi_get_driver_version(
+        getIfaceHandle(iface_name), buffer.data(), buffer.size());
+    return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion(
+    const std::string& iface_name) {
+    std::array<char, kMaxVersionStringLength> buffer;
+    buffer.fill(0);
+    wifi_error status = global_func_table_.wifi_get_firmware_version(
+        getIfaceHandle(iface_name), buffer.data(), buffer.size());
+    return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>>
+WifiLegacyHal::requestDriverMemoryDump(const std::string& iface_name) {
+    std::vector<uint8_t> driver_dump;
+    on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer,
+                                                             int buffer_size) {
+        driver_dump.insert(driver_dump.end(),
+                           reinterpret_cast<uint8_t*>(buffer),
+                           reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+    };
+    wifi_error status = global_func_table_.wifi_get_driver_memory_dump(
+        getIfaceHandle(iface_name), {onSyncDriverMemoryDump});
+    on_driver_memory_dump_internal_callback = nullptr;
+    return {status, std::move(driver_dump)};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>>
+WifiLegacyHal::requestFirmwareMemoryDump(const std::string& iface_name) {
+    std::vector<uint8_t> firmware_dump;
+    on_firmware_memory_dump_internal_callback =
+        [&firmware_dump](char* buffer, int buffer_size) {
+            firmware_dump.insert(
+                firmware_dump.end(), reinterpret_cast<uint8_t*>(buffer),
+                reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+        };
+    wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
+        getIfaceHandle(iface_name), {onSyncFirmwareMemoryDump});
+    on_firmware_memory_dump_internal_callback = nullptr;
+    return {status, std::move(firmware_dump)};
+}
+
+std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet(
+    const std::string& iface_name) {
+    feature_set set;
+    static_assert(sizeof(set) == sizeof(uint64_t),
+                  "Some feature_flags can not be represented in output");
+    wifi_error status = global_func_table_.wifi_get_supported_feature_set(
+        getIfaceHandle(iface_name), &set);
+    return {status, static_cast<uint32_t>(set)};
+}
+
+std::pair<wifi_error, PacketFilterCapabilities>
+WifiLegacyHal::getPacketFilterCapabilities(const std::string& iface_name) {
+    PacketFilterCapabilities caps;
+    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+        getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::setPacketFilter(const std::string& iface_name,
+                                          const std::vector<uint8_t>& program) {
+    return global_func_table_.wifi_set_packet_filter(
+        getIfaceHandle(iface_name), program.data(), program.size());
+}
+
+std::pair<wifi_error, std::vector<uint8_t>>
+WifiLegacyHal::readApfPacketFilterData(const std::string& iface_name) {
+    PacketFilterCapabilities caps;
+    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+        getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+    if (status != WIFI_SUCCESS) {
+        return {status, {}};
+    }
+
+    // Size the buffer to read the entire program & work memory.
+    std::vector<uint8_t> buffer(caps.max_len);
+
+    status = global_func_table_.wifi_read_packet_filter(
+        getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(),
+        buffer.size());
+    return {status, move(buffer)};
+}
+
+std::pair<wifi_error, wifi_gscan_capabilities>
+WifiLegacyHal::getGscanCapabilities(const std::string& iface_name) {
+    wifi_gscan_capabilities caps;
+    wifi_error status = global_func_table_.wifi_get_gscan_capabilities(
+        getIfaceHandle(iface_name), &caps);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::startGscan(
+    const std::string& iface_name, wifi_request_id id,
+    const wifi_scan_cmd_params& params,
+    const std::function<void(wifi_request_id)>& on_failure_user_callback,
+    const on_gscan_results_callback& on_results_user_callback,
+    const on_gscan_full_result_callback& on_full_result_user_callback) {
+    // If there is already an ongoing background scan, reject new scan requests.
+    if (on_gscan_event_internal_callback ||
+        on_gscan_full_result_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    // This callback will be used to either trigger |on_results_user_callback|
+    // or |on_failure_user_callback|.
+    on_gscan_event_internal_callback =
+        [iface_name, on_failure_user_callback, on_results_user_callback, this](
+            wifi_request_id id, wifi_scan_event event) {
+            switch (event) {
+                case WIFI_SCAN_RESULTS_AVAILABLE:
+                case WIFI_SCAN_THRESHOLD_NUM_SCANS:
+                case WIFI_SCAN_THRESHOLD_PERCENT: {
+                    wifi_error status;
+                    std::vector<wifi_cached_scan_results> cached_scan_results;
+                    std::tie(status, cached_scan_results) =
+                        getGscanCachedResults(iface_name);
+                    if (status == WIFI_SUCCESS) {
+                        on_results_user_callback(id, cached_scan_results);
+                        return;
+                    }
+                    FALLTHROUGH_INTENDED;
+                }
+                // Fall through if failed. Failure to retrieve cached scan
+                // results should trigger a background scan failure.
+                case WIFI_SCAN_FAILED:
+                    on_failure_user_callback(id);
+                    on_gscan_event_internal_callback = nullptr;
+                    on_gscan_full_result_internal_callback = nullptr;
+                    return;
+            }
+            LOG(FATAL) << "Unexpected gscan event received: " << event;
+        };
+
+    on_gscan_full_result_internal_callback = [on_full_result_user_callback](
+                                                 wifi_request_id id,
+                                                 wifi_scan_result* result,
+                                                 uint32_t buckets_scanned) {
+        if (result) {
+            on_full_result_user_callback(id, result, buckets_scanned);
+        }
+    };
+
+    wifi_scan_result_handler handler = {onAsyncGscanFullResult,
+                                        onAsyncGscanEvent};
+    wifi_error status = global_func_table_.wifi_start_gscan(
+        id, getIfaceHandle(iface_name), params, handler);
+    if (status != WIFI_SUCCESS) {
+        on_gscan_event_internal_callback = nullptr;
+        on_gscan_full_result_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::stopGscan(const std::string& iface_name,
+                                    wifi_request_id id) {
+    // If there is no an ongoing background scan, reject stop requests.
+    // TODO(b/32337212): This needs to be handled by the HIDL object because we
+    // need to return the NOT_STARTED error code.
+    if (!on_gscan_event_internal_callback &&
+        !on_gscan_full_result_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    wifi_error status =
+        global_func_table_.wifi_stop_gscan(id, getIfaceHandle(iface_name));
+    // If the request Id is wrong, don't stop the ongoing background scan. Any
+    // other error should be treated as the end of background scan.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_gscan_event_internal_callback = nullptr;
+        on_gscan_full_result_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, std::vector<uint32_t>>
+WifiLegacyHal::getValidFrequenciesForBand(const std::string& iface_name,
+                                          wifi_band band) {
+    static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
+                  "Wifi Channel cannot be represented in output");
+    std::vector<uint32_t> freqs;
+    freqs.resize(kMaxGscanFrequenciesForBand);
+    int32_t num_freqs = 0;
+    wifi_error status = global_func_table_.wifi_get_valid_channels(
+        getIfaceHandle(iface_name), band, freqs.size(),
+        reinterpret_cast<wifi_channel*>(freqs.data()), &num_freqs);
+    CHECK(num_freqs >= 0 &&
+          static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
+    freqs.resize(num_freqs);
+    return {status, std::move(freqs)};
+}
+
+wifi_error WifiLegacyHal::setDfsFlag(const std::string& iface_name,
+                                     bool dfs_on) {
+    return global_func_table_.wifi_set_nodfs_flag(getIfaceHandle(iface_name),
+                                                  dfs_on ? 0 : 1);
+}
+
+wifi_error WifiLegacyHal::enableLinkLayerStats(const std::string& iface_name,
+                                               bool debug) {
+    wifi_link_layer_params params;
+    params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
+    params.aggressive_statistics_gathering = debug;
+    return global_func_table_.wifi_set_link_stats(getIfaceHandle(iface_name),
+                                                  params);
+}
+
+wifi_error WifiLegacyHal::disableLinkLayerStats(const std::string& iface_name) {
+    // TODO: Do we care about these responses?
+    uint32_t clear_mask_rsp;
+    uint8_t stop_rsp;
+    return global_func_table_.wifi_clear_link_stats(
+        getIfaceHandle(iface_name), 0xFFFFFFFF, &clear_mask_rsp, 1, &stop_rsp);
+}
+
+std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
+    const std::string& iface_name) {
+    LinkLayerStats link_stats{};
+    LinkLayerStats* link_stats_ptr = &link_stats;
+
+    on_link_layer_stats_result_internal_callback =
+        [&link_stats_ptr](wifi_request_id /* id */,
+                          wifi_iface_stat* iface_stats_ptr, int num_radios,
+                          wifi_radio_stat* radio_stats_ptr) {
+            wifi_radio_stat* l_radio_stats_ptr;
+
+            if (iface_stats_ptr != nullptr) {
+                link_stats_ptr->iface = *iface_stats_ptr;
+                link_stats_ptr->iface.num_peers = 0;
+            } else {
+                LOG(ERROR) << "Invalid iface stats in link layer stats";
+            }
+            if (num_radios <= 0 || radio_stats_ptr == nullptr) {
+                LOG(ERROR) << "Invalid radio stats in link layer stats";
+                return;
+            }
+            l_radio_stats_ptr = radio_stats_ptr;
+            for (int i = 0; i < num_radios; i++) {
+                LinkLayerRadioStats radio;
+
+                radio.stats = *l_radio_stats_ptr;
+                // Copy over the tx level array to the separate vector.
+                if (l_radio_stats_ptr->num_tx_levels > 0 &&
+                    l_radio_stats_ptr->tx_time_per_levels != nullptr) {
+                    radio.tx_time_per_levels.assign(
+                        l_radio_stats_ptr->tx_time_per_levels,
+                        l_radio_stats_ptr->tx_time_per_levels +
+                            l_radio_stats_ptr->num_tx_levels);
+                }
+                radio.stats.num_tx_levels = 0;
+                radio.stats.tx_time_per_levels = nullptr;
+                /* Copy over the channel stat to separate vector */
+                if (l_radio_stats_ptr->num_channels > 0) {
+                    /* Copy the channel stats */
+                    radio.channel_stats.assign(
+                        l_radio_stats_ptr->channels,
+                        l_radio_stats_ptr->channels +
+                            l_radio_stats_ptr->num_channels);
+                }
+                link_stats_ptr->radios.push_back(radio);
+                l_radio_stats_ptr =
+                    (wifi_radio_stat*)((u8*)l_radio_stats_ptr +
+                                       sizeof(wifi_radio_stat) +
+                                       (sizeof(wifi_channel_stat) *
+                                        l_radio_stats_ptr->num_channels));
+            }
+        };
+
+    wifi_error status = global_func_table_.wifi_get_link_stats(
+        0, getIfaceHandle(iface_name), {onSyncLinkLayerStatsResult});
+    on_link_layer_stats_result_internal_callback = nullptr;
+    return {status, link_stats};
+}
+
+wifi_error WifiLegacyHal::startRssiMonitoring(
+    const std::string& iface_name, wifi_request_id id, int8_t max_rssi,
+    int8_t min_rssi,
+    const on_rssi_threshold_breached_callback&
+        on_threshold_breached_user_callback) {
+    if (on_rssi_threshold_breached_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_rssi_threshold_breached_internal_callback =
+        [on_threshold_breached_user_callback](wifi_request_id id,
+                                              uint8_t* bssid_ptr, int8_t rssi) {
+            if (!bssid_ptr) {
+                return;
+            }
+            std::array<uint8_t, 6> bssid_arr;
+            // |bssid_ptr| pointer is assumed to have 6 bytes for the mac
+            // address.
+            std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
+            on_threshold_breached_user_callback(id, bssid_arr, rssi);
+        };
+    wifi_error status = global_func_table_.wifi_start_rssi_monitoring(
+        id, getIfaceHandle(iface_name), max_rssi, min_rssi,
+        {onAsyncRssiThresholdBreached});
+    if (status != WIFI_SUCCESS) {
+        on_rssi_threshold_breached_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::stopRssiMonitoring(const std::string& iface_name,
+                                             wifi_request_id id) {
+    if (!on_rssi_threshold_breached_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    wifi_error status = global_func_table_.wifi_stop_rssi_monitoring(
+        id, getIfaceHandle(iface_name));
+    // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
+    // other error should be treated as the end of background scan.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_rssi_threshold_breached_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, wifi_roaming_capabilities>
+WifiLegacyHal::getRoamingCapabilities(const std::string& iface_name) {
+    wifi_roaming_capabilities caps;
+    wifi_error status = global_func_table_.wifi_get_roaming_capabilities(
+        getIfaceHandle(iface_name), &caps);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::configureRoaming(const std::string& iface_name,
+                                           const wifi_roaming_config& config) {
+    wifi_roaming_config config_internal = config;
+    return global_func_table_.wifi_configure_roaming(getIfaceHandle(iface_name),
+                                                     &config_internal);
+}
+
+wifi_error WifiLegacyHal::enableFirmwareRoaming(const std::string& iface_name,
+                                                fw_roaming_state_t state) {
+    return global_func_table_.wifi_enable_firmware_roaming(
+        getIfaceHandle(iface_name), state);
+}
+
+wifi_error WifiLegacyHal::configureNdOffload(const std::string& iface_name,
+                                             bool enable) {
+    return global_func_table_.wifi_configure_nd_offload(
+        getIfaceHandle(iface_name), enable);
+}
+
+wifi_error WifiLegacyHal::startSendingOffloadedPacket(
+    const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
+    const std::vector<uint8_t>& ip_packet_data,
+    const std::array<uint8_t, 6>& src_address,
+    const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
+    std::vector<uint8_t> ip_packet_data_internal(ip_packet_data);
+    std::vector<uint8_t> src_address_internal(
+        src_address.data(), src_address.data() + src_address.size());
+    std::vector<uint8_t> dst_address_internal(
+        dst_address.data(), dst_address.data() + dst_address.size());
+    return global_func_table_.wifi_start_sending_offloaded_packet(
+        cmd_id, getIfaceHandle(iface_name), ether_type,
+        ip_packet_data_internal.data(), ip_packet_data_internal.size(),
+        src_address_internal.data(), dst_address_internal.data(), period_in_ms);
+}
+
+wifi_error WifiLegacyHal::stopSendingOffloadedPacket(
+    const std::string& iface_name, uint32_t cmd_id) {
+    return global_func_table_.wifi_stop_sending_offloaded_packet(
+        cmd_id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name,
+                                                wifi_power_scenario scenario) {
+    return global_func_table_.wifi_select_tx_power_scenario(
+        getIfaceHandle(iface_name), scenario);
+}
+
+wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) {
+    return global_func_table_.wifi_reset_tx_power_scenario(
+        getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name,
+                                         wifi_latency_mode mode) {
+    return global_func_table_.wifi_set_latency_mode(getIfaceHandle(iface_name),
+                                                    mode);
+}
+
+wifi_error WifiLegacyHal::setThermalMitigationMode(wifi_thermal_mode mode,
+                                                   uint32_t completion_window) {
+    return global_func_table_.wifi_set_thermal_mitigation_mode(
+        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;
+    wifi_error status =
+        global_func_table_.wifi_get_logger_supported_feature_set(
+            getIfaceHandle(iface_name), &supported_feature_flags);
+    return {status, supported_feature_flags};
+}
+
+wifi_error WifiLegacyHal::startPktFateMonitoring(
+    const std::string& iface_name) {
+    return global_func_table_.wifi_start_pkt_fate_monitoring(
+        getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_tx_report>> WifiLegacyHal::getTxPktFates(
+    const std::string& iface_name) {
+    std::vector<wifi_tx_report> tx_pkt_fates;
+    tx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+    size_t num_fates = 0;
+    wifi_error status = global_func_table_.wifi_get_tx_pkt_fates(
+        getIfaceHandle(iface_name), tx_pkt_fates.data(), tx_pkt_fates.size(),
+        &num_fates);
+    CHECK(num_fates <= MAX_FATE_LOG_LEN);
+    tx_pkt_fates.resize(num_fates);
+    return {status, std::move(tx_pkt_fates)};
+}
+
+std::pair<wifi_error, std::vector<wifi_rx_report>> WifiLegacyHal::getRxPktFates(
+    const std::string& iface_name) {
+    std::vector<wifi_rx_report> rx_pkt_fates;
+    rx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+    size_t num_fates = 0;
+    wifi_error status = global_func_table_.wifi_get_rx_pkt_fates(
+        getIfaceHandle(iface_name), rx_pkt_fates.data(), rx_pkt_fates.size(),
+        &num_fates);
+    CHECK(num_fates <= MAX_FATE_LOG_LEN);
+    rx_pkt_fates.resize(num_fates);
+    return {status, std::move(rx_pkt_fates)};
+}
+
+std::pair<wifi_error, WakeReasonStats> WifiLegacyHal::getWakeReasonStats(
+    const std::string& iface_name) {
+    WakeReasonStats stats;
+    stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+    stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+
+    // This legacy struct needs separate memory to store the variable sized wake
+    // reason types.
+    stats.wake_reason_cnt.cmd_event_wake_cnt =
+        reinterpret_cast<int32_t*>(stats.cmd_event_wake_cnt.data());
+    stats.wake_reason_cnt.cmd_event_wake_cnt_sz =
+        stats.cmd_event_wake_cnt.size();
+    stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0;
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt =
+        reinterpret_cast<int32_t*>(stats.driver_fw_local_wake_cnt.data());
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz =
+        stats.driver_fw_local_wake_cnt.size();
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
+
+    wifi_error status = global_func_table_.wifi_get_wake_reason_stats(
+        getIfaceHandle(iface_name), &stats.wake_reason_cnt);
+
+    CHECK(
+        stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 &&
+        static_cast<uint32_t>(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <=
+            kMaxWakeReasonStatsArraySize);
+    stats.cmd_event_wake_cnt.resize(
+        stats.wake_reason_cnt.cmd_event_wake_cnt_used);
+    stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr;
+
+    CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 &&
+          static_cast<uint32_t>(
+              stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <=
+              kMaxWakeReasonStatsArraySize);
+    stats.driver_fw_local_wake_cnt.resize(
+        stats.wake_reason_cnt.driver_fw_local_wake_cnt_used);
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr;
+
+    return {status, stats};
+}
+
+wifi_error WifiLegacyHal::registerRingBufferCallbackHandler(
+    const std::string& iface_name,
+    const on_ring_buffer_data_callback& on_user_data_callback) {
+    if (on_ring_buffer_data_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_ring_buffer_data_internal_callback =
+        [on_user_data_callback](char* ring_name, char* buffer, int buffer_size,
+                                wifi_ring_buffer_status* status) {
+            if (status && buffer) {
+                std::vector<uint8_t> buffer_vector(
+                    reinterpret_cast<uint8_t*>(buffer),
+                    reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+                on_user_data_callback(ring_name, buffer_vector, *status);
+            }
+        };
+    wifi_error status = global_func_table_.wifi_set_log_handler(
+        0, getIfaceHandle(iface_name), {onAsyncRingBufferData});
+    if (status != WIFI_SUCCESS) {
+        on_ring_buffer_data_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler(
+    const std::string& iface_name) {
+    if (!on_ring_buffer_data_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_ring_buffer_data_internal_callback = nullptr;
+    return global_func_table_.wifi_reset_log_handler(
+        0, getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
+WifiLegacyHal::getRingBuffersStatus(const std::string& iface_name) {
+    std::vector<wifi_ring_buffer_status> ring_buffers_status;
+    ring_buffers_status.resize(kMaxRingBuffers);
+    uint32_t num_rings = kMaxRingBuffers;
+    wifi_error status = global_func_table_.wifi_get_ring_buffers_status(
+        getIfaceHandle(iface_name), &num_rings, ring_buffers_status.data());
+    CHECK(num_rings <= kMaxRingBuffers);
+    ring_buffers_status.resize(num_rings);
+    return {status, std::move(ring_buffers_status)};
+}
+
+wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& iface_name,
+                                                 const std::string& ring_name,
+                                                 uint32_t verbose_level,
+                                                 uint32_t max_interval_sec,
+                                                 uint32_t min_data_size) {
+    return global_func_table_.wifi_start_logging(
+        getIfaceHandle(iface_name), verbose_level, 0, max_interval_sec,
+        min_data_size, makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::getRingBufferData(const std::string& iface_name,
+                                            const std::string& ring_name) {
+    return global_func_table_.wifi_get_ring_data(getIfaceHandle(iface_name),
+                                                 makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
+    const std::string& iface_name,
+    const on_error_alert_callback& on_user_alert_callback) {
+    if (on_error_alert_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_error_alert_internal_callback = [on_user_alert_callback](
+                                           wifi_request_id id, char* buffer,
+                                           int buffer_size, int err_code) {
+        if (buffer) {
+            CHECK(id == 0);
+            on_user_alert_callback(
+                err_code,
+                std::vector<uint8_t>(
+                    reinterpret_cast<uint8_t*>(buffer),
+                    reinterpret_cast<uint8_t*>(buffer) + buffer_size));
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_alert_handler(
+        0, getIfaceHandle(iface_name), {onAsyncErrorAlert});
+    if (status != WIFI_SUCCESS) {
+        on_error_alert_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler(
+    const std::string& iface_name) {
+    if (!on_error_alert_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_error_alert_internal_callback = nullptr;
+    return global_func_table_.wifi_reset_alert_handler(
+        0, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler(
+    const std::string& iface_name,
+    const on_radio_mode_change_callback& on_user_change_callback) {
+    if (on_radio_mode_change_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_radio_mode_change_internal_callback = [on_user_change_callback](
+                                                 wifi_request_id /* id */,
+                                                 uint32_t num_macs,
+                                                 wifi_mac_info* mac_infos_arr) {
+        if (num_macs > 0 && mac_infos_arr) {
+            std::vector<WifiMacInfo> mac_infos_vec;
+            for (uint32_t i = 0; i < num_macs; i++) {
+                WifiMacInfo mac_info;
+                mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id;
+                mac_info.mac_band = mac_infos_arr[i].mac_band;
+                for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) {
+                    WifiIfaceInfo iface_info;
+                    iface_info.name = mac_infos_arr[i].iface_info[j].iface_name;
+                    iface_info.channel = mac_infos_arr[i].iface_info[j].channel;
+                    mac_info.iface_infos.push_back(iface_info);
+                }
+                mac_infos_vec.push_back(mac_info);
+            }
+            on_user_change_callback(mac_infos_vec);
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler(
+        0, getIfaceHandle(iface_name), {onAsyncRadioModeChange});
+    if (status != WIFI_SUCCESS) {
+        on_radio_mode_change_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::startRttRangeRequest(
+    const std::string& iface_name, wifi_request_id id,
+    const std::vector<wifi_rtt_config>& rtt_configs,
+    const on_rtt_results_callback& on_results_user_callback) {
+    if (on_rtt_results_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    on_rtt_results_internal_callback =
+        [on_results_user_callback](wifi_request_id id, unsigned num_results,
+                                   wifi_rtt_result* rtt_results[]) {
+            if (num_results > 0 && !rtt_results) {
+                LOG(ERROR) << "Unexpected nullptr in RTT results";
+                return;
+            }
+            std::vector<const wifi_rtt_result*> rtt_results_vec;
+            std::copy_if(rtt_results, rtt_results + num_results,
+                         back_inserter(rtt_results_vec),
+                         [](wifi_rtt_result* rtt_result) {
+                             return rtt_result != nullptr;
+                         });
+            on_results_user_callback(id, rtt_results_vec);
+        };
+
+    std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
+    wifi_error status = global_func_table_.wifi_rtt_range_request(
+        id, getIfaceHandle(iface_name), rtt_configs.size(),
+        rtt_configs_internal.data(), {onAsyncRttResults});
+    if (status != WIFI_SUCCESS) {
+        on_rtt_results_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::cancelRttRangeRequest(
+    const std::string& iface_name, wifi_request_id id,
+    const std::vector<std::array<uint8_t, 6>>& mac_addrs) {
+    if (!on_rtt_results_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, 6>),
+                  "MAC address size mismatch");
+    // TODO: How do we handle partial cancels (i.e only a subset of enabled mac
+    // addressed are cancelled).
+    std::vector<std::array<uint8_t, 6>> mac_addrs_internal(mac_addrs);
+    wifi_error status = global_func_table_.wifi_rtt_range_cancel(
+        id, getIfaceHandle(iface_name), mac_addrs.size(),
+        reinterpret_cast<mac_addr*>(mac_addrs_internal.data()));
+    // If the request Id is wrong, don't stop the ongoing range request. Any
+    // other error should be treated as the end of rtt ranging.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_rtt_results_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, wifi_rtt_capabilities> WifiLegacyHal::getRttCapabilities(
+    const std::string& iface_name) {
+    wifi_rtt_capabilities rtt_caps;
+    wifi_error status = global_func_table_.wifi_get_rtt_capabilities(
+        getIfaceHandle(iface_name), &rtt_caps);
+    return {status, rtt_caps};
+}
+
+std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo(
+    const std::string& iface_name) {
+    wifi_rtt_responder rtt_responder;
+    wifi_error status = global_func_table_.wifi_rtt_get_responder_info(
+        getIfaceHandle(iface_name), &rtt_responder);
+    return {status, rtt_responder};
+}
+
+wifi_error WifiLegacyHal::enableRttResponder(
+    const std::string& iface_name, wifi_request_id id,
+    const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
+    const wifi_rtt_responder& info) {
+    wifi_rtt_responder info_internal(info);
+    return global_func_table_.wifi_enable_responder(
+        id, getIfaceHandle(iface_name), channel_hint, max_duration_secs,
+        &info_internal);
+}
+
+wifi_error WifiLegacyHal::disableRttResponder(const std::string& iface_name,
+                                              wifi_request_id id) {
+    return global_func_table_.wifi_disable_responder(
+        id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setRttLci(const std::string& iface_name,
+                                    wifi_request_id id,
+                                    const wifi_lci_information& info) {
+    wifi_lci_information info_internal(info);
+    return global_func_table_.wifi_set_lci(id, getIfaceHandle(iface_name),
+                                           &info_internal);
+}
+
+wifi_error WifiLegacyHal::setRttLcr(const std::string& iface_name,
+                                    wifi_request_id id,
+                                    const wifi_lcr_information& info) {
+    wifi_lcr_information info_internal(info);
+    return global_func_table_.wifi_set_lcr(id, getIfaceHandle(iface_name),
+                                           &info_internal);
+}
+
+wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(
+    const std::string& iface_name, const NanCallbackHandlers& user_callbacks) {
+    on_nan_notify_response_user_callback = user_callbacks.on_notify_response;
+    on_nan_event_publish_terminated_user_callback =
+        user_callbacks.on_event_publish_terminated;
+    on_nan_event_match_user_callback = user_callbacks.on_event_match;
+    on_nan_event_match_expired_user_callback =
+        user_callbacks.on_event_match_expired;
+    on_nan_event_subscribe_terminated_user_callback =
+        user_callbacks.on_event_subscribe_terminated;
+    on_nan_event_followup_user_callback = user_callbacks.on_event_followup;
+    on_nan_event_disc_eng_event_user_callback =
+        user_callbacks.on_event_disc_eng_event;
+    on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled;
+    on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
+    on_nan_event_beacon_sdf_payload_user_callback =
+        user_callbacks.on_event_beacon_sdf_payload;
+    on_nan_event_data_path_request_user_callback =
+        user_callbacks.on_event_data_path_request;
+    on_nan_event_data_path_confirm_user_callback =
+        user_callbacks.on_event_data_path_confirm;
+    on_nan_event_data_path_end_user_callback =
+        user_callbacks.on_event_data_path_end;
+    on_nan_event_transmit_follow_up_user_callback =
+        user_callbacks.on_event_transmit_follow_up;
+    on_nan_event_range_request_user_callback =
+        user_callbacks.on_event_range_request;
+    on_nan_event_range_report_user_callback =
+        user_callbacks.on_event_range_report;
+    on_nan_event_schedule_update_user_callback =
+        user_callbacks.on_event_schedule_update;
+
+    return global_func_table_.wifi_nan_register_handler(
+        getIfaceHandle(iface_name),
+        {onAysncNanNotifyResponse, onAysncNanEventPublishReplied,
+         onAysncNanEventPublishTerminated, onAysncNanEventMatch,
+         onAysncNanEventMatchExpired, onAysncNanEventSubscribeTerminated,
+         onAysncNanEventFollowup, onAysncNanEventDiscEngEvent,
+         onAysncNanEventDisabled, onAysncNanEventTca,
+         onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
+         onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
+         onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
+         onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
+}
+
+wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name,
+                                           transaction_id id,
+                                           const NanEnableRequest& msg) {
+    NanEnableRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_enable_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDisableRequest(const std::string& iface_name,
+                                            transaction_id id) {
+    return global_func_table_.wifi_nan_disable_request(
+        id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanPublishRequest(const std::string& iface_name,
+                                            transaction_id id,
+                                            const NanPublishRequest& msg) {
+    NanPublishRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_publish_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanPublishCancelRequest(
+    const std::string& iface_name, transaction_id id,
+    const NanPublishCancelRequest& msg) {
+    NanPublishCancelRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_publish_cancel_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeRequest(const std::string& iface_name,
+                                              transaction_id id,
+                                              const NanSubscribeRequest& msg) {
+    NanSubscribeRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_subscribe_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeCancelRequest(
+    const std::string& iface_name, transaction_id id,
+    const NanSubscribeCancelRequest& msg) {
+    NanSubscribeCancelRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_subscribe_cancel_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTransmitFollowupRequest(
+    const std::string& iface_name, transaction_id id,
+    const NanTransmitFollowupRequest& msg) {
+    NanTransmitFollowupRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_transmit_followup_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanStatsRequest(const std::string& iface_name,
+                                          transaction_id id,
+                                          const NanStatsRequest& msg) {
+    NanStatsRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_stats_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanConfigRequest(const std::string& iface_name,
+                                           transaction_id id,
+                                           const NanConfigRequest& msg) {
+    NanConfigRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_config_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTcaRequest(const std::string& iface_name,
+                                        transaction_id id,
+                                        const NanTCARequest& msg) {
+    NanTCARequest msg_internal(msg);
+    return global_func_table_.wifi_nan_tca_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(
+    const std::string& iface_name, transaction_id id,
+    const NanBeaconSdfPayloadRequest& msg) {
+    NanBeaconSdfPayloadRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_beacon_sdf_payload_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+std::pair<wifi_error, NanVersion> WifiLegacyHal::nanGetVersion() {
+    NanVersion version;
+    wifi_error status =
+        global_func_table_.wifi_nan_get_version(global_handle_, &version);
+    return {status, version};
+}
+
+wifi_error WifiLegacyHal::nanGetCapabilities(const std::string& iface_name,
+                                             transaction_id id) {
+    return global_func_table_.wifi_nan_get_capabilities(
+        id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceCreate(
+    const std::string& iface_name, transaction_id id,
+    const std::string& data_iface_name) {
+    return global_func_table_.wifi_nan_data_interface_create(
+        id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceDelete(
+    const std::string& iface_name, transaction_id id,
+    const std::string& data_iface_name) {
+    return global_func_table_.wifi_nan_data_interface_delete(
+        id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataRequestInitiator(
+    const std::string& iface_name, transaction_id id,
+    const NanDataPathInitiatorRequest& msg) {
+    NanDataPathInitiatorRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_data_request_initiator(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDataIndicationResponse(
+    const std::string& iface_name, transaction_id id,
+    const NanDataPathIndicationResponse& msg) {
+    NanDataPathIndicationResponse msg_internal(msg);
+    return global_func_table_.wifi_nan_data_indication_response(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+typedef struct {
+    u8 num_ndp_instances;
+    NanDataPathId ndp_instance_id;
+} NanDataPathEndSingleNdpIdRequest;
+
+wifi_error WifiLegacyHal::nanDataEnd(const std::string& iface_name,
+                                     transaction_id id,
+                                     uint32_t ndpInstanceId) {
+    NanDataPathEndSingleNdpIdRequest msg;
+    msg.num_ndp_instances = 1;
+    msg.ndp_instance_id = ndpInstanceId;
+    wifi_error status = global_func_table_.wifi_nan_data_end(
+        id, getIfaceHandle(iface_name), (NanDataPathEndRequest*)&msg);
+    return status;
+}
+
+wifi_error WifiLegacyHal::setCountryCode(const std::string& iface_name,
+                                         std::array<int8_t, 2> code) {
+    std::string code_str(code.data(), code.data() + code.size());
+    return global_func_table_.wifi_set_country_code(getIfaceHandle(iface_name),
+                                                    code_str.c_str());
+}
+
+wifi_error WifiLegacyHal::retrieveIfaceHandles() {
+    wifi_interface_handle* iface_handles = nullptr;
+    int num_iface_handles = 0;
+    wifi_error status = global_func_table_.wifi_get_ifaces(
+        global_handle_, &num_iface_handles, &iface_handles);
+    if (status != WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to enumerate interface handles";
+        return status;
+    }
+    iface_name_to_handle_.clear();
+    for (int i = 0; i < num_iface_handles; ++i) {
+        std::array<char, IFNAMSIZ> iface_name_arr = {};
+        status = global_func_table_.wifi_get_iface_name(
+            iface_handles[i], iface_name_arr.data(), iface_name_arr.size());
+        if (status != WIFI_SUCCESS) {
+            LOG(WARNING) << "Failed to get interface handle name";
+            continue;
+        }
+        // Assuming the interface name is null terminated since the legacy HAL
+        // API does not return a size.
+        std::string iface_name(iface_name_arr.data());
+        LOG(INFO) << "Adding interface handle for " << iface_name;
+        iface_name_to_handle_[iface_name] = iface_handles[i];
+    }
+    return WIFI_SUCCESS;
+}
+
+wifi_interface_handle WifiLegacyHal::getIfaceHandle(
+    const std::string& iface_name) {
+    const auto iface_handle_iter = iface_name_to_handle_.find(iface_name);
+    if (iface_handle_iter == iface_name_to_handle_.end()) {
+        LOG(ERROR) << "Unknown iface name: " << iface_name;
+        return nullptr;
+    }
+    return iface_handle_iter->second;
+}
+
+void WifiLegacyHal::runEventLoop() {
+    LOG(DEBUG) << "Starting legacy HAL event loop";
+    global_func_table_.wifi_event_loop(global_handle_);
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (!awaiting_event_loop_termination_) {
+        LOG(FATAL)
+            << "Legacy HAL event loop terminated, but HAL was not stopping";
+    }
+    LOG(DEBUG) << "Legacy HAL event loop terminated";
+    awaiting_event_loop_termination_ = false;
+    stop_wait_cv_.notify_one();
+}
+
+std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
+WifiLegacyHal::getGscanCachedResults(const std::string& iface_name) {
+    std::vector<wifi_cached_scan_results> cached_scan_results;
+    cached_scan_results.resize(kMaxCachedGscanResults);
+    int32_t num_results = 0;
+    wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
+        getIfaceHandle(iface_name), true /* always flush */,
+        cached_scan_results.size(), cached_scan_results.data(), &num_results);
+    CHECK(num_results >= 0 &&
+          static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
+    cached_scan_results.resize(num_results);
+    // Check for invalid IE lengths in these cached scan results and correct it.
+    for (auto& cached_scan_result : cached_scan_results) {
+        int num_scan_results = cached_scan_result.num_results;
+        for (int i = 0; i < num_scan_results; i++) {
+            auto& scan_result = cached_scan_result.results[i];
+            if (scan_result.ie_length > 0) {
+                LOG(DEBUG) << "Cached scan result has non-zero IE length "
+                           << scan_result.ie_length;
+                scan_result.ie_length = 0;
+            }
+        }
+    }
+    return {status, std::move(cached_scan_results)};
+}
+
+wifi_error WifiLegacyHal::createVirtualInterface(const std::string& ifname,
+                                                 wifi_interface_type iftype) {
+    // Create the interface if it doesn't exist. If interface already exist,
+    // Vendor Hal should return WIFI_SUCCESS.
+    wifi_error status = global_func_table_.wifi_virtual_interface_create(
+        global_handle_, ifname.c_str(), iftype);
+    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::deleteVirtualInterface(const std::string& ifname) {
+    // Delete the interface if it was created dynamically.
+    wifi_error status = global_func_table_.wifi_virtual_interface_delete(
+        global_handle_, ifname.c_str());
+    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::handleVirtualInterfaceCreateOrDeleteStatus(
+    const std::string& ifname, wifi_error status) {
+    if (status == WIFI_SUCCESS) {
+        // refresh list of handlers now.
+        status = retrieveIfaceHandles();
+    } else if (status == WIFI_ERROR_NOT_SUPPORTED) {
+        // Vendor hal does not implement this API. Such vendor implementations
+        // are expected to create / delete interface by other means.
+
+        // check if interface exists.
+        if (if_nametoindex(ifname.c_str())) {
+            status = retrieveIfaceHandles();
+        }
+    }
+    return status;
+}
+
+void WifiLegacyHal::invalidate() {
+    global_handle_ = nullptr;
+    iface_name_to_handle_.clear();
+    on_driver_memory_dump_internal_callback = nullptr;
+    on_firmware_memory_dump_internal_callback = nullptr;
+    on_gscan_event_internal_callback = nullptr;
+    on_gscan_full_result_internal_callback = nullptr;
+    on_link_layer_stats_result_internal_callback = nullptr;
+    on_rssi_threshold_breached_internal_callback = nullptr;
+    on_ring_buffer_data_internal_callback = nullptr;
+    on_error_alert_internal_callback = nullptr;
+    on_radio_mode_change_internal_callback = nullptr;
+    on_rtt_results_internal_callback = nullptr;
+    on_nan_notify_response_user_callback = nullptr;
+    on_nan_event_publish_terminated_user_callback = nullptr;
+    on_nan_event_match_user_callback = nullptr;
+    on_nan_event_match_expired_user_callback = nullptr;
+    on_nan_event_subscribe_terminated_user_callback = nullptr;
+    on_nan_event_followup_user_callback = nullptr;
+    on_nan_event_disc_eng_event_user_callback = nullptr;
+    on_nan_event_disabled_user_callback = nullptr;
+    on_nan_event_tca_user_callback = nullptr;
+    on_nan_event_beacon_sdf_payload_user_callback = nullptr;
+    on_nan_event_data_path_request_user_callback = nullptr;
+    on_nan_event_data_path_confirm_user_callback = nullptr;
+    on_nan_event_data_path_end_user_callback = nullptr;
+    on_nan_event_transmit_follow_up_user_callback = nullptr;
+    on_nan_event_range_request_user_callback = nullptr;
+    on_nan_event_range_report_user_callback = nullptr;
+    on_nan_event_schedule_update_user_callback = nullptr;
+}
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h
new file mode 100644
index 0000000..9964460
--- /dev/null
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_LEGACY_HAL_H_
+#define WIFI_LEGACY_HAL_H_
+
+#include <condition_variable>
+#include <functional>
+#include <map>
+#include <thread>
+#include <vector>
+
+#include <wifi_system/interface_tool.h>
+
+// HACK: The include inside the namespace below also transitively includes a
+// bunch of libc headers into the namespace, which leads to functions like
+// socketpair being defined in
+// android::hardware::wifi::V1_1::implementation::legacy_hal. Include this one
+// particular header as a hacky workaround until that's fixed.
+#include <sys/socket.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the HIDL interface types.
+namespace legacy_hal {
+// Wrap all the types defined inside the legacy HAL header files inside this
+// namespace.
+#include <hardware_legacy/wifi_hal.h>
+
+// APF capabilities supported by the iface.
+struct PacketFilterCapabilities {
+    uint32_t version;
+    uint32_t max_len;
+};
+
+// WARNING: We don't care about the variable sized members of either
+// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
+// to escape the compiler warnings regarding this.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
+// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
+// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
+// into a separate return element to avoid passing pointers around.
+struct LinkLayerRadioStats {
+    wifi_radio_stat stats;
+    std::vector<uint32_t> tx_time_per_levels;
+    std::vector<wifi_channel_stat> channel_stats;
+};
+
+struct LinkLayerStats {
+    wifi_iface_stat iface;
+    std::vector<LinkLayerRadioStats> radios;
+};
+#pragma GCC diagnostic pop
+
+// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
+// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
+// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
+// API. Separate that out into a separate return elements to avoid passing
+// pointers around.
+struct WakeReasonStats {
+    WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
+    std::vector<uint32_t> cmd_event_wake_cnt;
+    std::vector<uint32_t> driver_fw_local_wake_cnt;
+};
+
+// NAN response and event callbacks struct.
+struct NanCallbackHandlers {
+    // NotifyResponse invoked to notify the status of the Request.
+    std::function<void(transaction_id, const NanResponseMsg&)>
+        on_notify_response;
+    // Various event callbacks.
+    std::function<void(const NanPublishTerminatedInd&)>
+        on_event_publish_terminated;
+    std::function<void(const NanMatchInd&)> on_event_match;
+    std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
+    std::function<void(const NanSubscribeTerminatedInd&)>
+        on_event_subscribe_terminated;
+    std::function<void(const NanFollowupInd&)> on_event_followup;
+    std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
+    std::function<void(const NanDisabledInd&)> on_event_disabled;
+    std::function<void(const NanTCAInd&)> on_event_tca;
+    std::function<void(const NanBeaconSdfPayloadInd&)>
+        on_event_beacon_sdf_payload;
+    std::function<void(const NanDataPathRequestInd&)>
+        on_event_data_path_request;
+    std::function<void(const NanDataPathConfirmInd&)>
+        on_event_data_path_confirm;
+    std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
+    std::function<void(const NanTransmitFollowupInd&)>
+        on_event_transmit_follow_up;
+    std::function<void(const NanRangeRequestInd&)> on_event_range_request;
+    std::function<void(const NanRangeReportInd&)> on_event_range_report;
+    std::function<void(const NanDataPathScheduleUpdateInd&)>
+        on_event_schedule_update;
+};
+
+// Full scan results contain IE info and are hence passed by reference, to
+// preserve the variable length array member |ie_data|. Callee must not retain
+// the pointer.
+using on_gscan_full_result_callback =
+    std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
+// These scan results don't contain any IE info, so no need to pass by
+// reference.
+using on_gscan_results_callback = std::function<void(
+    wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
+
+// Invoked when the rssi value breaches the thresholds set.
+using on_rssi_threshold_breached_callback =
+    std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
+
+// Callback for RTT range request results.
+// Rtt results contain IE info and are hence passed by reference, to
+// preserve the |LCI| and |LCR| pointers. Callee must not retain
+// the pointer.
+using on_rtt_results_callback = std::function<void(
+    wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
+
+// Callback for ring buffer data.
+using on_ring_buffer_data_callback =
+    std::function<void(const std::string&, const std::vector<uint8_t>&,
+                       const wifi_ring_buffer_status&)>;
+
+// Callback for alerts.
+using on_error_alert_callback =
+    std::function<void(int32_t, const std::vector<uint8_t>&)>;
+
+// Struct for the mac info from the legacy HAL. This is a cleaner version
+// of the |wifi_mac_info| & |wifi_iface_info|.
+typedef struct {
+    std::string name;
+    wifi_channel channel;
+} WifiIfaceInfo;
+
+typedef struct {
+    uint32_t wlan_mac_id;
+    /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
+    uint32_t mac_band;
+    /* Represents the connected Wi-Fi interfaces associated with each MAC */
+    std::vector<WifiIfaceInfo> iface_infos;
+} WifiMacInfo;
+
+// Callback for radio mode change
+using on_radio_mode_change_callback =
+    std::function<void(const std::vector<WifiMacInfo>&)>;
+
+/**
+ * Class that encapsulates all legacy HAL interactions.
+ * This class manages the lifetime of the event loop thread used by legacy HAL.
+ *
+ * Note: There will only be a single instance of this class created in the Wifi
+ * object and will be valid for the lifetime of the process.
+ */
+class WifiLegacyHal {
+   public:
+    WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+    virtual ~WifiLegacyHal() = default;
+
+    // Initialize the legacy HAL function table.
+    virtual wifi_error initialize();
+    // Start the legacy HAL and the event looper thread.
+    virtual wifi_error start();
+    // Deinitialize the legacy HAL and wait for the event loop thread to exit
+    // using a predefined timeout.
+    virtual wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
+                            const std::function<void()>& on_complete_callback);
+    // Checks if legacy HAL has successfully started
+    bool isStarted();
+    // Wrappers for all the functions in the legacy HAL function table.
+    virtual std::pair<wifi_error, std::string> getDriverVersion(
+        const std::string& iface_name);
+    virtual std::pair<wifi_error, std::string> getFirmwareVersion(
+        const std::string& iface_name);
+    std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
+        const std::string& iface_name);
+    std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
+        const std::string& iface_name);
+    std::pair<wifi_error, uint32_t> getSupportedFeatureSet(
+        const std::string& iface_name);
+    // APF functions.
+    std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
+        const std::string& iface_name);
+    wifi_error setPacketFilter(const std::string& iface_name,
+                               const std::vector<uint8_t>& program);
+    std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
+        const std::string& iface_name);
+    // Gscan functions.
+    std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
+        const std::string& iface_name);
+    // These API's provides a simplified interface over the legacy Gscan API's:
+    // a) All scan events from the legacy HAL API other than the
+    //    |WIFI_SCAN_FAILED| are treated as notification of results.
+    //    This method then retrieves the cached scan results from the legacy
+    //    HAL API and triggers the externally provided
+    //    |on_results_user_callback| on success.
+    // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan
+    // results
+    //    triggers the externally provided |on_failure_user_callback|.
+    // c) Full scan result event triggers the externally provided
+    //    |on_full_result_user_callback|.
+    wifi_error startGscan(
+        const std::string& iface_name, wifi_request_id id,
+        const wifi_scan_cmd_params& params,
+        const std::function<void(wifi_request_id)>& on_failure_callback,
+        const on_gscan_results_callback& on_results_callback,
+        const on_gscan_full_result_callback& on_full_result_callback);
+    wifi_error stopGscan(const std::string& iface_name, wifi_request_id id);
+    std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
+        const std::string& iface_name, wifi_band band);
+    virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on);
+    // Link layer stats functions.
+    wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
+    wifi_error disableLinkLayerStats(const std::string& iface_name);
+    std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(
+        const std::string& iface_name);
+    // RSSI monitor functions.
+    wifi_error startRssiMonitoring(const std::string& iface_name,
+                                   wifi_request_id id, int8_t max_rssi,
+                                   int8_t min_rssi,
+                                   const on_rssi_threshold_breached_callback&
+                                       on_threshold_breached_callback);
+    wifi_error stopRssiMonitoring(const std::string& iface_name,
+                                  wifi_request_id id);
+    std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities(
+        const std::string& iface_name);
+    wifi_error configureRoaming(const std::string& iface_name,
+                                const wifi_roaming_config& config);
+    wifi_error enableFirmwareRoaming(const std::string& iface_name,
+                                     fw_roaming_state_t state);
+    wifi_error configureNdOffload(const std::string& iface_name, bool enable);
+    wifi_error startSendingOffloadedPacket(
+        const std::string& iface_name, uint32_t cmd_id, uint16_t ether_type,
+        const std::vector<uint8_t>& ip_packet_data,
+        const std::array<uint8_t, 6>& src_address,
+        const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
+    wifi_error stopSendingOffloadedPacket(const std::string& iface_name,
+                                          uint32_t cmd_id);
+    virtual wifi_error selectTxPowerScenario(const std::string& iface_name,
+                                             wifi_power_scenario scenario);
+    virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
+    wifi_error setLatencyMode(const std::string& iface_name,
+                              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);
+    wifi_error startPktFateMonitoring(const std::string& iface_name);
+    std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates(
+        const std::string& iface_name);
+    std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates(
+        const std::string& iface_name);
+    std::pair<wifi_error, WakeReasonStats> getWakeReasonStats(
+        const std::string& iface_name);
+    wifi_error registerRingBufferCallbackHandler(
+        const std::string& iface_name,
+        const on_ring_buffer_data_callback& on_data_callback);
+    wifi_error deregisterRingBufferCallbackHandler(
+        const std::string& iface_name);
+    std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
+    getRingBuffersStatus(const std::string& iface_name);
+    wifi_error startRingBufferLogging(const std::string& iface_name,
+                                      const std::string& ring_name,
+                                      uint32_t verbose_level,
+                                      uint32_t max_interval_sec,
+                                      uint32_t min_data_size);
+    wifi_error getRingBufferData(const std::string& iface_name,
+                                 const std::string& ring_name);
+    wifi_error registerErrorAlertCallbackHandler(
+        const std::string& iface_name,
+        const on_error_alert_callback& on_alert_callback);
+    wifi_error deregisterErrorAlertCallbackHandler(
+        const std::string& iface_name);
+    // Radio mode functions.
+    virtual wifi_error registerRadioModeChangeCallbackHandler(
+        const std::string& iface_name,
+        const on_radio_mode_change_callback& on_user_change_callback);
+    // RTT functions.
+    wifi_error startRttRangeRequest(
+        const std::string& iface_name, wifi_request_id id,
+        const std::vector<wifi_rtt_config>& rtt_configs,
+        const on_rtt_results_callback& on_results_callback);
+    wifi_error cancelRttRangeRequest(
+        const std::string& iface_name, wifi_request_id id,
+        const std::vector<std::array<uint8_t, 6>>& mac_addrs);
+    std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(
+        const std::string& iface_name);
+    std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(
+        const std::string& iface_name);
+    wifi_error enableRttResponder(const std::string& iface_name,
+                                  wifi_request_id id,
+                                  const wifi_channel_info& channel_hint,
+                                  uint32_t max_duration_secs,
+                                  const wifi_rtt_responder& info);
+    wifi_error disableRttResponder(const std::string& iface_name,
+                                   wifi_request_id id);
+    wifi_error setRttLci(const std::string& iface_name, wifi_request_id id,
+                         const wifi_lci_information& info);
+    wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id,
+                         const wifi_lcr_information& info);
+    // NAN functions.
+    virtual wifi_error nanRegisterCallbackHandlers(
+        const std::string& iface_name, const NanCallbackHandlers& callbacks);
+    wifi_error nanEnableRequest(const std::string& iface_name,
+                                transaction_id id, const NanEnableRequest& msg);
+    virtual wifi_error nanDisableRequest(const std::string& iface_name,
+                                         transaction_id id);
+    wifi_error nanPublishRequest(const std::string& iface_name,
+                                 transaction_id id,
+                                 const NanPublishRequest& msg);
+    wifi_error nanPublishCancelRequest(const std::string& iface_name,
+                                       transaction_id id,
+                                       const NanPublishCancelRequest& msg);
+    wifi_error nanSubscribeRequest(const std::string& iface_name,
+                                   transaction_id id,
+                                   const NanSubscribeRequest& msg);
+    wifi_error nanSubscribeCancelRequest(const std::string& iface_name,
+                                         transaction_id id,
+                                         const NanSubscribeCancelRequest& msg);
+    wifi_error nanTransmitFollowupRequest(
+        const std::string& iface_name, transaction_id id,
+        const NanTransmitFollowupRequest& msg);
+    wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id,
+                               const NanStatsRequest& msg);
+    wifi_error nanConfigRequest(const std::string& iface_name,
+                                transaction_id id, const NanConfigRequest& msg);
+    wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id,
+                             const NanTCARequest& msg);
+    wifi_error nanBeaconSdfPayloadRequest(
+        const std::string& iface_name, transaction_id id,
+        const NanBeaconSdfPayloadRequest& msg);
+    std::pair<wifi_error, NanVersion> nanGetVersion();
+    wifi_error nanGetCapabilities(const std::string& iface_name,
+                                  transaction_id id);
+    wifi_error nanDataInterfaceCreate(const std::string& iface_name,
+                                      transaction_id id,
+                                      const std::string& data_iface_name);
+    virtual wifi_error nanDataInterfaceDelete(
+        const std::string& iface_name, transaction_id id,
+        const std::string& data_iface_name);
+    wifi_error nanDataRequestInitiator(const std::string& iface_name,
+                                       transaction_id id,
+                                       const NanDataPathInitiatorRequest& msg);
+    wifi_error nanDataIndicationResponse(
+        const std::string& iface_name, transaction_id id,
+        const NanDataPathIndicationResponse& msg);
+    wifi_error nanDataEnd(const std::string& iface_name, transaction_id id,
+                          uint32_t ndpInstanceId);
+    // AP functions.
+    wifi_error setCountryCode(const std::string& iface_name,
+                              std::array<int8_t, 2> code);
+
+    // interface functions.
+    virtual wifi_error createVirtualInterface(const std::string& ifname,
+                                              wifi_interface_type iftype);
+    virtual wifi_error deleteVirtualInterface(const std::string& ifname);
+
+   private:
+    // Retrieve interface handles for all the available interfaces.
+    wifi_error retrieveIfaceHandles();
+    wifi_interface_handle getIfaceHandle(const std::string& iface_name);
+    // Run the legacy HAL event loop thread.
+    void runEventLoop();
+    // Retrieve the cached gscan results to pass the results back to the
+    // external callbacks.
+    std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
+    getGscanCachedResults(const std::string& iface_name);
+    void invalidate();
+    // Handles wifi (error) status of Virtual interface create/delete
+    wifi_error handleVirtualInterfaceCreateOrDeleteStatus(
+        const std::string& ifname, wifi_error status);
+
+    // Global function table of legacy HAL.
+    wifi_hal_fn global_func_table_;
+    // Opaque handle to be used for all global operations.
+    wifi_handle global_handle_;
+    // Map of interface name to handle that is to be used for all interface
+    // specific operations.
+    std::map<std::string, wifi_interface_handle> iface_name_to_handle_;
+    // Flag to indicate if we have initiated the cleanup of legacy HAL.
+    std::atomic<bool> awaiting_event_loop_termination_;
+    std::condition_variable_any stop_wait_cv_;
+    // Flag to indicate if the legacy HAL has been started.
+    bool is_started_;
+    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+};
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
new file mode 100644
index 0000000..153a685
--- /dev/null
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_legacy_hal_stubs.h"
+
+// TODO: Remove these stubs from HalTool in libwifi-system.
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace legacy_hal {
+template <typename>
+struct stubFunction;
+
+template <typename R, typename... Args>
+struct stubFunction<R (*)(Args...)> {
+    static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
+};
+template <typename... Args>
+struct stubFunction<void (*)(Args...)> {
+    static constexpr void invoke(Args...) {}
+};
+
+template <typename T>
+void populateStubFor(T* val) {
+    *val = &stubFunction<T>::invoke;
+}
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
+    if (hal_fn == nullptr) {
+        return false;
+    }
+    populateStubFor(&hal_fn->wifi_initialize);
+    populateStubFor(&hal_fn->wifi_wait_for_driver_ready);
+    populateStubFor(&hal_fn->wifi_cleanup);
+    populateStubFor(&hal_fn->wifi_event_loop);
+    populateStubFor(&hal_fn->wifi_get_error_info);
+    populateStubFor(&hal_fn->wifi_get_supported_feature_set);
+    populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
+    populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
+    populateStubFor(&hal_fn->wifi_get_supported_channels);
+    populateStubFor(&hal_fn->wifi_is_epr_supported);
+    populateStubFor(&hal_fn->wifi_get_ifaces);
+    populateStubFor(&hal_fn->wifi_get_iface_name);
+    populateStubFor(&hal_fn->wifi_set_iface_event_handler);
+    populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
+    populateStubFor(&hal_fn->wifi_start_gscan);
+    populateStubFor(&hal_fn->wifi_stop_gscan);
+    populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
+    populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
+    populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
+    populateStubFor(&hal_fn->wifi_set_significant_change_handler);
+    populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
+    populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
+    populateStubFor(&hal_fn->wifi_set_link_stats);
+    populateStubFor(&hal_fn->wifi_get_link_stats);
+    populateStubFor(&hal_fn->wifi_clear_link_stats);
+    populateStubFor(&hal_fn->wifi_get_valid_channels);
+    populateStubFor(&hal_fn->wifi_rtt_range_request);
+    populateStubFor(&hal_fn->wifi_rtt_range_cancel);
+    populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
+    populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
+    populateStubFor(&hal_fn->wifi_enable_responder);
+    populateStubFor(&hal_fn->wifi_disable_responder);
+    populateStubFor(&hal_fn->wifi_set_nodfs_flag);
+    populateStubFor(&hal_fn->wifi_start_logging);
+    populateStubFor(&hal_fn->wifi_set_epno_list);
+    populateStubFor(&hal_fn->wifi_reset_epno_list);
+    populateStubFor(&hal_fn->wifi_set_country_code);
+    populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
+    populateStubFor(&hal_fn->wifi_set_log_handler);
+    populateStubFor(&hal_fn->wifi_reset_log_handler);
+    populateStubFor(&hal_fn->wifi_set_alert_handler);
+    populateStubFor(&hal_fn->wifi_reset_alert_handler);
+    populateStubFor(&hal_fn->wifi_get_firmware_version);
+    populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
+    populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
+    populateStubFor(&hal_fn->wifi_get_ring_data);
+    populateStubFor(&hal_fn->wifi_enable_tdls);
+    populateStubFor(&hal_fn->wifi_disable_tdls);
+    populateStubFor(&hal_fn->wifi_get_tdls_status);
+    populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
+    populateStubFor(&hal_fn->wifi_get_driver_version);
+    populateStubFor(&hal_fn->wifi_set_passpoint_list);
+    populateStubFor(&hal_fn->wifi_reset_passpoint_list);
+    populateStubFor(&hal_fn->wifi_set_lci);
+    populateStubFor(&hal_fn->wifi_set_lcr);
+    populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
+    populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
+    populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
+    populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
+    populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
+    populateStubFor(&hal_fn->wifi_configure_nd_offload);
+    populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
+    populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
+    populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
+    populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
+    populateStubFor(&hal_fn->wifi_nan_enable_request);
+    populateStubFor(&hal_fn->wifi_nan_disable_request);
+    populateStubFor(&hal_fn->wifi_nan_publish_request);
+    populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
+    populateStubFor(&hal_fn->wifi_nan_subscribe_request);
+    populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
+    populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
+    populateStubFor(&hal_fn->wifi_nan_stats_request);
+    populateStubFor(&hal_fn->wifi_nan_config_request);
+    populateStubFor(&hal_fn->wifi_nan_tca_request);
+    populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
+    populateStubFor(&hal_fn->wifi_nan_register_handler);
+    populateStubFor(&hal_fn->wifi_nan_get_version);
+    populateStubFor(&hal_fn->wifi_nan_get_capabilities);
+    populateStubFor(&hal_fn->wifi_nan_data_interface_create);
+    populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
+    populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
+    populateStubFor(&hal_fn->wifi_nan_data_indication_response);
+    populateStubFor(&hal_fn->wifi_nan_data_end);
+    populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
+    populateStubFor(&hal_fn->wifi_set_packet_filter);
+    populateStubFor(&hal_fn->wifi_read_packet_filter);
+    populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
+    populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
+    populateStubFor(&hal_fn->wifi_configure_roaming);
+    populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
+    populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
+    populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
+    populateStubFor(&hal_fn->wifi_set_latency_mode);
+    populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
+    populateStubFor(&hal_fn->wifi_virtual_interface_create);
+    populateStubFor(&hal_fn->wifi_virtual_interface_delete);
+    populateStubFor(&hal_fn->wifi_map_dscp_access_category);
+    populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
+    return true;
+}
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.h b/wifi/1.4/default/wifi_legacy_hal_stubs.h
new file mode 100644
index 0000000..577a545
--- /dev/null
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_LEGACY_HAL_STUBS_H_
+#define WIFI_LEGACY_HAL_STUBS_H_
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace legacy_hal {
+#include <hardware_legacy/wifi_hal.h>
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/1.4/default/wifi_mode_controller.cpp b/wifi/1.4/default/wifi_mode_controller.cpp
new file mode 100644
index 0000000..252121a
--- /dev/null
+++ b/wifi/1.4/default/wifi_mode_controller.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#include "wifi_mode_controller.h"
+
+using android::hardware::wifi::V1_0::IfaceType;
+using android::wifi_hal::DriverTool;
+
+namespace {
+int convertIfaceTypeToFirmwareMode(IfaceType type) {
+    int mode;
+    switch (type) {
+        case IfaceType::AP:
+            mode = DriverTool::kFirmwareModeAp;
+            break;
+        case IfaceType::P2P:
+            mode = DriverTool::kFirmwareModeP2p;
+            break;
+        case IfaceType::NAN:
+            // NAN is exposed in STA mode currently.
+            mode = DriverTool::kFirmwareModeSta;
+            break;
+        case IfaceType::STA:
+            mode = DriverTool::kFirmwareModeSta;
+            break;
+    }
+    return mode;
+}
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace mode_controller {
+
+WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
+
+bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
+    return driver_tool_->IsFirmwareModeChangeNeeded(
+        convertIfaceTypeToFirmwareMode(type));
+}
+
+bool WifiModeController::initialize() {
+    if (!driver_tool_->LoadDriver()) {
+        LOG(ERROR) << "Failed to load WiFi driver";
+        return false;
+    }
+    return true;
+}
+
+bool WifiModeController::changeFirmwareMode(IfaceType type) {
+    if (!driver_tool_->ChangeFirmwareMode(
+            convertIfaceTypeToFirmwareMode(type))) {
+        LOG(ERROR) << "Failed to change firmware mode";
+        return false;
+    }
+    return true;
+}
+
+bool WifiModeController::deinitialize() {
+    if (!driver_tool_->UnloadDriver()) {
+        LOG(ERROR) << "Failed to unload WiFi driver";
+        return false;
+    }
+    return true;
+}
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_mode_controller.h b/wifi/1.4/default/wifi_mode_controller.h
new file mode 100644
index 0000000..45fa999
--- /dev/null
+++ b/wifi/1.4/default/wifi_mode_controller.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_MODE_CONTROLLER_H_
+#define WIFI_MODE_CONTROLLER_H_
+
+#include <wifi_hal/driver_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+namespace mode_controller {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * Class that encapsulates all firmware mode configuration.
+ * This class will perform the necessary firmware reloads to put the chip in the
+ * required state (essentially a wrapper over DriverTool).
+ */
+class WifiModeController {
+   public:
+    WifiModeController();
+    virtual ~WifiModeController() = default;
+
+    // Checks if a firmware mode change is necessary to support the specified
+    // iface type operations.
+    virtual bool isFirmwareModeChangeNeeded(IfaceType type);
+    virtual bool initialize();
+    // Change the firmware mode to support the specified iface type operations.
+    virtual bool changeFirmwareMode(IfaceType type);
+    // Unload the driver. This should be invoked whenever |IWifi.stop()| is
+    // invoked.
+    virtual bool deinitialize();
+
+   private:
+    std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
+};
+
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.4/default/wifi_nan_iface.cpp b/wifi/1.4/default/wifi_nan_iface.cpp
new file mode 100644
index 0000000..5764d35
--- /dev/null
+++ b/wifi/1.4/default/wifi_nan_iface.cpp
@@ -0,0 +1,930 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_nan_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiNanIface::WifiNanIface(
+    const std::string& ifname, bool is_dedicated_iface,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+    : ifname_(ifname),
+      is_dedicated_iface_(is_dedicated_iface),
+      legacy_hal_(legacy_hal),
+      iface_util_(iface_util),
+      is_valid_(true) {
+    if (is_dedicated_iface_) {
+        // If using a dedicated iface, set the iface up first.
+        if (!iface_util_.lock()->setUpState(ifname_, true)) {
+            // Fatal failure, invalidate the iface object.
+            invalidate();
+            return;
+        }
+    }
+    // Register all the callbacks here. these should be valid for the lifetime
+    // of the object. Whenever the mode changes legacy HAL will remove
+    // all of these callbacks.
+    legacy_hal::NanCallbackHandlers callback_handlers;
+    android::wp<WifiNanIface> weak_ptr_this(this);
+
+    // Callback for response.
+    callback_handlers
+        .on_notify_response = [weak_ptr_this](
+                                  legacy_hal::transaction_id id,
+                                  const legacy_hal::NanResponseMsg& msg) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        WifiNanStatus wifiNanStatus;
+        if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(
+                msg, &wifiNanStatus)) {
+            LOG(ERROR) << "Failed to convert nan response header";
+            return;
+        }
+
+        switch (msg.response_type) {
+            case legacy_hal::NAN_RESPONSE_ENABLED: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyEnableResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_DISABLED: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyDisableResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_PUBLISH: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyStartPublishResponse(
+                                 id, wifiNanStatus,
+                                 msg.body.publish_response.publish_id)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyStopPublishResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyTransmitFollowupResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyStartSubscribeResponse(
+                                 id, wifiNanStatus,
+                                 msg.body.subscribe_response.subscribe_id)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyStopSubscribeResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_CONFIG: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyConfigResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_GET_CAPABILITIES: {
+                NanCapabilities hidl_struct;
+                if (!hidl_struct_util::
+                        convertLegacyNanCapabilitiesResponseToHidl(
+                            msg.body.nan_capabilities, &hidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyCapabilitiesResponse(id, wifiNanStatus,
+                                                          hidl_struct)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INTERFACE_CREATE: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyCreateDataInterfaceResponse(id,
+                                                                 wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INTERFACE_DELETE: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyDeleteDataInterfaceResponse(id,
+                                                                 wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyInitiateDataPathResponse(
+                                 id, wifiNanStatus,
+                                 msg.body.data_request_response.ndp_instance_id)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyRespondToDataPathIndicationResponse(
+                                 id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_END: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyTerminateDataPathResponse(id,
+                                                               wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_TCA:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_STATS:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_ERROR:
+            /* fall through */
+            default:
+                LOG(ERROR) << "Unknown or unhandled response type: "
+                           << msg.response_type;
+                return;
+        }
+    };
+
+    callback_handlers.on_event_disc_eng_event =
+        [weak_ptr_this](const legacy_hal::NanDiscEngEventInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            NanClusterEventInd hidl_struct;
+            // event types defined identically - hence can be cast
+            hidl_struct.eventType = (NanClusterEventType)msg.event_type;
+            hidl_struct.addr = msg.data.mac_addr.addr;
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventClusterEvent(hidl_struct).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_disabled =
+        [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            WifiNanStatus status;
+            hidl_struct_util::convertToWifiNanStatus(
+                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventDisabled(status).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_publish_terminated =
+        [weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            WifiNanStatus status;
+            hidl_struct_util::convertToWifiNanStatus(
+                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventPublishTerminated(msg.publish_id, status)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_subscribe_terminated =
+        [weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            WifiNanStatus status;
+            hidl_struct_util::convertToWifiNanStatus(
+                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback
+                         ->eventSubscribeTerminated(msg.subscribe_id, status)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_match =
+        [weak_ptr_this](const legacy_hal::NanMatchInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            NanMatchInd hidl_struct;
+            if (!hidl_struct_util::convertLegacyNanMatchIndToHidl(
+                    msg, &hidl_struct)) {
+                LOG(ERROR) << "Failed to convert nan capabilities response";
+                return;
+            }
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventMatch(hidl_struct).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_match_expired =
+        [weak_ptr_this](const legacy_hal::NanMatchExpiredInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback
+                         ->eventMatchExpired(msg.publish_subscribe_id,
+                                             msg.requestor_instance_id)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_followup =
+        [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            NanFollowupReceivedInd hidl_struct;
+            if (!hidl_struct_util::convertLegacyNanFollowupIndToHidl(
+                    msg, &hidl_struct)) {
+                LOG(ERROR) << "Failed to convert nan capabilities response";
+                return;
+            }
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventFollowupReceived(hidl_struct).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_transmit_follow_up =
+        [weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            WifiNanStatus status;
+            hidl_struct_util::convertToWifiNanStatus(
+                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_data_path_request =
+        [weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            NanDataPathRequestInd hidl_struct;
+            if (!hidl_struct_util::convertLegacyNanDataPathRequestIndToHidl(
+                    msg, &hidl_struct)) {
+                LOG(ERROR) << "Failed to convert nan capabilities response";
+                return;
+            }
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventDataPathRequest(hidl_struct).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_data_path_confirm =
+        [weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            V1_2::NanDataPathConfirmInd hidl_struct;
+            if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(
+                    msg, &hidl_struct)) {
+                LOG(ERROR) << "Failed to convert nan capabilities response";
+                return;
+            }
+
+            for (const auto& callback :
+                 shared_ptr_this->getEventCallbacks_1_2()) {
+                if (!callback->eventDataPathConfirm_1_2(hidl_struct).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_data_path_end =
+        [weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                for (int i = 0; i < msg.num_ndp_instances; ++i) {
+                    if (!callback
+                             ->eventDataPathTerminated(msg.ndp_instance_id[i])
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            }
+        };
+
+    callback_handlers.on_event_beacon_sdf_payload =
+        [weak_ptr_this](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
+            LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
+        };
+
+    callback_handlers.on_event_range_request =
+        [weak_ptr_this](const legacy_hal::NanRangeRequestInd& /* msg */) {
+            LOG(ERROR) << "on_event_range_request - should not be called";
+        };
+
+    callback_handlers.on_event_range_report =
+        [weak_ptr_this](const legacy_hal::NanRangeReportInd& /* msg */) {
+            LOG(ERROR) << "on_event_range_report - should not be called";
+        };
+
+    callback_handlers
+        .on_event_schedule_update = [weak_ptr_this](
+                                        const legacy_hal::
+                                            NanDataPathScheduleUpdateInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        V1_2::NanDataPathScheduleUpdateInd hidl_struct;
+        if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
+                msg, &hidl_struct)) {
+            LOG(ERROR) << "Failed to convert nan capabilities response";
+            return;
+        }
+
+        for (const auto& callback : shared_ptr_this->getEventCallbacks_1_2()) {
+            if (!callback->eventDataPathScheduleUpdate(hidl_struct).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_,
+                                                        callback_handlers);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
+        invalidate();
+    }
+
+    // Register for iface state toggle events.
+    iface_util::IfaceEventHandlers event_handlers = {};
+    event_handlers.on_state_toggle_off_on =
+        [weak_ptr_this](const std::string& /* iface_name */) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            // Tell framework that NAN has been disabled.
+            WifiNanStatus status = {
+                NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventDisabled(status).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+    iface_util_.lock()->registerIfaceEventHandlers(ifname_, event_handlers);
+}
+
+void WifiNanIface::invalidate() {
+    // send commands to HAL to actually disable and destroy interfaces
+    legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
+    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");
+    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1");
+    iface_util_.lock()->unregisterIfaceEventHandlers(ifname_);
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    event_cb_handler_1_2_.invalidate();
+    is_valid_ = false;
+    if (is_dedicated_iface_) {
+        // If using a dedicated iface, set the iface down.
+        iface_util_.lock()->setUpState(ifname_, false);
+    }
+}
+
+bool WifiNanIface::isValid() { return is_valid_; }
+
+std::string WifiNanIface::getName() { return ifname_; }
+
+std::set<sp<V1_0::IWifiNanIfaceEventCallback>>
+WifiNanIface::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+std::set<sp<V1_2::IWifiNanIfaceEventCallback>>
+WifiNanIface::getEventCallbacks_1_2() {
+    return event_cb_handler_1_2_.getCallbacks();
+}
+
+Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiNanIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiNanIface::registerEventCallback(
+    const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::registerEventCallbackInternal,
+                           hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::getCapabilitiesRequest(
+    uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getCapabilitiesRequestInternal,
+                           hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiNanIface::enableRequest(uint16_t cmd_id,
+                                         const V1_0::NanEnableRequest& msg,
+                                         enableRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequestInternal, hidl_status_cb,
+                           cmd_id, msg);
+}
+
+Return<void> WifiNanIface::configRequest(uint16_t cmd_id,
+                                         const V1_0::NanConfigRequest& msg,
+                                         configRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequestInternal, hidl_status_cb,
+                           cmd_id, msg);
+}
+
+Return<void> WifiNanIface::disableRequest(uint16_t cmd_id,
+                                          disableRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::disableRequestInternal,
+                           hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiNanIface::startPublishRequest(
+    uint16_t cmd_id, const NanPublishRequest& msg,
+    startPublishRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::startPublishRequestInternal,
+                           hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::stopPublishRequest(
+    uint16_t cmd_id, uint8_t sessionId, stopPublishRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::stopPublishRequestInternal,
+                           hidl_status_cb, cmd_id, sessionId);
+}
+
+Return<void> WifiNanIface::startSubscribeRequest(
+    uint16_t cmd_id, const NanSubscribeRequest& msg,
+    startSubscribeRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::startSubscribeRequestInternal,
+                           hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::stopSubscribeRequest(
+    uint16_t cmd_id, uint8_t sessionId,
+    stopSubscribeRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::stopSubscribeRequestInternal,
+                           hidl_status_cb, cmd_id, sessionId);
+}
+
+Return<void> WifiNanIface::transmitFollowupRequest(
+    uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
+    transmitFollowupRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::transmitFollowupRequestInternal,
+                           hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::createDataInterfaceRequest(
+    uint16_t cmd_id, const hidl_string& iface_name,
+    createDataInterfaceRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::createDataInterfaceRequestInternal,
+                           hidl_status_cb, cmd_id, iface_name);
+}
+
+Return<void> WifiNanIface::deleteDataInterfaceRequest(
+    uint16_t cmd_id, const hidl_string& iface_name,
+    deleteDataInterfaceRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::deleteDataInterfaceRequestInternal,
+                           hidl_status_cb, cmd_id, iface_name);
+}
+
+Return<void> WifiNanIface::initiateDataPathRequest(
+    uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
+    initiateDataPathRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::initiateDataPathRequestInternal,
+                           hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::respondToDataPathIndicationRequest(
+    uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
+    respondToDataPathIndicationRequest_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+        &WifiNanIface::respondToDataPathIndicationRequestInternal,
+        hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::terminateDataPathRequest(
+    uint16_t cmd_id, uint32_t ndpInstanceId,
+    terminateDataPathRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::terminateDataPathRequestInternal,
+                           hidl_status_cb, cmd_id, ndpInstanceId);
+}
+
+Return<void> WifiNanIface::registerEventCallback_1_2(
+    const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
+    registerEventCallback_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::registerEventCallback_1_2Internal,
+                           hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::enableRequest_1_2(
+    uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
+    const V1_2::NanConfigRequestSupplemental& msg2,
+    enableRequest_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequest_1_2Internal,
+                           hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_2(
+    uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
+    const V1_2::NanConfigRequestSupplemental& msg2,
+    configRequest_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequest_1_2Internal,
+                           hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+Return<void> WifiNanIface::enableRequest_1_4(
+    uint16_t cmd_id, const NanEnableRequest& msg1,
+    const V1_2::NanConfigRequestSupplemental& msg2,
+    enableRequest_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequest_1_4Internal,
+                           hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_4(
+    uint16_t cmd_id, const NanConfigRequest& msg1,
+    const V1_2::NanConfigRequestSupplemental& msg2,
+    configRequest_1_4_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequest_1_4Internal,
+                           hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiNanIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
+}
+
+WifiStatus WifiNanIface::registerEventCallbackInternal(
+    const sp<V1_0::IWifiNanIfaceEventCallback>& callback) {
+    if (!event_cb_handler_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::enableRequestInternal(
+    uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequestInternal(
+    uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startPublishRequestInternal(
+    uint16_t cmd_id, const NanPublishRequest& msg) {
+    legacy_hal::NanPublishRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(msg,
+                                                                &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::stopPublishRequestInternal(uint16_t cmd_id,
+                                                    uint8_t sessionId) {
+    legacy_hal::NanPublishCancelRequest legacy_msg;
+    legacy_msg.publish_id = sessionId;
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id,
+                                                    legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startSubscribeRequestInternal(
+    uint16_t cmd_id, const NanSubscribeRequest& msg) {
+    legacy_hal::NanSubscribeRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(
+            msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::stopSubscribeRequestInternal(uint16_t cmd_id,
+                                                      uint8_t sessionId) {
+    legacy_hal::NanSubscribeCancelRequest legacy_msg;
+    legacy_msg.subscribe_id = sessionId;
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id,
+                                                      legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::transmitFollowupRequestInternal(
+    uint16_t cmd_id, const NanTransmitFollowupRequest& msg) {
+    legacy_hal::NanTransmitFollowupRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanTransmitFollowupRequestToLegacy(
+            msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id,
+                                                       legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::createDataInterfaceRequestInternal(
+    uint16_t cmd_id, const std::string& iface_name) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::deleteDataInterfaceRequestInternal(
+    uint16_t cmd_id, const std::string& iface_name) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::initiateDataPathRequestInternal(
+    uint16_t cmd_id, const NanInitiateDataPathRequest& msg) {
+    legacy_hal::NanDataPathInitiatorRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequestToLegacy(
+            msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id,
+                                                    legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
+    uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg) {
+    legacy_hal::NanDataPathIndicationResponse legacy_msg;
+    if (!hidl_struct_util::convertHidlNanDataPathIndicationResponseToLegacy(
+            msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id,
+                                                      legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::terminateDataPathRequestInternal(
+    uint16_t cmd_id, uint32_t ndpInstanceId) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
+    const sp<V1_2::IWifiNanIfaceEventCallback>& callback) {
+    sp<V1_0::IWifiNanIfaceEventCallback> callback_1_0 = callback;
+    if (!event_cb_handler_.addCallback(callback_1_0)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    if (!event_cb_handler_1_2_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_2Internal(
+    uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg1 */,
+    const V1_2::NanConfigRequestSupplemental& /*msg2 */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequest_1_2Internal(
+    uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg1 */,
+    const V1_2::NanConfigRequestSupplemental& /* msg2 */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_4Internal(
+    uint16_t cmd_id, const NanEnableRequest& msg1,
+    const V1_2::NanConfigRequestSupplemental& msg2) {
+    legacy_hal::NanEnableRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanEnableRequest_1_4ToLegacy(
+            msg1, msg2, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::configRequest_1_4Internal(
+    uint16_t cmd_id, const NanConfigRequest& msg1,
+    const V1_2::NanConfigRequestSupplemental& msg2) {
+    legacy_hal::NanConfigRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanConfigRequest_1_4ToLegacy(
+            msg1, msg2, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_nan_iface.h b/wifi/1.4/default/wifi_nan_iface.h
new file mode 100644
index 0000000..06edbf2
--- /dev/null
+++ b/wifi/1.4/default/wifi_nan_iface.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_NAN_IFACE_H_
+#define WIFI_NAN_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
+#include <android/hardware/wifi/1.4/IWifiNanIface.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+using namespace android::hardware::wifi::V1_2;
+
+/**
+ * HIDL interface object used to control a NAN Iface instance.
+ */
+class WifiNanIface : public V1_4::IWifiNanIface {
+   public:
+    WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+    Return<void> registerEventCallback(
+        const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
+        registerEventCallback_cb hidl_status_cb) override;
+    Return<void> getCapabilitiesRequest(
+        uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) override;
+    Return<void> enableRequest(uint16_t cmd_id,
+                               const V1_0::NanEnableRequest& msg,
+                               enableRequest_cb hidl_status_cb) override;
+    Return<void> configRequest(uint16_t cmd_id,
+                               const V1_0::NanConfigRequest& msg,
+                               configRequest_cb hidl_status_cb) override;
+    Return<void> disableRequest(uint16_t cmd_id,
+                                disableRequest_cb hidl_status_cb) override;
+    Return<void> startPublishRequest(
+        uint16_t cmd_id, const NanPublishRequest& msg,
+        startPublishRequest_cb hidl_status_cb) override;
+    Return<void> stopPublishRequest(
+        uint16_t cmd_id, uint8_t sessionId,
+        stopPublishRequest_cb hidl_status_cb) override;
+    Return<void> startSubscribeRequest(
+        uint16_t cmd_id, const NanSubscribeRequest& msg,
+        startSubscribeRequest_cb hidl_status_cb) override;
+    Return<void> stopSubscribeRequest(
+        uint16_t cmd_id, uint8_t sessionId,
+        stopSubscribeRequest_cb hidl_status_cb) override;
+    Return<void> transmitFollowupRequest(
+        uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
+        transmitFollowupRequest_cb hidl_status_cb) override;
+    Return<void> createDataInterfaceRequest(
+        uint16_t cmd_id, const hidl_string& iface_name,
+        createDataInterfaceRequest_cb hidl_status_cb) override;
+    Return<void> deleteDataInterfaceRequest(
+        uint16_t cmd_id, const hidl_string& iface_name,
+        deleteDataInterfaceRequest_cb hidl_status_cb) override;
+    Return<void> initiateDataPathRequest(
+        uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
+        initiateDataPathRequest_cb hidl_status_cb) override;
+    Return<void> respondToDataPathIndicationRequest(
+        uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
+        respondToDataPathIndicationRequest_cb hidl_status_cb) override;
+    Return<void> terminateDataPathRequest(
+        uint16_t cmd_id, uint32_t ndpInstanceId,
+        terminateDataPathRequest_cb hidl_status_cb) override;
+
+    Return<void> registerEventCallback_1_2(
+        const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
+        registerEventCallback_1_2_cb hidl_status_cb) override;
+    Return<void> enableRequest_1_2(
+        uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
+        const V1_2::NanConfigRequestSupplemental& msg2,
+        enableRequest_1_2_cb hidl_status_cb) override;
+    Return<void> configRequest_1_2(
+        uint16_t cmd_id, const V1_0::NanConfigRequest& msg1,
+        const V1_2::NanConfigRequestSupplemental& msg2,
+        configRequest_1_2_cb hidl_status_cb) override;
+    Return<void> enableRequest_1_4(
+        uint16_t cmd_id, const NanEnableRequest& msg1,
+        const V1_2::NanConfigRequestSupplemental& msg2,
+        enableRequest_1_2_cb hidl_status_cb) override;
+    Return<void> configRequest_1_4(
+        uint16_t cmd_id, const NanConfigRequest& msg1,
+        const V1_2::NanConfigRequestSupplemental& msg2,
+        configRequest_1_2_cb hidl_status_cb) override;
+
+   private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+    WifiStatus registerEventCallbackInternal(
+        const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
+    WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
+    WifiStatus enableRequestInternal(uint16_t cmd_id,
+                                     const V1_0::NanEnableRequest& msg);
+    WifiStatus configRequestInternal(uint16_t cmd_id,
+                                     const V1_0::NanConfigRequest& msg);
+    WifiStatus disableRequestInternal(uint16_t cmd_id);
+    WifiStatus startPublishRequestInternal(uint16_t cmd_id,
+                                           const NanPublishRequest& msg);
+    WifiStatus stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId);
+    WifiStatus startSubscribeRequestInternal(uint16_t cmd_id,
+                                             const NanSubscribeRequest& msg);
+    WifiStatus stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId);
+    WifiStatus transmitFollowupRequestInternal(
+        uint16_t cmd_id, const NanTransmitFollowupRequest& msg);
+    WifiStatus createDataInterfaceRequestInternal(
+        uint16_t cmd_id, const std::string& iface_name);
+    WifiStatus deleteDataInterfaceRequestInternal(
+        uint16_t cmd_id, const std::string& iface_name);
+    WifiStatus initiateDataPathRequestInternal(
+        uint16_t cmd_id, const NanInitiateDataPathRequest& msg);
+    WifiStatus respondToDataPathIndicationRequestInternal(
+        uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg);
+    WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id,
+                                                uint32_t ndpInstanceId);
+
+    WifiStatus registerEventCallback_1_2Internal(
+        const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
+    WifiStatus enableRequest_1_2Internal(
+        uint16_t cmd_id, const V1_0::NanEnableRequest& msg1,
+        const V1_2::NanConfigRequestSupplemental& msg2);
+    WifiStatus configRequest_1_2Internal(
+        uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
+        const V1_2::NanConfigRequestSupplemental& msg2);
+    WifiStatus enableRequest_1_4Internal(
+        uint16_t cmd_id, const NanEnableRequest& msg1,
+        const V1_2::NanConfigRequestSupplemental& msg2);
+    WifiStatus configRequest_1_4Internal(
+        uint16_t cmd_id, const NanConfigRequest& msg,
+        const V1_2::NanConfigRequestSupplemental& msg2);
+
+    // all 1_0 and descendant callbacks
+    std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
+    // all 1_2 and descendant callbacks
+    std::set<sp<V1_2::IWifiNanIfaceEventCallback>> getEventCallbacks_1_2();
+
+    std::string ifname_;
+    bool is_dedicated_iface_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    bool is_valid_;
+    hidl_callback_util::HidlCallbackHandler<V1_0::IWifiNanIfaceEventCallback>
+        event_cb_handler_;
+    hidl_callback_util::HidlCallbackHandler<V1_2::IWifiNanIfaceEventCallback>
+        event_cb_handler_1_2_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_NAN_IFACE_H_
diff --git a/wifi/1.4/default/wifi_p2p_iface.cpp b/wifi/1.4/default/wifi_p2p_iface.cpp
new file mode 100644
index 0000000..9e7341f
--- /dev/null
+++ b/wifi/1.4/default/wifi_p2p_iface.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_return_util.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiP2pIface::WifiP2pIface(
+    const std::string& ifname,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
+
+void WifiP2pIface::invalidate() {
+    legacy_hal_.reset();
+    is_valid_ = false;
+}
+
+bool WifiP2pIface::isValid() { return is_valid_; }
+
+std::string WifiP2pIface::getName() { return ifname_; }
+
+Return<void> WifiP2pIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiP2pIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiP2pIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiP2pIface::getTypeInternal, hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiP2pIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::P2P};
+}
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_p2p_iface.h b/wifi/1.4/default/wifi_p2p_iface.h
new file mode 100644
index 0000000..a6fc59d
--- /dev/null
+++ b/wifi/1.4/default/wifi_p2p_iface.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_P2P_IFACE_H_
+#define WIFI_P2P_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a P2P Iface instance.
+ */
+class WifiP2pIface : public V1_0::IWifiP2pIface {
+   public:
+    WifiP2pIface(const std::string& ifname,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+
+   private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_P2P_IFACE_H_
diff --git a/wifi/1.4/default/wifi_rtt_controller.cpp b/wifi/1.4/default/wifi_rtt_controller.cpp
new file mode 100644
index 0000000..594a116
--- /dev/null
+++ b/wifi/1.4/default/wifi_rtt_controller.cpp
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiRttController::WifiRttController(
+    const std::string& iface_name, const sp<IWifiIface>& bound_iface,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(iface_name),
+      bound_iface_(bound_iface),
+      legacy_hal_(legacy_hal),
+      is_valid_(true) {}
+
+void WifiRttController::invalidate() {
+    legacy_hal_.reset();
+    event_callbacks_.clear();
+    is_valid_ = false;
+}
+
+bool WifiRttController::isValid() { return is_valid_; }
+
+std::vector<sp<IWifiRttControllerEventCallback>>
+WifiRttController::getEventCallbacks() {
+    return event_callbacks_;
+}
+
+std::string WifiRttController::getIfaceName() { return ifname_; }
+
+Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::getBoundIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::registerEventCallback(
+    const sp<V1_0::IWifiRttControllerEventCallback>& callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this,
+                           WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::registerEventCallbackInternal,
+                           hidl_status_cb, callback);
+}
+
+Return<void> WifiRttController::rangeRequest(
+    uint32_t cmd_id, const hidl_vec<V1_0::RttConfig>& rtt_configs,
+    rangeRequest_cb hidl_status_cb) {
+    return validateAndCall(this,
+                           WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::rangeRequestInternal,
+                           hidl_status_cb, cmd_id, rtt_configs);
+}
+
+Return<void> WifiRttController::rangeCancel(
+    uint32_t cmd_id, const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
+    rangeCancel_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::rangeCancelInternal, hidl_status_cb, cmd_id, addrs);
+}
+
+Return<void> WifiRttController::getCapabilities(
+    getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::setLci(uint32_t cmd_id,
+                                       const RttLciInformation& lci,
+                                       setLci_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::setLciInternal, hidl_status_cb, cmd_id, lci);
+}
+
+Return<void> WifiRttController::setLcr(uint32_t cmd_id,
+                                       const RttLcrInformation& lcr,
+                                       setLcr_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::setLcrInternal, hidl_status_cb, cmd_id, lcr);
+}
+
+Return<void> WifiRttController::getResponderInfo(
+    getResponderInfo_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::getResponderInfoInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder(
+    uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+    uint32_t max_duration_seconds, const V1_0::RttResponder& info,
+    enableResponder_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::enableResponderInternal, hidl_status_cb, cmd_id,
+        channel_hint, max_duration_seconds, info);
+}
+
+Return<void> WifiRttController::disableResponder(
+    uint32_t cmd_id, disableResponder_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiRttController::registerEventCallback_1_4(
+    const sp<IWifiRttControllerEventCallback>& callback,
+    registerEventCallback_1_4_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::registerEventCallbackInternal_1_4, hidl_status_cb,
+        callback);
+}
+
+Return<void> WifiRttController::rangeRequest_1_4(
+    uint32_t cmd_id, const hidl_vec<RttConfig>& rtt_configs,
+    rangeRequest_1_4_cb hidl_status_cb) {
+    return validateAndCall(this,
+                           WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::rangeRequestInternal_1_4,
+                           hidl_status_cb, cmd_id, rtt_configs);
+}
+
+Return<void> WifiRttController::getCapabilities_1_4(
+    getCapabilities_1_4_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::getCapabilitiesInternal_1_4, hidl_status_cb);
+}
+
+Return<void> WifiRttController::getResponderInfo_1_4(
+    getResponderInfo_1_4_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::getResponderInfoInternal_1_4, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder_1_4(
+    uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+    uint32_t max_duration_seconds, const RttResponder& info,
+    enableResponder_1_4_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::enableResponderInternal_1_4, hidl_status_cb, cmd_id,
+        channel_hint, max_duration_seconds, info);
+}
+
+std::pair<WifiStatus, sp<IWifiIface>>
+WifiRttController::getBoundIfaceInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal(
+    const sp<V1_0::IWifiRttControllerEventCallback>& /* callback */) {
+    // Deprecated support for this api
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal(
+    uint32_t /* cmd_id */,
+    const std::vector<V1_0::RttConfig>& /* rtt_configs */) {
+    // Deprecated support for this api
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiRttController::rangeCancelInternal(
+    uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
+    std::vector<std::array<uint8_t, 6>> legacy_addrs;
+    for (const auto& addr : addrs) {
+        legacy_addrs.push_back(addr);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id,
+                                                  legacy_addrs);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::RttCapabilities>
+WifiRttController::getCapabilitiesInternal() {
+    // Deprecated support for this api
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id,
+                                             const RttLciInformation& lci) {
+    legacy_hal::wifi_lci_information legacy_lci;
+    if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci,
+                                                                &legacy_lci)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id,
+                                             const RttLcrInformation& lcr) {
+    legacy_hal::wifi_lcr_information legacy_lcr;
+    if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr,
+                                                                &legacy_lcr)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::RttResponder>
+WifiRttController::getResponderInfoInternal() {
+    // Deprecated support for this api
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+WifiStatus WifiRttController::enableResponderInternal(
+    uint32_t /* cmd_id */, const WifiChannelInfo& /* channel_hint */,
+    uint32_t /* max_duration_seconds */, const V1_0::RttResponder& /* info */) {
+    // Deprecated support for this api
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED)};
+}
+
+WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal_1_4(
+    const sp<IWifiRttControllerEventCallback>& callback) {
+    // TODO(b/31632518): remove the callback when the client is destroyed
+    event_callbacks_.emplace_back(callback);
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal_1_4(
+    uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
+    std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
+    if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(
+            rtt_configs, &legacy_configs)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    android::wp<WifiRttController> weak_ptr_this(this);
+    const auto& on_results_callback =
+        [weak_ptr_this](
+            legacy_hal::wifi_request_id id,
+            const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            std::vector<RttResult> hidl_results;
+            if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(
+                    results, &hidl_results)) {
+                LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                callback->onResults_1_4(id, hidl_results);
+            }
+        };
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->startRttRangeRequest(
+            ifname_, cmd_id, legacy_configs, on_results_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, RttCapabilities>
+WifiRttController::getCapabilitiesInternal_1_4() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_rtt_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) =
+        legacy_hal_.lock()->getRttCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    RttCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps,
+                                                              &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, RttResponder>
+WifiRttController::getResponderInfoInternal_1_4() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_rtt_responder legacy_responder;
+    std::tie(legacy_status, legacy_responder) =
+        legacy_hal_.lock()->getRttResponderInfo(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    RttResponder hidl_responder;
+    if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder,
+                                                           &hidl_responder)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
+}
+
+WifiStatus WifiRttController::enableResponderInternal_1_4(
+    uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+    uint32_t max_duration_seconds, const RttResponder& info) {
+    legacy_hal::wifi_channel_info legacy_channel_info;
+    if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(
+            channel_hint, &legacy_channel_info)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_rtt_responder legacy_responder;
+    if (!hidl_struct_util::convertHidlRttResponderToLegacy(info,
+                                                           &legacy_responder)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->enableRttResponder(
+            ifname_, cmd_id, legacy_channel_info, max_duration_seconds,
+            legacy_responder);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_rtt_controller.h b/wifi/1.4/default/wifi_rtt_controller.h
new file mode 100644
index 0000000..1f12555
--- /dev/null
+++ b/wifi/1.4/default/wifi_rtt_controller.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_RTT_CONTROLLER_H_
+#define WIFI_RTT_CONTROLLER_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiIface.h>
+#include <android/hardware/wifi/1.4/IWifiRttController.h>
+#include <android/hardware/wifi/1.4/IWifiRttControllerEventCallback.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+/**
+ * HIDL interface object used to control all RTT operations.
+ */
+class WifiRttController : public V1_4::IWifiRttController {
+   public:
+    WifiRttController(
+        const std::string& iface_name, const sp<IWifiIface>& bound_iface,
+        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::vector<sp<IWifiRttControllerEventCallback>> getEventCallbacks();
+    std::string getIfaceName();
+
+    // HIDL methods exposed.
+    Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
+    Return<void> registerEventCallback(
+        const sp<V1_0::IWifiRttControllerEventCallback>& callback,
+        registerEventCallback_cb hidl_status_cb) override;
+    Return<void> rangeRequest(uint32_t cmd_id,
+                              const hidl_vec<V1_0::RttConfig>& rtt_configs,
+                              rangeRequest_cb hidl_status_cb) override;
+    Return<void> rangeCancel(uint32_t cmd_id,
+                             const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
+                             rangeCancel_cb hidl_status_cb) override;
+    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+    Return<void> setLci(uint32_t cmd_id, const RttLciInformation& lci,
+                        setLci_cb hidl_status_cb) override;
+    Return<void> setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
+                        setLcr_cb hidl_status_cb) override;
+    Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
+    Return<void> enableResponder(uint32_t cmd_id,
+                                 const WifiChannelInfo& channel_hint,
+                                 uint32_t max_duration_seconds,
+                                 const V1_0::RttResponder& info,
+                                 enableResponder_cb hidl_status_cb) override;
+    Return<void> disableResponder(uint32_t cmd_id,
+                                  disableResponder_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_4(
+        const sp<IWifiRttControllerEventCallback>& callback,
+        registerEventCallback_1_4_cb hidl_status_cb) override;
+    Return<void> rangeRequest_1_4(uint32_t cmd_id,
+                                  const hidl_vec<RttConfig>& rtt_configs,
+                                  rangeRequest_1_4_cb hidl_status_cb) override;
+    Return<void> getCapabilities_1_4(
+        getCapabilities_1_4_cb hidl_status_cb) override;
+    Return<void> getResponderInfo_1_4(
+        getResponderInfo_1_4_cb hidl_status_cb) override;
+    Return<void> enableResponder_1_4(
+        uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+        uint32_t max_duration_seconds, const RttResponder& info,
+        enableResponder_1_4_cb hidl_status_cb) override;
+
+   private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, sp<IWifiIface>> getBoundIfaceInternal();
+    WifiStatus registerEventCallbackInternal(
+        const sp<V1_0::IWifiRttControllerEventCallback>& callback);
+    WifiStatus rangeRequestInternal(
+        uint32_t cmd_id, const std::vector<V1_0::RttConfig>& rtt_configs);
+    WifiStatus rangeCancelInternal(
+        uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs);
+    std::pair<WifiStatus, V1_0::RttCapabilities> getCapabilitiesInternal();
+    WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
+    WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
+    std::pair<WifiStatus, V1_0::RttResponder> getResponderInfoInternal();
+    WifiStatus enableResponderInternal(uint32_t cmd_id,
+                                       const WifiChannelInfo& channel_hint,
+                                       uint32_t max_duration_seconds,
+                                       const V1_0::RttResponder& info);
+    WifiStatus disableResponderInternal(uint32_t cmd_id);
+    WifiStatus registerEventCallbackInternal_1_4(
+        const sp<IWifiRttControllerEventCallback>& callback);
+    WifiStatus rangeRequestInternal_1_4(
+        uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs);
+    std::pair<WifiStatus, RttCapabilities> getCapabilitiesInternal_1_4();
+    std::pair<WifiStatus, RttResponder> getResponderInfoInternal_1_4();
+    WifiStatus enableResponderInternal_1_4(uint32_t cmd_id,
+                                           const WifiChannelInfo& channel_hint,
+                                           uint32_t max_duration_seconds,
+                                           const RttResponder& info);
+
+    std::string ifname_;
+    sp<IWifiIface> bound_iface_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::vector<sp<IWifiRttControllerEventCallback>> event_callbacks_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiRttController);
+};
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp
new file mode 100644
index 0000000..49f383a
--- /dev/null
+++ b/wifi/1.4/default/wifi_sta_iface.cpp
@@ -0,0 +1,646 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_sta_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiStaIface::WifiStaIface(
+    const std::string& ifname,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+    : ifname_(ifname),
+      legacy_hal_(legacy_hal),
+      iface_util_(iface_util),
+      is_valid_(true) {
+    // Turn on DFS channel usage for STA iface.
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setDfsFlag(ifname_, true);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR)
+            << "Failed to set DFS flag; DFS channels may be unavailable.";
+    }
+}
+
+void WifiStaIface::invalidate() {
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    is_valid_ = false;
+}
+
+bool WifiStaIface::isValid() { return is_valid_; }
+
+std::string WifiStaIface::getName() { return ifname_; }
+
+std::set<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::registerEventCallback(
+    const sp<IWifiStaIfaceEventCallback>& callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::registerEventCallbackInternal,
+                           hidl_status_cb, callback);
+}
+
+Return<void> WifiStaIface::getCapabilities(getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getCapabilitiesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getApfPacketFilterCapabilities(
+    getApfPacketFilterCapabilities_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+        &WifiStaIface::getApfPacketFilterCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::installApfPacketFilter(
+    uint32_t cmd_id, const hidl_vec<uint8_t>& program,
+    installApfPacketFilter_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::installApfPacketFilterInternal,
+                           hidl_status_cb, cmd_id, program);
+}
+
+Return<void> WifiStaIface::readApfPacketFilterData(
+    readApfPacketFilterData_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::readApfPacketFilterDataInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getBackgroundScanCapabilities(
+    getBackgroundScanCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getBackgroundScanCapabilitiesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getValidFrequenciesForBand(
+    V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getValidFrequenciesForBandInternal,
+                           hidl_status_cb, band);
+}
+
+Return<void> WifiStaIface::startBackgroundScan(
+    uint32_t cmd_id, const StaBackgroundScanParameters& params,
+    startBackgroundScan_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startBackgroundScanInternal,
+                           hidl_status_cb, cmd_id, params);
+}
+
+Return<void> WifiStaIface::stopBackgroundScan(
+    uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopBackgroundScanInternal,
+                           hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::enableLinkLayerStatsCollection(
+    bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+        &WifiStaIface::enableLinkLayerStatsCollectionInternal, hidl_status_cb,
+        debug);
+}
+
+Return<void> WifiStaIface::disableLinkLayerStatsCollection(
+    disableLinkLayerStatsCollection_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+        &WifiStaIface::disableLinkLayerStatsCollectionInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats(
+    getLinkLayerStats_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getLinkLayerStatsInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats_1_3(
+    getLinkLayerStats_1_3_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getLinkLayerStatsInternal_1_3,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::startRssiMonitoring(
+    uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
+    startRssiMonitoring_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startRssiMonitoringInternal,
+                           hidl_status_cb, cmd_id, max_rssi, min_rssi);
+}
+
+Return<void> WifiStaIface::stopRssiMonitoring(
+    uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopRssiMonitoringInternal,
+                           hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::getRoamingCapabilities(
+    getRoamingCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getRoamingCapabilitiesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::configureRoaming(
+    const StaRoamingConfig& config, configureRoaming_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::configureRoamingInternal,
+                           hidl_status_cb, config);
+}
+
+Return<void> WifiStaIface::setRoamingState(StaRoamingState state,
+                                           setRoamingState_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setRoamingStateInternal,
+                           hidl_status_cb, state);
+}
+
+Return<void> WifiStaIface::enableNdOffload(bool enable,
+                                           enableNdOffload_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::enableNdOffloadInternal,
+                           hidl_status_cb, enable);
+}
+
+Return<void> WifiStaIface::startSendingKeepAlivePackets(
+    uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
+    uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
+    const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
+    startSendingKeepAlivePackets_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startSendingKeepAlivePacketsInternal,
+                           hidl_status_cb, cmd_id, ip_packet_data, ether_type,
+                           src_address, dst_address, period_in_ms);
+}
+
+Return<void> WifiStaIface::stopSendingKeepAlivePackets(
+    uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopSendingKeepAlivePacketsInternal,
+                           hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::setScanningMacOui(
+    const hidl_array<uint8_t, 3>& oui, setScanningMacOui_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setScanningMacOuiInternal,
+                           hidl_status_cb, oui);
+}
+
+Return<void> WifiStaIface::startDebugPacketFateMonitoring(
+    startDebugPacketFateMonitoring_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+        &WifiStaIface::startDebugPacketFateMonitoringInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getDebugTxPacketFates(
+    getDebugTxPacketFates_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getDebugTxPacketFatesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getDebugRxPacketFates(
+    getDebugRxPacketFates_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getDebugRxPacketFatesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                                         setMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setMacAddressInternal, hidl_status_cb,
+                           mac);
+}
+
+Return<void> WifiStaIface::getFactoryMacAddress(
+    getFactoryMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getFactoryMacAddressInternal,
+                           hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiStaIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::STA};
+}
+
+WifiStatus WifiStaIface::registerEventCallbackInternal(
+    const sp<IWifiStaIfaceEventCallback>& callback) {
+    if (!event_cb_handler_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    uint64_t legacy_feature_set;
+    std::tie(legacy_status, legacy_feature_set) =
+        legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), 0};
+    }
+    uint32_t legacy_logger_feature_set;
+    std::tie(legacy_status, legacy_logger_feature_set) =
+        legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        // some devices don't support querying logger feature set
+        legacy_logger_feature_set = 0;
+    }
+    uint32_t hidl_caps;
+    if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
+            legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, StaApfPacketFilterCapabilities>
+WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::PacketFilterCapabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) =
+        legacy_hal_.lock()->getPacketFilterCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    StaApfPacketFilterCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps,
+                                                              &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiStaIface::installApfPacketFilterInternal(
+    uint32_t /* cmd_id */, const std::vector<uint8_t>& program) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setPacketFilter(ifname_, program);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>>
+WifiStaIface::readApfPacketFilterDataInternal() {
+    const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>>
+        legacy_status_and_data =
+            legacy_hal_.lock()->readApfPacketFilterData(ifname_);
+    return {createWifiStatusFromLegacyError(legacy_status_and_data.first),
+            std::move(legacy_status_and_data.second)};
+}
+
+std::pair<WifiStatus, StaBackgroundScanCapabilities>
+WifiStaIface::getBackgroundScanCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_gscan_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) =
+        legacy_hal_.lock()->getGscanCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    StaBackgroundScanCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps,
+                                                                &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+WifiStaIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
+    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
+                  "Size mismatch");
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint32_t> valid_frequencies;
+    std::tie(legacy_status, valid_frequencies) =
+        legacy_hal_.lock()->getValidFrequenciesForBand(
+            ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
+    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
+}
+
+WifiStatus WifiStaIface::startBackgroundScanInternal(
+    uint32_t cmd_id, const StaBackgroundScanParameters& params) {
+    legacy_hal::wifi_scan_cmd_params legacy_params;
+    if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params,
+                                                          &legacy_params)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    android::wp<WifiStaIface> weak_ptr_this(this);
+    const auto& on_failure_callback =
+        [weak_ptr_this](legacy_hal::wifi_request_id id) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onBackgroundScanFailure(id).isOk()) {
+                    LOG(ERROR)
+                        << "Failed to invoke onBackgroundScanFailure callback";
+                }
+            }
+        };
+    const auto& on_results_callback =
+        [weak_ptr_this](
+            legacy_hal::wifi_request_id id,
+            const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            std::vector<StaScanData> hidl_scan_datas;
+            if (!hidl_struct_util::
+                    convertLegacyVectorOfCachedGscanResultsToHidl(
+                        results, &hidl_scan_datas)) {
+                LOG(ERROR) << "Failed to convert scan results to HIDL structs";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onBackgroundScanResults(id, hidl_scan_datas)
+                         .isOk()) {
+                    LOG(ERROR)
+                        << "Failed to invoke onBackgroundScanResults callback";
+                }
+            }
+        };
+    const auto& on_full_result_callback = [weak_ptr_this](
+                                              legacy_hal::wifi_request_id id,
+                                              const legacy_hal::
+                                                  wifi_scan_result* result,
+                                              uint32_t buckets_scanned) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        StaScanResult hidl_scan_result;
+        if (!hidl_struct_util::convertLegacyGscanResultToHidl(
+                *result, true, &hidl_scan_result)) {
+            LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback
+                     ->onBackgroundFullScanResult(id, buckets_scanned,
+                                                  hidl_scan_result)
+                     .isOk()) {
+                LOG(ERROR)
+                    << "Failed to invoke onBackgroundFullScanResult callback";
+            }
+        }
+    };
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startGscan(
+        ifname_, cmd_id, legacy_params, on_failure_callback,
+        on_results_callback, on_full_result_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->disableLinkLayerStats(ifname_);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, V1_0::StaLinkLayerStats>
+WifiStaIface::getLinkLayerStatsInternal() {
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_3::StaLinkLayerStats>
+WifiStaIface::getLinkLayerStatsInternal_1_3() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::LinkLayerStats legacy_stats;
+    std::tie(legacy_status, legacy_stats) =
+        legacy_hal_.lock()->getLinkLayerStats(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    V1_3::StaLinkLayerStats hidl_stats;
+    if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
+                                                             &hidl_stats)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id,
+                                                     int32_t max_rssi,
+                                                     int32_t min_rssi) {
+    android::wp<WifiStaIface> weak_ptr_this(this);
+    const auto& on_threshold_breached_callback =
+        [weak_ptr_this](legacy_hal::wifi_request_id id,
+                        std::array<uint8_t, 6> bssid, int8_t rssi) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onRssiThresholdBreached(id, bssid, rssi)
+                         .isOk()) {
+                    LOG(ERROR)
+                        << "Failed to invoke onRssiThresholdBreached callback";
+                }
+            }
+        };
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->startRssiMonitoring(ifname_, cmd_id, max_rssi,
+                                                min_rssi,
+                                                on_threshold_breached_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, StaRoamingCapabilities>
+WifiStaIface::getRoamingCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_roaming_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) =
+        legacy_hal_.lock()->getRoamingCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    StaRoamingCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyRoamingCapabilitiesToHidl(legacy_caps,
+                                                                  &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiStaIface::configureRoamingInternal(
+    const StaRoamingConfig& config) {
+    legacy_hal::wifi_roaming_config legacy_config;
+    if (!hidl_struct_util::convertHidlRoamingConfigToLegacy(config,
+                                                            &legacy_config)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->configureRoaming(ifname_, legacy_config);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->enableFirmwareRoaming(
+            ifname_, hidl_struct_util::convertHidlRoamingStateToLegacy(state));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->configureNdOffload(ifname_, enable);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
+    uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
+    uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
+    const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->startSendingOffloadedPacket(
+            ifname_, cmd_id, ether_type, ip_packet_data, src_address,
+            dst_address, period_in_ms);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::setScanningMacOuiInternal(
+    const std::array<uint8_t, 3>& /* oui */) {
+    // deprecated.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->startPktFateMonitoring(ifname_);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
+WifiStaIface::getDebugTxPacketFatesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_tx_report> legacy_fates;
+    std::tie(legacy_status, legacy_fates) =
+        legacy_hal_.lock()->getTxPktFates(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    std::vector<WifiDebugTxPacketFateReport> hidl_fates;
+    if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(
+            legacy_fates, &hidl_fates)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
+WifiStaIface::getDebugRxPacketFatesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_rx_report> legacy_fates;
+    std::tie(legacy_status, legacy_fates) =
+        legacy_hal_.lock()->getRxPktFates(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    std::vector<WifiDebugRxPacketFateReport> hidl_fates;
+    if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(
+            legacy_fates, &hidl_fates)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
+}
+
+WifiStatus WifiStaIface::setMacAddressInternal(
+    const std::array<uint8_t, 6>& mac) {
+    bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
+    if (!status) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::array<uint8_t, 6>>
+WifiStaIface::getFactoryMacAddressInternal() {
+    std::array<uint8_t, 6> mac =
+        iface_util_.lock()->getFactoryMacAddress(ifname_);
+    return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
+}
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h
new file mode 100644
index 0000000..dee04f2
--- /dev/null
+++ b/wifi/1.4/default/wifi_sta_iface.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_STA_IFACE_H_
+#define WIFI_STA_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
+#include <android/hardware/wifi/1.3/IWifiStaIface.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a STA Iface instance.
+ */
+class WifiStaIface : public V1_3::IWifiStaIface {
+   public:
+    WifiStaIface(const std::string& ifname,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::set<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+    Return<void> registerEventCallback(
+        const sp<IWifiStaIfaceEventCallback>& callback,
+        registerEventCallback_cb hidl_status_cb) override;
+    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+    Return<void> getApfPacketFilterCapabilities(
+        getApfPacketFilterCapabilities_cb hidl_status_cb) override;
+    Return<void> installApfPacketFilter(
+        uint32_t cmd_id, const hidl_vec<uint8_t>& program,
+        installApfPacketFilter_cb hidl_status_cb) override;
+    Return<void> readApfPacketFilterData(
+        readApfPacketFilterData_cb hidl_status_cb) override;
+    Return<void> getBackgroundScanCapabilities(
+        getBackgroundScanCapabilities_cb hidl_status_cb) override;
+    Return<void> getValidFrequenciesForBand(
+        V1_0::WifiBand band,
+        getValidFrequenciesForBand_cb hidl_status_cb) override;
+    Return<void> startBackgroundScan(
+        uint32_t cmd_id, const StaBackgroundScanParameters& params,
+        startBackgroundScan_cb hidl_status_cb) override;
+    Return<void> stopBackgroundScan(
+        uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) override;
+    Return<void> enableLinkLayerStatsCollection(
+        bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) override;
+    Return<void> disableLinkLayerStatsCollection(
+        disableLinkLayerStatsCollection_cb hidl_status_cb) override;
+    Return<void> getLinkLayerStats(
+        getLinkLayerStats_cb hidl_status_cb) override;
+    Return<void> getLinkLayerStats_1_3(
+        getLinkLayerStats_1_3_cb hidl_status_cb) override;
+    Return<void> startRssiMonitoring(
+        uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
+        startRssiMonitoring_cb hidl_status_cb) override;
+    Return<void> stopRssiMonitoring(
+        uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
+    Return<void> getRoamingCapabilities(
+        getRoamingCapabilities_cb hidl_status_cb) override;
+    Return<void> configureRoaming(const StaRoamingConfig& config,
+                                  configureRoaming_cb hidl_status_cb) override;
+    Return<void> setRoamingState(StaRoamingState state,
+                                 setRoamingState_cb hidl_status_cb) override;
+    Return<void> enableNdOffload(bool enable,
+                                 enableNdOffload_cb hidl_status_cb) override;
+    Return<void> startSendingKeepAlivePackets(
+        uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
+        uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
+        const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
+        startSendingKeepAlivePackets_cb hidl_status_cb) override;
+    Return<void> stopSendingKeepAlivePackets(
+        uint32_t cmd_id,
+        stopSendingKeepAlivePackets_cb hidl_status_cb) override;
+    Return<void> setScanningMacOui(
+        const hidl_array<uint8_t, 3>& oui,
+        setScanningMacOui_cb hidl_status_cb) override;
+    Return<void> startDebugPacketFateMonitoring(
+        startDebugPacketFateMonitoring_cb hidl_status_cb) override;
+    Return<void> getDebugTxPacketFates(
+        getDebugTxPacketFates_cb hidl_status_cb) override;
+    Return<void> getDebugRxPacketFates(
+        getDebugRxPacketFates_cb hidl_status_cb) override;
+    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                               setMacAddress_cb hidl_status_cb) override;
+    Return<void> getFactoryMacAddress(
+        getFactoryMacAddress_cb hidl_status_cb) override;
+
+   private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+    WifiStatus registerEventCallbackInternal(
+        const sp<IWifiStaIfaceEventCallback>& callback);
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
+    std::pair<WifiStatus, StaApfPacketFilterCapabilities>
+    getApfPacketFilterCapabilitiesInternal();
+    WifiStatus installApfPacketFilterInternal(
+        uint32_t cmd_id, const std::vector<uint8_t>& program);
+    std::pair<WifiStatus, std::vector<uint8_t>>
+    readApfPacketFilterDataInternal();
+    std::pair<WifiStatus, StaBackgroundScanCapabilities>
+    getBackgroundScanCapabilitiesInternal();
+    std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+    getValidFrequenciesForBandInternal(V1_0::WifiBand band);
+    WifiStatus startBackgroundScanInternal(
+        uint32_t cmd_id, const StaBackgroundScanParameters& params);
+    WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
+    WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
+    WifiStatus disableLinkLayerStatsCollectionInternal();
+    std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
+    std::pair<WifiStatus, V1_3::StaLinkLayerStats>
+    getLinkLayerStatsInternal_1_3();
+    WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
+                                           int32_t min_rssi);
+    WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
+    std::pair<WifiStatus, StaRoamingCapabilities>
+    getRoamingCapabilitiesInternal();
+    WifiStatus configureRoamingInternal(const StaRoamingConfig& config);
+    WifiStatus setRoamingStateInternal(StaRoamingState state);
+    WifiStatus enableNdOffloadInternal(bool enable);
+    WifiStatus startSendingKeepAlivePacketsInternal(
+        uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
+        uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
+        const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
+    WifiStatus stopSendingKeepAlivePacketsInternal(uint32_t cmd_id);
+    WifiStatus setScanningMacOuiInternal(const std::array<uint8_t, 3>& oui);
+    WifiStatus startDebugPacketFateMonitoringInternal();
+    std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
+    getDebugTxPacketFatesInternal();
+    std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
+    getDebugRxPacketFatesInternal();
+    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+    std::pair<WifiStatus, std::array<uint8_t, 6>>
+    getFactoryMacAddressInternal();
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    bool is_valid_;
+    hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback>
+        event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_STA_IFACE_H_
diff --git a/wifi/1.4/default/wifi_status_util.cpp b/wifi/1.4/default/wifi_status_util.cpp
new file mode 100644
index 0000000..8ceb926
--- /dev/null
+++ b/wifi/1.4/default/wifi_status_util.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+
+std::string legacyErrorToString(legacy_hal::wifi_error error) {
+    switch (error) {
+        case legacy_hal::WIFI_SUCCESS:
+            return "SUCCESS";
+        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+            return "UNINITIALIZED";
+        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+            return "NOT_AVAILABLE";
+        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+            return "NOT_SUPPORTED";
+        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+            return "INVALID_ARGS";
+        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+            return "INVALID_REQUEST_ID";
+        case legacy_hal::WIFI_ERROR_TIMED_OUT:
+            return "TIMED_OUT";
+        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+            return "TOO_MANY_REQUESTS";
+        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+            return "OUT_OF_MEMORY";
+        case legacy_hal::WIFI_ERROR_BUSY:
+            return "BUSY";
+        case legacy_hal::WIFI_ERROR_UNKNOWN:
+            return "UNKNOWN";
+        default:
+            return "UNKNOWN ERROR";
+    }
+}
+
+WifiStatus createWifiStatus(WifiStatusCode code,
+                            const std::string& description) {
+    return {code, description};
+}
+
+WifiStatus createWifiStatus(WifiStatusCode code) {
+    return createWifiStatus(code, "");
+}
+
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
+                                           const std::string& desc) {
+    switch (error) {
+        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+            return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
+
+        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+            return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
+
+        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+            return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
+
+        case legacy_hal::WIFI_ERROR_TIMED_OUT:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+                                    desc + ", timed out");
+
+        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+                                    desc + ", too many requests");
+
+        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+                                    desc + ", out of memory");
+
+        case legacy_hal::WIFI_ERROR_BUSY:
+            return createWifiStatus(WifiStatusCode::ERROR_BUSY);
+
+        case legacy_hal::WIFI_ERROR_NONE:
+            return createWifiStatus(WifiStatusCode::SUCCESS, desc);
+
+        case legacy_hal::WIFI_ERROR_UNKNOWN:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
+
+        default:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+                                    "unknown error");
+    }
+}
+
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
+    return createWifiStatusFromLegacyError(error, "");
+}
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.4/default/wifi_status_util.h b/wifi/1.4/default/wifi_status_util.h
new file mode 100644
index 0000000..3ff58f0
--- /dev/null
+++ b/wifi/1.4/default/wifi_status_util.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 WIFI_STATUS_UTIL_H_
+#define WIFI_STATUS_UTIL_H_
+
+#include <android/hardware/wifi/1.4/IWifi.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_4 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+std::string legacyErrorToString(legacy_hal::wifi_error error);
+WifiStatus createWifiStatus(WifiStatusCode code,
+                            const std::string& description);
+WifiStatus createWifiStatus(WifiStatusCode code);
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
+                                           const std::string& description);
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
+
+}  // namespace implementation
+}  // namespace V1_4
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_STATUS_UTIL_H_
diff --git a/wifi/1.4/types.hal b/wifi/1.4/types.hal
new file mode 100644
index 0000000..4f1d22e
--- /dev/null
+++ b/wifi/1.4/types.hal
@@ -0,0 +1,593 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.4;
+
+import @1.0::MacAddress;
+import @1.0::NanBandIndex;
+import @1.0::NanBandSpecificConfig;
+import @1.0::Rssi;
+import @1.0::RttBw;
+import @1.0::RttConfig;
+import @1.0::RttPeerType;
+import @1.0::RttPreamble;
+import @1.0::RttStatus;
+import @1.0::RttType;
+import @1.0::TimeSpanInPs;
+import @1.0::TimeStampInUs;
+import @1.0::WifiBand;
+import @1.0::WifiChannelInfo;
+import @1.0::WifiChannelInMhz;
+import @1.0::WifiChannelWidthInMhz;
+import @1.0::WifiInformationElement;
+import @1.0::WifiRateNss;
+import @1.0::WifiRatePreamble;
+
+/**
+ * Wifi bands defined in 80211 spec.
+ */
+enum WifiBand : @1.0::WifiBand {
+    /**
+     * 6 GHz.
+     */
+    BAND_6GHZ = 8,
+    /**
+     * 5 GHz no DFS + 6 GHz.
+     */
+    BAND_5GHZ_6GHZ = 10,
+    /**
+     * 2.4 GHz + 5 GHz no DFS + 6 GHz.
+     */
+    BAND_24GHZ_5GHZ_6GHZ = 11,
+    /**
+     * 2.4 GHz + 5 GHz with DFS + 6 GHz.
+     */
+    BAND_24GHZ_5GHZ_WITH_DFS_6GHZ = 15,
+};
+
+/**
+ * The discovery bands supported by NAN.
+ */
+enum NanBandIndex : @1.0::NanBandIndex {
+    /**
+     * Index for 6 GHz band.
+     */
+    NAN_BAND_6GHZ = 2,
+};
+
+/**
+ * Wifi Rate Preamble
+ */
+enum WifiRatePreamble : @1.0::WifiRatePreamble {
+    /**
+     * Preamble type for 11ax
+     */
+    HE = 5,
+};
+
+/**
+ * RTT Measurement Preamble.
+ */
+enum RttPreamble : @1.0::RttPreamble {
+    /**
+     * Preamble type for 11ax
+     */
+    HE = 0x8,
+};
+
+/**
+ * Debug configuration parameters. Many of these allow non-standard-compliant operation and are
+ * not intended for normal operational mode.
+ */
+struct NanDebugConfig {
+    /**
+     * Specification of the lower 2 bytes of the cluster ID. The cluster ID is 50-60-9a-01-00-00 to
+     * 50-60-9a-01-FF-FF. Configuration of the bottom and top values of the range (which defaults to
+     * 0x0000 and 0xFFFF respectively).
+     * Configuration is only used if |validClusterIdVals| is set to true.
+     */
+    bool validClusterIdVals;
+
+    uint16_t clusterIdBottomRangeVal;
+
+    uint16_t clusterIdTopRangeVal;
+
+    /**
+     * NAN management interface address, if specified (|validIntfAddrVal| is true) then overrides any
+     * other configuration (specifically the default randomization configured by
+     * |NanConfigRequest.macAddressRandomizationIntervalSec|).
+     */
+    bool validIntfAddrVal;
+
+    MacAddress intfAddrVal;
+
+    /**
+     * Combination of the 24 bit Organizationally Unique ID (OUI) and the 8 bit OUI Type.
+     * Used if |validOuiVal| is set to true.
+     */
+    bool validOuiVal;
+
+    uint32_t ouiVal;
+
+    /**
+     * Force the Random Factor to the specified value for all transmitted Sync/Discovery beacons.
+     * Used if |validRandomFactorForceVal| is set to true.
+     * NAN Spec: Master Indication Attribute / Random Factor
+     */
+    bool validRandomFactorForceVal;
+
+    uint8_t randomFactorForceVal;
+
+    /**
+     * Forces the hop-count for all transmitted Sync and Discovery Beacons NO matter the real
+     * hop-count being received over the air. Used if the |validHopCountForceVal}| flag is set to
+     * true.
+     * NAN Spec: Cluster Attribute / Anchor Master Information / Hop Count to Anchor Master
+     */
+    bool validHopCountForceVal;
+
+    uint8_t hopCountForceVal;
+
+    /**
+     * Frequency in MHz to of the discovery channel in the specified band. Indexed by |NanBandIndex|.
+     * Used if the |validDiscoveryChannelVal| is set to true.
+     */
+    bool validDiscoveryChannelVal;
+
+    WifiChannelInMhz[3] discoveryChannelMhzVal;
+
+    /**
+     * Specifies whether sync/discovery beacons are transmitted in the specified band. Indexed by
+     * |NanBandIndex|. Used if the |validUseBeaconsInBandVal| is set to true.
+     */
+    bool validUseBeaconsInBandVal;
+
+    bool[3] useBeaconsInBandVal;
+
+    /**
+     * Specifies whether SDF (service discovery frames) are transmitted in the specified band. Indexed
+     * by |NanBandIndex|. Used if the |validUseSdfInBandVal| is set to true.
+     */
+    bool validUseSdfInBandVal;
+
+    bool[3] useSdfInBandVal;
+};
+
+/**
+ * Configuration parameters of NAN: used when enabling and re-configuring a NAN cluster.
+ */
+struct NanConfigRequest {
+    /**
+     * Master preference of this device.
+     * NAN Spec: Master Indication Attribute / Master Preference
+     */
+    uint8_t masterPref;
+
+    /**
+     * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered
+     * for |NanClusterEventType.DISCOVERY_MAC_ADDRESS_CHANGED|.
+     */
+    bool disableDiscoveryAddressChangeIndication;
+
+    /**
+     * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered
+     * for |NanClusterEventType.STARTED_CLUSTER|.
+     */
+    bool disableStartedClusterIndication;
+
+    /**
+     * Controls whether or not the |IWifiNanIfaceEventCallback.eventClusterEvent| will be delivered
+     * for |NanClusterEventType.JOINED_CLUSTER|.
+     */
+    bool disableJoinedClusterIndication;
+
+    /**
+     * Control whether publish service IDs are included in Sync/Discovery beacons.
+     * NAN Spec: Service ID List Attribute
+     */
+    bool includePublishServiceIdsInBeacon;
+
+    /**
+     * If |includePublishServiceIdsInBeacon| is true then specifies the number of publish service IDs
+     * to include in the Sync/Discovery beacons:
+     *  Value = 0: include as many service IDs as will fit into the maximum allowed beacon frame size.
+     *  Value must fit within 7 bits - i.e. <= 127.
+     */
+    uint8_t numberOfPublishServiceIdsInBeacon;
+
+    /**
+     * Control whether subscribe service IDs are included in Sync/Discovery beacons.
+     * Spec: Subscribe Service ID List Attribute
+     */
+    bool includeSubscribeServiceIdsInBeacon;
+
+    /**
+     * If |includeSubscribeServiceIdsInBeacon| is true then specifies the number of subscribe service
+     * IDs to include in the Sync/Discovery beacons:
+     *  Value = 0: include as many service IDs as will fit into the maximum allowed beacon frame size.
+     *  Value must fit within 7 bits - i.e. <= 127.
+     */
+    uint8_t numberOfSubscribeServiceIdsInBeacon;
+
+    /**
+     * Number of samples used to calculate RSSI.
+     */
+    uint16_t rssiWindowSize;
+
+    /**
+     * Specifies the interval in seconds that the NAN management interface MAC address is randomized.
+     * A value of 0 is used to disable the MAC address randomization
+     */
+    uint32_t macAddressRandomizationIntervalSec;
+
+    /**
+     * Additional configuration provided per band: indexed by |NanBandIndex|.
+     */
+    NanBandSpecificConfig[3] bandSpecificConfig;
+};
+
+/**
+ * Enable requests for NAN: start-up configuration |IWifiNanIface.enableRequest|.
+ */
+struct NanEnableRequest {
+    /**
+     * Enable operation in a specific band: indexed by |NanBandIndex|.
+     */
+    bool[3] operateInBand;
+
+    /**
+     * Specify extent of cluster by specifying the max hop count.
+     */
+    uint8_t hopCountMax;
+
+    /**
+     * Configurations of NAN cluster operation. Can also be modified at run-time using
+     * |IWifiNanIface.configRequest|.
+     */
+    NanConfigRequest configParams;
+
+    /**
+     * Non-standard configurations of NAN cluster operation - useful for debugging operations.
+     */
+    NanDebugConfig debugConfigs;
+};
+
+/**
+ * RTT configuration.
+ */
+struct RttConfig {
+    /**
+     * Peer device mac address.
+     */
+    MacAddress addr;
+
+    /**
+     * 1-sided or 2-sided RTT.
+     */
+    RttType type;
+
+    /**
+     * Optional - peer device hint (STA, P2P, AP).
+     */
+    RttPeerType peer;
+
+    /**
+     * Required for STA-AP mode, optional for P2P, NBD etc.
+     */
+    WifiChannelInfo channel;
+
+    /**
+     * Time interval between bursts (units: 100 ms).
+     * Applies to 1-sided and 2-sided RTT multi-burst requests.
+     * Range: 0-31, 0: no preference by initiator (2-sided RTT).
+     */
+    uint32_t burstPeriod;
+
+    /**
+     * Total number of RTT bursts to be executed. It will be
+     * specified in the same way as the parameter "Number of
+     * Burst Exponent" found in the FTM frame format. It
+     * applies to both: 1-sided RTT and 2-sided RTT. Valid
+     * values are 0 to 15 as defined in 802.11mc std.
+     * 0 means single shot
+     * The implication of this parameter on the maximum
+     * number of RTT results is the following:
+     * for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst)
+     * for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1)
+     */
+    uint32_t numBurst;
+
+    /**
+     * Num of frames per burst.
+     * Minimum value = 1, Maximum value = 31
+     * For 2-sided this equals the number of FTM frames
+     * to be attempted in a single burst. This also
+     * equals the number of FTM frames that the
+     * initiator will request that the responder send
+     * in a single frame.
+     */
+    uint32_t numFramesPerBurst;
+
+    /**
+     * Number of retries for a failed RTT frame.
+     * Applies to 1-sided RTT only. Minimum value = 0, Maximum value = 3
+     */
+    uint32_t numRetriesPerRttFrame;
+
+    /**
+     * Following fields are only valid for 2-side RTT.
+     *
+     *
+     * Maximum number of retries that the initiator can
+     * retry an FTMR frame.
+     * Minimum value = 0, Maximum value = 3
+     */
+    uint32_t numRetriesPerFtmr;
+
+    /**
+     * Whether to request location civic info or not.
+     */
+    bool mustRequestLci;
+
+    /**
+     * Whether to request location civic records or not.
+     */
+    bool mustRequestLcr;
+
+    /**
+     * Applies to 1-sided and 2-sided RTT. Valid values will
+     * be 2-11 and 15 as specified by the 802.11mc std for
+     * the FTM parameter burst duration. In a multi-burst
+     * request, if responder overrides with larger value,
+     * the initiator will return failure. In a single-burst
+     * request if responder overrides with larger value,
+     * the initiator will sent TMR_STOP to terminate RTT
+     * at the end of the burst_duration it requested.
+     */
+    uint32_t burstDuration;
+
+    /**
+     * RTT preamble to be used in the RTT frames.
+     */
+    RttPreamble preamble;
+
+    /**
+     * RTT BW to be used in the RTT frames.
+     */
+    RttBw bw;
+};
+
+/**
+ * RTT Capabilities.
+ */
+struct RttCapabilities {
+    /**
+     * if 1-sided rtt data collection is supported.
+     */
+    bool rttOneSidedSupported;
+
+    /**
+     * if ftm rtt data collection is supported.
+     */
+    bool rttFtmSupported;
+
+    /**
+     * if initiator supports LCI request. Applies to 2-sided RTT.
+     */
+    bool lciSupported;
+
+    /**
+     * if initiator supports LCR request. Applies to 2-sided RTT.
+     */
+    bool lcrSupported;
+
+    /**
+     * if 11mc responder mode is supported.
+     */
+    bool responderSupported;
+
+    /**
+     * Bit mask indicates what preamble is supported by initiator.
+     * Combination of |RttPreamble| values.
+     */
+    bitfield<RttPreamble> preambleSupport;
+
+    /**
+     * Bit mask indicates what BW is supported by initiator.
+     * Combination of |RttBw| values.
+     */
+    bitfield<RttBw> bwSupport;
+
+    /**
+     * Draft 11mc spec version supported by chip.
+     * For instance, version 4.0 must be 40 and version 4.3 must be 43 etc.
+     */
+    uint8_t mcVersion;
+};
+
+/**
+ * RTT Responder information
+ */
+struct RttResponder {
+    WifiChannelInfo channel;
+
+    RttPreamble preamble;
+};
+
+/**
+ * Wifi rate info.
+ */
+struct WifiRateInfo {
+    /**
+     * Preamble used for RTT measurements.
+     */
+    WifiRatePreamble preamble;
+
+    /**
+     * Number of spatial streams.
+     */
+    WifiRateNss nss;
+
+    /**
+     * Bandwidth of channel.
+     */
+    WifiChannelWidthInMhz bw;
+
+    /**
+     * OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps.
+     * HT/VHT/HE it would be mcs index.
+     */
+    uint8_t rateMcsIdx;
+
+    /**
+     * Bitrate in units of 100 Kbps.
+     */
+    uint32_t bitRateInKbps;
+};
+
+/**
+ * RTT results.
+ */
+struct RttResult {
+    /**
+     * Peer device mac address.
+     */
+    MacAddress addr;
+
+    /**
+     * Burst number in a multi-burst request.
+     */
+    uint32_t burstNum;
+
+    /**
+     * Total RTT measurement frames attempted.
+     */
+    uint32_t measurementNumber;
+
+    /**
+     * Total successful RTT measurement frames.
+     */
+    uint32_t successNumber;
+
+    /**
+     * Maximum number of "FTM frames per burst" supported by
+     * the responder STA. Applies to 2-sided RTT only.
+     * If reponder overrides with larger value:
+     * - for single-burst request initiator will truncate the
+     * larger value and send a TMR_STOP after receiving as
+     * many frames as originally requested.
+     * - for multi-burst request, initiator will return
+     * failure right away.
+     */
+    uint8_t numberPerBurstPeer;
+
+    /**
+     * Ranging status.
+     */
+    RttStatus status;
+
+    /**
+     * When status == RTT_STATUS_FAIL_BUSY_TRY_LATER,
+     * this will be the time provided by the responder as to
+     * when the request can be tried again. Applies to 2-sided
+     * RTT only. In sec, 1-31sec.
+     */
+    uint8_t retryAfterDuration;
+
+    /**
+     * RTT type.
+     */
+    RttType type;
+
+    /**
+     * Average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB.
+     */
+    Rssi rssi;
+
+    /**
+     * Rssi spread in 0.5 dB steps e.g. 5 implies 2.5 dB spread (optional).
+     */
+    Rssi rssiSpread;
+
+    /**
+     * 1-sided RTT: TX rate of RTT frame.
+     * 2-sided RTT: TX rate of initiator's Ack in response to FTM frame.
+     */
+    WifiRateInfo txRate;
+
+    /**
+     * 1-sided RTT: TX rate of Ack from other side.
+     * 2-sided RTT: TX rate of FTM frame coming from responder.
+     */
+    WifiRateInfo rxRate;
+
+    /**
+     * Round trip time in picoseconds
+     */
+    TimeSpanInPs rtt;
+
+    /**
+     * Rtt standard deviation in picoseconds.
+     */
+    TimeSpanInPs rttSd;
+
+    /**
+     * Difference between max and min rtt times recorded in picoseconds.
+     */
+    TimeSpanInPs rttSpread;
+
+    /**
+     * Distance in mm (optional).
+     */
+    int32_t distanceInMm;
+
+    /**
+     * Standard deviation in mm (optional).
+     */
+    int32_t distanceSdInMm;
+
+    /**
+     * Difference between max and min distance recorded in mm (optional).
+     */
+    int32_t distanceSpreadInMm;
+
+    /**
+     * Time of the measurement (in microseconds since boot).
+     */
+    TimeStampInUs timeStampInUs;
+
+    /**
+     * in ms, actual time taken by the FW to finish one burst
+     * measurement. Applies to 1-sided and 2-sided RTT.
+     */
+    uint32_t burstDurationInMs;
+
+    /**
+     * Number of bursts allowed by the responder. Applies
+     * to 2-sided RTT only.
+     */
+    uint32_t negotiatedBurstNum;
+
+    /**
+     * for 11mc only.
+     */
+    WifiInformationElement lci;
+
+    /**
+     * for 11mc only.
+     */
+    WifiInformationElement lcr;
+};
diff --git a/wifi/1.3/default/OWNERS b/wifi/1.4/vts/OWNERS
similarity index 100%
copy from wifi/1.3/default/OWNERS
copy to wifi/1.4/vts/OWNERS
diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp
new file mode 100644
index 0000000..59a35e0
--- /dev/null
+++ b/wifi/1.4/vts/functional/Android.bp
@@ -0,0 +1,84 @@
+//
+// 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.
+//
+
+// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest.
+cc_test {
+    name: "VtsHalWifiApV1_4TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "wifi_ap_iface_hidl_test.cpp",
+        "wifi_chip_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+// These tests are split out so that they can be conditioned on presence of the
+// "android.hardware.wifi.aware" feature.
+cc_test {
+    name: "VtsHalWifiNanV1_4TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "wifi_nan_iface_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+// These tests are split out so that they can be conditioned on presence of the
+// "android.hardware.wifi.rtt" feature.
+cc_test {
+    name: "VtsHalWifiRttV1_4TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "wifi_rtt_controller_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
new file mode 100644
index 0000000..aff0ef7
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Staache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifiApIface.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_array;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_4::IWifi;
+using ::android::hardware::wifi::V1_4::IWifiApIface;
+
+/**
+ * Fixture to use for all STA Iface HIDL interface tests.
+ */
+class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+   public:
+    virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_ap_iface_ =
+            IWifiApIface::castFrom(getWifiApIface(GetInstanceName()));
+        ASSERT_NE(nullptr, wifi_ap_iface_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+   protected:
+    sp<IWifiApIface> wifi_ap_iface_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * SetMacAddress:
+ * Ensures that calls to set MAC address will return a success status
+ * code.
+ */
+TEST_P(WifiApIfaceHidlTest, SetMacAddress) {
+    const hidl_array<uint8_t, 6> kMac{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}};
+    EXPECT_EQ(WifiStatusCode::SUCCESS,
+              HIDL_INVOKE(wifi_ap_iface_, setMacAddress, kMac).code);
+}
+
+/*
+ * GetFactoryMacAddress:
+ * Ensures that calls to get factory MAC address will retrieve a non-zero MAC
+ * and return a success status code.
+ */
+TEST_P(WifiApIfaceHidlTest, GetFactoryMacAddress) {
+    std::pair<WifiStatus, hidl_array<uint8_t, 6> > status_and_mac =
+        HIDL_INVOKE(wifi_ap_iface_, getFactoryMacAddress);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code);
+    hidl_array<uint8_t, 6> all_zero{};
+    EXPECT_NE(all_zero, status_and_mac.second);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiApIfaceHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
new file mode 100644
index 0000000..be5c3bd
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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 <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/IWifiChipEventCallback.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_string;
+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;
+
+/**
+ * Fixture to use for all Wifi chip HIDL interface tests.
+ */
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
+   public:
+    virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
+        ASSERT_NE(nullptr, wifi_chip_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+    // A simple test implementation of WifiChipEventCallback.
+    class WifiChipEventCallback
+        : public ::testing::VtsHalHidlTargetCallbackBase<WifiChipHidlTest>,
+          public IWifiChipEventCallback {
+       public:
+        WifiChipEventCallback(){};
+
+        virtual ~WifiChipEventCallback() = default;
+
+        Return<void> onChipReconfigured(uint32_t modeId __unused) {
+            return Void();
+        };
+
+        Return<void> onChipReconfigureFailure(
+            const WifiStatus& status __unused) {
+            return Void();
+        };
+
+        Return<void> onIfaceAdded(IfaceType type __unused,
+                                  const hidl_string& name __unused) {
+            return Void();
+        };
+
+        Return<void> onIfaceRemoved(IfaceType type __unused,
+                                    const hidl_string& name __unused) {
+            return Void();
+        };
+
+        Return<void> onDebugRingBufferDataAvailable(
+            const WifiDebugRingBufferStatus& status __unused,
+            const hidl_vec<uint8_t>& data __unused) {
+            return Void();
+        };
+
+        Return<void> onDebugErrorAlert(int32_t errorCode __unused,
+                                       const hidl_vec<uint8_t>& debugData
+                                           __unused) {
+            return Void();
+        };
+
+        Return<void> onRadioModeChange(
+            const hidl_vec<::android::hardware::wifi::V1_2::
+                               IWifiChipEventCallback::RadioModeInfo>&
+                radioModeInfos __unused) {
+            return Void();
+        };
+
+        Return<void> onRadioModeChange_1_4(
+            const hidl_vec<RadioModeInfo>& radioModeInfos __unused) {
+            return Void();
+        };
+    };
+
+   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:
+    std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * 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(WifiChipHidlTest, registerEventCallback_1_4) {
+    sp<WifiChipEventCallback> wifiChipEventCallback =
+        new WifiChipEventCallback();
+    const auto& status = HIDL_INVOKE(wifi_chip_, registerEventCallback_1_4,
+                                     wifiChipEventCallback);
+
+    if (status.code != WifiStatusCode::SUCCESS) {
+        EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
+        return;
+    }
+}
+
+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
new file mode 100644
index 0000000..f6a1147
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -0,0 +1,556 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Nanache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.2/IWifiNanIfaceEventCallback.h>
+#include <android/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifiNanIface.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using namespace ::android::hardware::wifi::V1_0;
+using namespace ::android::hardware::wifi::V1_2;
+using namespace ::android::hardware::wifi::V1_4;
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+#define TIMEOUT_PERIOD 10
+
+android::sp<android::hardware::wifi::V1_4::IWifiNanIface> getWifiNanIface_1_4(
+    const std::string& instance_name) {
+    return android::hardware::wifi::V1_4::IWifiNanIface::castFrom(
+        getWifiNanIface(instance_name));
+}
+
+/**
+ * Fixture to use for all NAN Iface HIDL interface tests.
+ */
+class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+   public:
+    virtual void SetUp() override {
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.aware"))
+            GTEST_SKIP() << "Skipping this test since NAN is not supported.";
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        iwifiNanIface = getWifiNanIface_1_4(GetInstanceName());
+        ASSERT_NE(nullptr, iwifiNanIface.get());
+        ASSERT_EQ(WifiStatusCode::SUCCESS,
+                  HIDL_INVOKE(iwifiNanIface, registerEventCallback_1_2,
+                              new WifiNanIfaceEventCallback(*this))
+                      .code);
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    inline void notify() {
+        std::unique_lock<std::mutex> lock(mtx_);
+        count_++;
+        cv_.notify_one();
+    }
+
+    enum CallbackType {
+        INVALID = -2,
+        ANY_CALLBACK = -1,
+
+        NOTIFY_CAPABILITIES_RESPONSE = 0,
+        NOTIFY_ENABLE_RESPONSE,
+        NOTIFY_CONFIG_RESPONSE,
+        NOTIFY_DISABLE_RESPONSE,
+        NOTIFY_START_PUBLISH_RESPONSE,
+        NOTIFY_STOP_PUBLISH_RESPONSE,
+        NOTIFY_START_SUBSCRIBE_RESPONSE,
+        NOTIFY_STOP_SUBSCRIBE_RESPONSE,
+        NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE,
+        NOTIFY_CREATE_DATA_INTERFACE_RESPONSE,
+        NOTIFY_DELETE_DATA_INTERFACE_RESPONSE,
+        NOTIFY_INITIATE_DATA_PATH_RESPONSE,
+        NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE,
+        NOTIFY_TERMINATE_DATA_PATH_RESPONSE,
+
+        EVENT_CLUSTER_EVENT,
+        EVENT_DISABLED,
+        EVENT_PUBLISH_TERMINATED,
+        EVENT_SUBSCRIBE_TERMINATED,
+        EVENT_MATCH,
+        EVENT_MATCH_EXPIRED,
+        EVENT_FOLLOWUP_RECEIVED,
+        EVENT_TRANSMIT_FOLLOWUP,
+        EVENT_DATA_PATH_REQUEST,
+        EVENT_DATA_PATH_CONFIRM,
+        EVENT_DATA_PATH_TERMINATED,
+        EVENT_DATA_PATH_CONFIRM_1_2,
+        EVENT_DATA_PATH_SCHEDULE_UPDATE
+    };
+
+    /* Test code calls this function to wait for data/event callback */
+    /* Must set callbackType = INVALID before call this function */
+    inline std::cv_status wait(CallbackType waitForCallbackType) {
+        std::unique_lock<std::mutex> lock(mtx_);
+
+        EXPECT_NE(INVALID, waitForCallbackType);  // can't ASSERT in a
+                                                  // non-void-returning method
+
+        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;
+            if (waitForCallbackType != ANY_CALLBACK &&
+                callbackType != INVALID &&
+                callbackType != waitForCallbackType) {
+                count_--;
+            }
+        }
+        count_--;
+        return status;
+    }
+
+    class WifiNanIfaceEventCallback
+        : public ::android::hardware::wifi::V1_2::IWifiNanIfaceEventCallback {
+        WifiNanIfaceHidlTest& parent_;
+
+       public:
+        WifiNanIfaceEventCallback(WifiNanIfaceHidlTest& parent)
+            : parent_(parent){};
+
+        virtual ~WifiNanIfaceEventCallback() = default;
+
+        Return<void> notifyCapabilitiesResponse(
+            uint16_t id, const WifiNanStatus& status,
+            const NanCapabilities& capabilities) override {
+            parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+            parent_.capabilities = capabilities;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyEnableResponse(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_ENABLE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyConfigResponse(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_CONFIG_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyDisableResponse(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_DISABLE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyStartPublishResponse(uint16_t id,
+                                                const WifiNanStatus& status,
+                                                uint8_t sessionId) override {
+            parent_.callbackType = NOTIFY_START_PUBLISH_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+            parent_.sessionId = sessionId;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyStopPublishResponse(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_STOP_PUBLISH_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyStartSubscribeResponse(uint16_t id,
+                                                  const WifiNanStatus& status,
+                                                  uint8_t sessionId) override {
+            parent_.callbackType = NOTIFY_START_SUBSCRIBE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+            parent_.sessionId = sessionId;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyStopSubscribeResponse(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyTransmitFollowupResponse(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyCreateDataInterfaceResponse(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyDeleteDataInterfaceResponse(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyInitiateDataPathResponse(
+            uint16_t id, const WifiNanStatus& status,
+            uint32_t ndpInstanceId) override {
+            parent_.callbackType = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+            parent_.ndpInstanceId = ndpInstanceId;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyRespondToDataPathIndicationResponse(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType =
+                NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyTerminateDataPathResponse(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventClusterEvent(
+            const NanClusterEventInd& event) override {
+            parent_.callbackType = EVENT_CLUSTER_EVENT;
+
+            parent_.nanClusterEventInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDisabled(const WifiNanStatus& status) override {
+            parent_.callbackType = EVENT_DISABLED;
+
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventPublishTerminated(
+            uint8_t sessionId, const WifiNanStatus& status) override {
+            parent_.callbackType = EVENT_PUBLISH_TERMINATED;
+
+            parent_.sessionId = sessionId;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventSubscribeTerminated(
+            uint8_t sessionId, const WifiNanStatus& status) override {
+            parent_.callbackType = EVENT_SUBSCRIBE_TERMINATED;
+
+            parent_.sessionId = sessionId;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventMatch(const NanMatchInd& event) override {
+            parent_.callbackType = EVENT_MATCH;
+
+            parent_.nanMatchInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventMatchExpired(uint8_t discoverySessionId,
+                                       uint32_t peerId) override {
+            parent_.callbackType = EVENT_MATCH_EXPIRED;
+
+            parent_.sessionId = discoverySessionId;
+            parent_.peerId = peerId;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventFollowupReceived(
+            const NanFollowupReceivedInd& event) override {
+            parent_.callbackType = EVENT_FOLLOWUP_RECEIVED;
+
+            parent_.nanFollowupReceivedInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventTransmitFollowup(
+            uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = EVENT_TRANSMIT_FOLLOWUP;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathRequest(
+            const NanDataPathRequestInd& event) override {
+            parent_.callbackType = EVENT_DATA_PATH_REQUEST;
+
+            parent_.nanDataPathRequestInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathConfirm(
+            const ::android::hardware::wifi::V1_0::NanDataPathConfirmInd& event)
+            override {
+            parent_.callbackType = EVENT_DATA_PATH_CONFIRM;
+
+            parent_.nanDataPathConfirmInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathTerminated(uint32_t ndpInstanceId) override {
+            parent_.callbackType = EVENT_DATA_PATH_TERMINATED;
+
+            parent_.ndpInstanceId = ndpInstanceId;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathConfirm_1_2(
+            const ::android::hardware::wifi::V1_2::NanDataPathConfirmInd& event)
+            override {
+            parent_.callbackType = EVENT_DATA_PATH_CONFIRM_1_2;
+
+            parent_.nanDataPathConfirmInd_1_2 = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathScheduleUpdate(
+            const NanDataPathScheduleUpdateInd& event) override {
+            parent_.callbackType = EVENT_DATA_PATH_SCHEDULE_UPDATE;
+
+            parent_.nanDataPathScheduleUpdateInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+    };
+
+   private:
+    // synchronization objects
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int count_ = 0;
+
+   protected:
+    android::sp<::android::hardware::wifi::V1_4::IWifiNanIface> iwifiNanIface;
+
+    // Data from IWifiNanIfaceEventCallback callbacks: this is the collection of
+    // all arguments to all callbacks. They are set by the callback
+    // (notifications or events) and can be retrieved by tests.
+    CallbackType callbackType;
+    uint16_t id;
+    WifiNanStatus status;
+    NanCapabilities capabilities;
+    uint8_t sessionId;
+    uint32_t ndpInstanceId;
+    NanClusterEventInd nanClusterEventInd;
+    NanMatchInd nanMatchInd;
+    uint32_t peerId;
+    NanFollowupReceivedInd nanFollowupReceivedInd;
+    NanDataPathRequestInd nanDataPathRequestInd;
+    ::android::hardware::wifi::V1_0::NanDataPathConfirmInd
+        nanDataPathConfirmInd;
+    ::android::hardware::wifi::V1_2::NanDataPathConfirmInd
+        nanDataPathConfirmInd_1_2;
+    NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd;
+
+    std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * Create:
+ * Ensures that an instance of the IWifiNanIface proxy object is
+ * successfully created.
+ */
+TEST_P(WifiNanIfaceHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
+}
+
+/*
+ * enableRequest_1_4InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_4InvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callbackType = INVALID;
+    ::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {};
+    NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    ASSERT_EQ(WifiStatusCode::SUCCESS,
+              HIDL_INVOKE(iwifiNanIface, enableRequest_1_4, inputCmdId,
+                          nanEnableRequest, nanConfigRequestSupp)
+                  .code);
+    // wait for a callback
+    ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
+    ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
+    ASSERT_EQ(id, inputCmdId);
+    ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+}
+
+/*
+ * enableRequest_1_4ShimInvalidArgs: validate that fails with invalid arguments
+ * to the shim
+ */
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_4ShimInvalidArgs) {
+    uint16_t inputCmdId = 10;
+    ::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {};
+    nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon =
+        128;  // must be <= 127
+    NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
+              HIDL_INVOKE(iwifiNanIface, enableRequest_1_4, inputCmdId,
+                          nanEnableRequest, nanConfigRequestSupp)
+                  .code);
+}
+
+/*
+ * configRequest_1_4InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_4InvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callbackType = INVALID;
+    ::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {};
+    NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    ASSERT_EQ(WifiStatusCode::SUCCESS,
+              HIDL_INVOKE(iwifiNanIface, configRequest_1_4, inputCmdId,
+                          nanConfigRequest, nanConfigRequestSupp)
+                  .code);
+    // wait for a callback
+    ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
+    ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType);
+    ASSERT_EQ(id, inputCmdId);
+    ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+}
+
+/*
+ * configRequest_1_4ShimInvalidArgs: validate that fails with invalid arguments
+ * to the shim
+ */
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_4ShimInvalidArgs) {
+    uint16_t inputCmdId = 10;
+    ::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {};
+    nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128;  // must be <= 127
+    NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS,
+              HIDL_INVOKE(iwifiNanIface, configRequest_1_4, inputCmdId,
+                          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..a099c8a
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+
+#undef NAN  // NAN is defined in bionic/libc/include/math.h:38
+
+#include <VtsCoreUtil.h>
+#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 {
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.rtt"))
+            GTEST_SKIP() << "Skipping this test since RTT is not supported.";
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_rtt_controller_ = getWifiRttController();
+        ASSERT_NE(nullptr, wifi_rtt_controller_.get());
+
+        // Check RTT support before we run the test.
+        std::pair<WifiStatus, RttCapabilities> status_and_caps;
+        status_and_caps =
+            HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_4);
+        if (status_and_caps.first.code == WifiStatusCode::ERROR_NOT_SUPPORTED) {
+            GTEST_SKIP() << "Skipping this test since RTT is not supported.";
+        }
+    }
+
+    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::pair<WifiStatus, RttCapabilities> status_and_caps;
+
+    // Get the Capabilities
+    status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_4);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+    // Get the highest support preamble
+    int preamble = 1;
+    status_and_caps.second.preambleSupport >>= 1;
+    while (status_and_caps.second.preambleSupport != 0) {
+        status_and_caps.second.preambleSupport >>= 1;
+        preamble <<= 1;
+    }
+    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::AP;
+    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)preamble;
+    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 = 5660;
+    channelInfo.centerFreq0 = 5660;
+    channelInfo.centerFreq1 = 0;
+
+    // Get the responder first
+    status_and_info = HIDL_INVOKE(wifi_rtt_controller_, getResponderInfo_1_4);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_info.first.code);
+
+    // Invoke the call
+    const auto& status =
+        HIDL_INVOKE(wifi_rtt_controller_, enableResponder_1_4, cmdId,
+                    channelInfo, 10, status_and_info.second);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiRttControllerHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_4::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/hostapd/1.0/vts/functional/Android.bp b/wifi/hostapd/1.0/vts/functional/Android.bp
index 0356696..2a35f15 100644
--- a/wifi/hostapd/1.0/vts/functional/Android.bp
+++ b/wifi/hostapd/1.0/vts/functional/Android.bp
@@ -36,7 +36,6 @@
     name: "VtsHalWifiHostapdV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiHostapdV1_0TargetTest.cpp",
         "hostapd_hidl_test.cpp",
     ],
     static_libs: [
diff --git a/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp b/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp
deleted file mode 100644
index 4b62b15..0000000
--- a/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <VtsHalHidlTargetTestEnvBase.h>
-
-// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
-// updated.
-::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
index 6058fd2..3ddb2b3 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 
 #include <android/hidl/manager/1.0/IServiceManager.h>
@@ -48,16 +47,24 @@
 // Helper function to initialize the driver and firmware to AP mode
 // using the vendor HAL HIDL interface.
 void initilializeDriverAndFirmware(const std::string& wifi_instance_name) {
-    sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
-    ChipModeId mode_id;
-    EXPECT_TRUE(configureChipToSupportIfaceType(
-        wifi_chip, ::android::hardware::wifi::V1_0::IfaceType::AP, &mode_id));
+    if (getWifi(wifi_instance_name) != nullptr) {
+        sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
+        ChipModeId mode_id;
+        EXPECT_TRUE(configureChipToSupportIfaceType(
+            wifi_chip, ::android::hardware::wifi::V1_0::IfaceType::AP, &mode_id));
+    } else {
+        LOG(WARNING) << __func__ << ": Vendor HAL not supported";
+    }
 }
 
 // Helper function to deinitialize the driver and firmware
 // using the vendor HAL HIDL interface.
 void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) {
-    stopWifi(wifi_instance_name);
+    if (getWifi(wifi_instance_name) != nullptr) {
+        stopWifi(wifi_instance_name);
+    } else {
+        LOG(WARNING) << __func__ << ": Vendor HAL not supported";
+    }
 }
 }  // namespace
 
@@ -148,4 +155,4 @@
     sp<::android::hardware::wifi::hostapd::V1_1::IHostapd> hostapd_1_1 =
         ::android::hardware::wifi::hostapd::V1_1::IHostapd::castFrom(hostapd);
     return hostapd_1_1.get() != nullptr;
-}
\ No newline at end of file
+}
diff --git a/wifi/hostapd/1.1/vts/functional/Android.bp b/wifi/hostapd/1.1/vts/functional/Android.bp
index 675b68e..291eceb 100644
--- a/wifi/hostapd/1.1/vts/functional/Android.bp
+++ b/wifi/hostapd/1.1/vts/functional/Android.bp
@@ -18,7 +18,6 @@
     name: "VtsHalWifiHostapdV1_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiHostapdV1_1TargetTest.cpp",
         "hostapd_hidl_test.cpp",
     ],
     static_libs: [
diff --git a/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp b/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp
deleted file mode 100644
index 7e0f3cd..0000000
--- a/wifi/hostapd/1.1/vts/functional/VtsHalWifiHostapdV1_1TargetTest.cpp
+++ /dev/null
@@ -1,21 +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 <VtsHalHidlTargetTestEnvBase.h>
-
-// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
-// updated.
-::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
\ No newline at end of file
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
index 1804d8c..345cf31 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
@@ -233,7 +233,11 @@
 TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                               getIfaceParamsWithoutAcs(), getPskNwParams());
-    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    // FAILURE_UNKNOWN is used by higher versions to indicate this API is no
+    // longer supported (replaced by an upgraded API)
+    if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) {
+        EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    }
 }
 
 /**
@@ -243,7 +247,11 @@
 TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                               getIfaceParamsWithoutAcs(), getOpenNwParams());
-    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    // FAILURE_UNKNOWN is used by higher versions to indicate this API is no
+    // longer supported (replaced by an upgraded API)
+    if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) {
+        EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    }
 }
 
 /**
@@ -269,10 +277,14 @@
 TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_1,
                               getIfaceParamsWithoutAcs(), getPskNwParams());
-    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
-    status =
-        HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
-    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    // FAILURE_UNKNOWN is used by higher versions to indicate this API is no
+    // longer supported (replaced by an upgraded API)
+    if (status.code != HostapdStatusCode::FAILURE_UNKNOWN) {
+        EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+        status =
+            HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+        EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    }
 }
 
 /**
diff --git a/wifi/hostapd/1.2/Android.bp b/wifi/hostapd/1.2/Android.bp
new file mode 100644
index 0000000..9b26ece
--- /dev/null
+++ b/wifi/hostapd/1.2/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi.hostapd@1.2",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IHostapd.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi.hostapd@1.0",
+        "android.hardware.wifi.hostapd@1.1",
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal
new file mode 100644
index 0000000..0869da0
--- /dev/null
+++ b/wifi/hostapd/1.2/IHostapd.hal
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.hostapd@1.2;
+
+import @1.0::IHostapd.EncryptionType;
+import @1.0::IHostapd.NetworkParams;
+import @1.1::IHostapd;
+import HostapdStatus;
+import MacAddress;
+import Ieee80211ReasonCode;
+import DebugLevel;
+
+/**
+ * Top-level object for managing SoftAPs.
+ */
+interface IHostapd extends @1.1::IHostapd {
+    /** Possible Security types. */
+    enum EncryptionType : @1.0::IHostapd.EncryptionType {
+        WPA3_SAE_TRANSITION,
+        WPA3_SAE,
+    };
+
+    /**
+     * Band bitmMask to use for the SoftAp operations.
+     * A combinatoin of these bits are used to identify the allowed bands
+     * to start the softAp
+     */
+    enum BandMask : uint32_t {
+        /**
+         * 2.4 GHz band.
+         */
+        BAND_2_GHZ = 1 << 0,
+        /**
+         * 5 GHz band.
+         */
+        BAND_5_GHZ = 1 << 1,
+        /**
+         * 6 GHz band.
+         */
+        BAND_6_GHZ = 1 << 2,
+    };
+
+    /**
+     * Parameters to control the HW mode for the interface.
+     */
+    struct HwModeParams {
+        /**
+         * Whether IEEE 802.11ax (HE) is enabled or not.
+         * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
+         * used with HE.
+         */
+        bool enable80211AX;
+
+        /**
+         * Whether 6GHz band enabled or not on softAp.
+         * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
+         * used.
+         */
+        bool enable6GhzBand;
+
+        /**
+         * Whether HE single user beamformer in enabled or not on softAp.
+         * Note: this is only applicable if 802.11ax is supported for softAp
+         */
+        bool enableHeSingleUserBeamformer;
+
+        /**
+         * Whether HE single user beamformee is enabled or not on softAp.
+         * Note: this is only applicable if 802.11ax is supported for softAp
+         */
+        bool enableHeSingleUserBeamformee;
+
+        /**
+         * Whether HE multiple user beamformer is enabled or not on softAp.
+         * Note: this is only applicable if 802.11ax is supported for softAp
+         */
+        bool enableHeMultiUserBeamformer;
+
+        /**
+         * Whether HE Target Wait Time (TWT) is enabled or not on softAp.
+         * Note: this is only applicable if 802.11ax is supported for softAp
+         */
+        bool enableHeTargetWakeTime;
+    };
+
+    /**
+     * Parameters to specify the channel frequency range for ACS.
+     */
+    struct AcsFrequencyRange {
+        /**
+         * Channel Frequency (in MHz) at the start of the range.
+         */
+        uint32_t start;
+
+        /**
+         * Channel Frequency (in MHz) at the end of the range.
+         */
+        uint32_t end;
+    };
+
+    /**
+     * Parameters to control the channel selection for the interface.
+     */
+    struct ChannelParams {
+        /**
+         * Band to use for the SoftAp operations.
+         */
+        bitfield<BandMask> bandMask;
+
+        /**
+         * This option can be used to specify the channel frequencies (in MHz) selected by ACS.
+         * If this is an empty list, all channels allowed in selected HW mode
+         * are specified implicitly.
+         * Note: channels may be overridden by firmware.
+         * Note: this option is ignored if ACS is disabled.
+         */
+        vec<AcsFrequencyRange> acsChannelFreqRangesMhz;
+    };
+
+    /**
+     * Parameters to use for setting up the access point interface.
+     */
+    struct IfaceParams {
+        /**
+         * Baseline information as defined in HAL 1.1.
+         */
+        @1.1::IHostapd.IfaceParams V1_1;
+
+        /**
+         * Additional Hw mode params for the interface
+         */
+        HwModeParams hwModeParams;
+
+        /**
+         * Additional Channel params for the interface
+         */
+        ChannelParams channelParams;
+    };
+
+    /**
+     * Parameters to use for setting up the access point network.
+     */
+    struct NetworkParams {
+        /**
+         * Baseline information as defined in HAL 1.0.
+         */
+        @1.0::IHostapd.NetworkParams V1_0;
+        /** Key management mask for the replace V1_0.encryptionType. */
+        EncryptionType encryptionType;
+        /**
+         * Passphrase for WPA3_SAE network, WPA3_SAE_TRANSITION and
+         * WPA2_PSK. Replaces @1.0::IHostapd.NetworkParams.pskPassphrase.
+         */
+        string passphrase;
+    };
+
+
+    /**
+     * Adds a new access point for hostapd to control.
+     *
+     * This should trigger the setup of an access point with the specified
+     * interface and network params.
+     *
+     * @param ifaceParams AccessPoint Params for the access point.
+     * @param nwParams Network Params for the access point.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |HostapdStatusCode.SUCCESS|,
+     *         |HostapdStatusCode.FAILURE_ARGS_INVALID|,
+     *         |HostapdStatusCode.FAILURE_UNKNOWN|,
+     *         |HostapdStatusCode.FAILURE_IFACE_EXISTS|
+     */
+    addAccessPoint_1_2(IfaceParams ifaceParams, NetworkParams nwParams)
+        generates (HostapdStatus status);
+
+    /**
+     * force one of the hotspot clients disconnect..
+     *
+     * @param ifaceName Name of the interface.
+     * @param clientAddress Mac Address of the hotspot client.
+     * @param reasonCode One of disconnect reason code which defined by 802.11.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |HostapdStatusCode.SUCCESS|,
+     *         |HostapdStatusCode.FAILURE_IFACE_UNKNOWN|
+     *         |HostapdStatusCode.FAILURE_CLIENT_UNKNOWN|
+     */
+    forceClientDisconnect(string ifaceName, MacAddress clientAddress,
+        Ieee80211ReasonCode reasonCode) generates (HostapdStatus status);
+
+    /**
+     * Set debug parameters for the hostapd.
+     *
+     * @param level Debug logging level for the hostapd.
+     *        (one of |DebugLevel| values).
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |HostapdStatusCode.SUCCESS|,
+     *         |HostapdStatusCode.FAILURE_UNKNOWN|
+     */
+    setDebugParams(DebugLevel level)
+        generates (HostapdStatus status);
+};
diff --git a/wifi/hostapd/1.2/types.hal b/wifi/hostapd/1.2/types.hal
new file mode 100644
index 0000000..9c187fa
--- /dev/null
+++ b/wifi/hostapd/1.2/types.hal
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.hostapd@1.2;
+
+import @1.0::HostapdStatusCode;
+
+/**
+ * Enum values indicating the status of any hostapd operation.
+ */
+enum HostapdStatusCode : @1.0::HostapdStatusCode {
+    /**
+     * Failure because unknown the client.
+     */
+    FAILURE_CLIENT_UNKNOWN,
+};
+
+/**
+ * Enum values indicating the reason code for disconnect packet.
+ * Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45).
+ */
+enum Ieee80211ReasonCode : uint16_t {
+    WLAN_REASON_UNSPECIFIED = 1,
+    WLAN_REASON_PREV_AUTH_NOT_VALID = 2,
+    WLAN_REASON_DISASSOC_AP_BUSY = 5,
+};
+
+/**
+ * Mac Address type. 6 octets representing physical address of a device.
+ */
+typedef uint8_t[6] MacAddress;
+
+/**
+ * Generic structure to return the status of any hostapd operation.
+ */
+struct HostapdStatus {
+    HostapdStatusCode code;
+
+    /**
+     * A vendor-specific error message to provide more information beyond the
+     * status code.
+     * This must be used for debugging purposes only.
+     */
+    string debugMessage;
+};
+
+/**
+ * Debug levels for the hostapd.
+ * Only log messages with a level greater than the set level
+ * (via |setDebugParams|) will be logged.
+ */
+enum DebugLevel : uint32_t {
+    EXCESSIVE = 0,
+    MSGDUMP = 1,
+    DEBUG = 2,
+    INFO = 3,
+    WARNING = 4,
+    ERROR = 5
+};
diff --git a/wifi/1.3/default/OWNERS b/wifi/hostapd/1.2/vts/OWNERS
similarity index 100%
copy from wifi/1.3/default/OWNERS
copy to wifi/hostapd/1.2/vts/OWNERS
diff --git a/wifi/hostapd/1.2/vts/functional/Android.bp b/wifi/hostapd/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..cec1782
--- /dev/null
+++ b/wifi/hostapd/1.2/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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: "VtsHalWifiHostapdV1_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "hostapd_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiHostapdV1_0TargetTestUtil",
+        "android.hardware.wifi.hostapd@1.0",
+        "android.hardware.wifi.hostapd@1.1",
+	"android.hardware.wifi.hostapd@1.2",
+        "android.hardware.wifi@1.0",
+        "libgmock",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+    test_suites: ["general-tests", "vts"],
+}
+
diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
new file mode 100644
index 0000000..2715891
--- /dev/null
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -0,0 +1,424 @@
+/*
+ * 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 <VtsCoreUtil.h>
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/hostapd/1.2/IHostapd.h>
+
+#include "hostapd_hidl_call_util.h"
+#include "hostapd_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::hostapd::V1_2::DebugLevel;
+using ::android::hardware::wifi::hostapd::V1_2::HostapdStatusCode;
+using ::android::hardware::wifi::hostapd::V1_2::Ieee80211ReasonCode;
+using ::android::hardware::wifi::hostapd::V1_2::IHostapd;
+using ::android::hardware::wifi::V1_0::IWifi;
+
+namespace {
+constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1',
+                                     '2', '3', '4', '5'};
+constexpr char kNwPassphrase[] = "test12345";
+constexpr char kInvalidMaxPskNwPassphrase[] =
+    "0123456789012345678901234567890123456789012345678901234567890123456789";
+constexpr char kInvalidMinPskNwPassphrase[] = "test";
+constexpr int kIfaceChannel = 6;
+constexpr int kIfaceInvalidChannel = 567;
+constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0};
+constexpr Ieee80211ReasonCode kTestDisconnectReasonCode =
+    Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED;
+}  // namespace
+
+class HostapdHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+   public:
+    virtual void SetUp() override {
+        wifi_instance_name_ = std::get<0>(GetParam());
+        hostapd_instance_name_ = std::get<1>(GetParam());
+        stopSupplicantIfNeeded(wifi_instance_name_);
+        startHostapdAndWaitForHidlService(wifi_instance_name_,
+                                          hostapd_instance_name_);
+        hostapd_ = IHostapd::getService(hostapd_instance_name_);
+        ASSERT_NE(hostapd_.get(), nullptr);
+        isAcsSupport_ = testing::checkSubstringInCommandOutput(
+            "/system/bin/cmd wifi get-softap-supported-features",
+            "wifi_softap_acs_supported");
+        isWpa3SaeSupport_ = testing::checkSubstringInCommandOutput(
+            "/system/bin/cmd wifi get-softap-supported-features",
+            "wifi_softap_wpa3_sae_supported");
+    }
+
+    virtual void TearDown() override { stopHostapd(hostapd_instance_name_); }
+
+   protected:
+    bool isWpa3SaeSupport_ = false;
+    bool isAcsSupport_ = false;
+    std::string getPrimaryWlanIfaceName() {
+        std::array<char, PROPERTY_VALUE_MAX> buffer;
+        auto res = property_get("ro.vendor.wifi.sap.interface", buffer.data(),
+                                nullptr);
+        if (res > 0) return buffer.data();
+        property_get("wifi.interface", buffer.data(), "wlan0");
+        return buffer.data();
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithoutAcs() {
+        ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams
+            iface_params;
+        ::android::hardware::wifi::hostapd::V1_1::IHostapd::IfaceParams
+            iface_params_1_1;
+        IHostapd::IfaceParams iface_params_1_2;
+
+        iface_params.ifaceName = getPrimaryWlanIfaceName();
+        iface_params.hwModeParams.enable80211N = true;
+        iface_params.hwModeParams.enable80211AC = false;
+        iface_params.channelParams.enableAcs = false;
+        iface_params.channelParams.acsShouldExcludeDfs = false;
+        iface_params.channelParams.channel = kIfaceChannel;
+        iface_params_1_1.V1_0 = iface_params;
+        iface_params_1_2.V1_1 = iface_params_1_1;
+        // Newly added attributes in V1_2
+        iface_params_1_2.hwModeParams.enable80211AX = false;
+        iface_params_1_2.hwModeParams.enable6GhzBand = false;
+        iface_params_1_2.channelParams.bandMask = 0;
+        iface_params_1_2.channelParams.bandMask |=
+            IHostapd::BandMask::BAND_2_GHZ;
+        return iface_params_1_2;
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithAcs() {
+        // First get the settings for WithoutAcs and then make changes
+        IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+        iface_params_1_2.V1_1.V1_0.channelParams.enableAcs = true;
+        iface_params_1_2.V1_1.V1_0.channelParams.acsShouldExcludeDfs = true;
+        iface_params_1_2.V1_1.V1_0.channelParams.channel = 0;
+        iface_params_1_2.channelParams.bandMask |=
+            IHostapd::BandMask::BAND_5_GHZ;
+
+        return iface_params_1_2;
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithAcsAndFreqRange() {
+        IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs();
+        ::android::hardware::wifi::hostapd::V1_2::IHostapd::AcsFrequencyRange
+            acsFrequencyRange;
+        acsFrequencyRange.start = 2412;
+        acsFrequencyRange.end = 2462;
+        std::vector<::android::hardware::wifi::hostapd::V1_2::IHostapd::
+                        AcsFrequencyRange>
+            vec_acsFrequencyRange;
+        vec_acsFrequencyRange.push_back(acsFrequencyRange);
+        iface_params_1_2.channelParams.acsChannelFreqRangesMhz =
+            vec_acsFrequencyRange;
+        return iface_params_1_2;
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidFreqRange() {
+        IHostapd::IfaceParams iface_params_1_2 =
+            getIfaceParamsWithAcsAndFreqRange();
+        iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].start = 222;
+        iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].end = 999;
+        return iface_params_1_2;
+    }
+
+    IHostapd::NetworkParams getOpenNwParams() {
+        IHostapd::NetworkParams nw_params_1_2;
+        ::android::hardware::wifi::hostapd::V1_0::IHostapd::NetworkParams
+            nw_params_1_0;
+        nw_params_1_0.ssid =
+            std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+        nw_params_1_0.isHidden = false;
+        nw_params_1_2.V1_0 = nw_params_1_0;
+        nw_params_1_2.encryptionType = IHostapd::EncryptionType::NONE;
+        return nw_params_1_2;
+    }
+
+    IHostapd::NetworkParams getPskNwParams() {
+        IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+        nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA2;
+        nw_params_1_2.passphrase = kNwPassphrase;
+        return nw_params_1_2;
+    }
+
+    IHostapd::NetworkParams getInvalidPskNwParams() {
+        IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+        nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA2;
+        nw_params_1_2.passphrase = kInvalidMaxPskNwPassphrase;
+
+        return nw_params_1_2;
+    }
+
+    IHostapd::NetworkParams getSaeTransitionNwParams() {
+        IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+        nw_params_1_2.encryptionType =
+            IHostapd::EncryptionType::WPA3_SAE_TRANSITION;
+        nw_params_1_2.passphrase = kNwPassphrase;
+        return nw_params_1_2;
+    }
+
+    IHostapd::NetworkParams getInvalidSaeTransitionNwParams() {
+        IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+        nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA2;
+        nw_params_1_2.passphrase = kInvalidMinPskNwPassphrase;
+        return nw_params_1_2;
+    }
+
+    IHostapd::NetworkParams getSaeNwParams() {
+        IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+        nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA3_SAE;
+        nw_params_1_2.passphrase = kNwPassphrase;
+        return nw_params_1_2;
+    }
+
+    IHostapd::NetworkParams getInvalidSaeNwParams() {
+        IHostapd::NetworkParams nw_params_1_2 = getOpenNwParams();
+        nw_params_1_2.encryptionType = IHostapd::EncryptionType::WPA3_SAE;
+        nw_params_1_2.passphrase = "";
+        return nw_params_1_2;
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() {
+        IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+        iface_params_1_2.V1_1.V1_0.channelParams.channel = kIfaceInvalidChannel;
+        return iface_params_1_2;
+    }
+
+    // IHostapd object used for all tests in this fixture.
+    sp<IHostapd> hostapd_;
+    std::string wifi_instance_name_;
+    std::string hostapd_instance_name_;
+};
+
+/**
+ * Adds an access point with PSK network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) {
+    if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithAcs(), getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config, ACS enabled & frequency Range.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndFreqRange) {
+    if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithAcsAndFreqRange(), getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid channel range.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidFreqRange) {
+    if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithAcsAndInvalidFreqRange(),
+                              getPskNwParams());
+    EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) {
+    if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithAcs(), getOpenNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithoutAcs(), getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithoutAcs(), getOpenNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with SAE Transition network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddSaeTransitionAccessPointWithoutAcs) {
+    if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+                    getSaeTransitionNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with SAE network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddSAEAccessPointWithoutAcs) {
+    if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithoutAcs(), getSaeNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS enabled.
+ * Access point creation & removal should pass.
+ */
+TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) {
+    if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
+    auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                                  getIfaceParamsWithAcs(), getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+    auto status =
+        HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+    EXPECT_EQ(
+        android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
+        status.code);
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS disabled.
+ * Access point creation & removal should pass.
+ */
+TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
+    auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                                  getIfaceParamsWithoutAcs(), getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+    auto status =
+        HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+    EXPECT_EQ(
+        android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
+        status.code);
+}
+
+/**
+ * Adds an access point with invalid channel.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithInvalidChannel(), getPskNwParams());
+    EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid PSK network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+                    getInvalidPskNwParams());
+    EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid SAE transition network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidSaeTransitionAccessPointWithoutAcs) {
+    if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+                    getInvalidSaeTransitionNwParams());
+    EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid SAE network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidSaeAccessPointWithoutAcs) {
+    if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+                    getInvalidSaeNwParams());
+    EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * forceClientDisconnect should return FAILURE_IFACE_UNKNOWN
+ * when hotspot interface doesn't init..
+ */
+TEST_P(HostapdHidlTest, DisconnectClientWhenIfaceNotAvailable) {
+    auto status =
+        HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(),
+                    kTestZeroMacAddr, kTestDisconnectReasonCode);
+    EXPECT_EQ(HostapdStatusCode::FAILURE_IFACE_UNKNOWN, status.code);
+}
+
+/**
+ * forceClientDisconnect should return FAILURE_CLIENT_UNKNOWN
+ * when hotspot interface available.
+ */
+TEST_P(HostapdHidlTest, DisconnectClientWhenIfacAvailable) {
+    auto status_1_2 =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+                    getOpenNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+
+    status_1_2 =
+        HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(),
+                    kTestZeroMacAddr, kTestDisconnectReasonCode);
+    EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code);
+}
+
+/*
+ * SetDebugParams
+ */
+TEST_P(HostapdHidlTest, SetDebugParams) {
+    auto status = HIDL_INVOKE(hostapd_, setDebugParams, DebugLevel::EXCESSIVE);
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, HostapdHidlTest,
+    testing::Combine(
+        testing::ValuesIn(
+            android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::hostapd::V1_2::IHostapd::descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index 6ebe5d0..6f282bb 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -36,7 +36,6 @@
     name: "VtsHalWifiSupplicantV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiSupplicantV1_0TargetTest.cpp",
         "supplicant_hidl_test.cpp",
         "supplicant_sta_iface_hidl_test.cpp",
         "supplicant_sta_network_hidl_test.cpp",
@@ -46,6 +45,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/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
index a132707..01840e2 100644
--- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
@@ -17,10 +17,6 @@
 #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;
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
deleted file mode 100644
index f582cc1..0000000
--- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "supplicant_hidl_test_utils.h"
-
-// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
-// updated.
-WifiSupplicantHidlEnvironment* gEnv = nullptr;
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index d47e42f..addf066 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 #include <cutils/properties.h>
 
@@ -50,23 +49,37 @@
 using ::android::wifi_system::InterfaceTool;
 using ::android::wifi_system::SupplicantManager;
 
-extern WifiSupplicantHidlEnvironment* gEnv;
-
 namespace {
 
 // Helper function to initialize the driver and firmware to STA mode
 // using the vendor HAL HIDL interface.
 void initilializeDriverAndFirmware(const std::string& wifi_instance_name) {
-    sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
-    ChipModeId mode_id;
-    EXPECT_TRUE(configureChipToSupportIfaceType(
-        wifi_chip, ::android::hardware::wifi::V1_0::IfaceType::STA, &mode_id));
+    // Skip if wifi instance is not set.
+    if (wifi_instance_name == "") {
+        return;
+    }
+    if (getWifi(wifi_instance_name) != nullptr) {
+        sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
+        ChipModeId mode_id;
+        EXPECT_TRUE(configureChipToSupportIfaceType(
+            wifi_chip, ::android::hardware::wifi::V1_0::IfaceType::STA, &mode_id));
+    } else {
+        LOG(WARNING) << __func__ << ": Vendor HAL not supported";
+    }
 }
 
 // Helper function to deinitialize the driver and firmware
 // using the vendor HAL HIDL interface.
 void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) {
-    stopWifi(wifi_instance_name);
+    // Skip if wifi instance is not set.
+    if (wifi_instance_name == "") {
+        return;
+    }
+    if (getWifi(wifi_instance_name) != nullptr) {
+        stopWifi(wifi_instance_name);
+    } else {
+        LOG(WARNING) << __func__ << ": Vendor HAL not supported";
+    }
 }
 
 // Helper function to find any iface of the desired type exposed.
@@ -166,12 +179,6 @@
     ASSERT_FALSE(supplicant_manager.IsSupplicantRunning());
 }
 
-// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
-void startSupplicantAndWaitForHidlService() {
-    startSupplicantAndWaitForHidlService("",
-                                         gEnv->getServiceName<ISupplicant>());
-}
-
 void startSupplicantAndWaitForHidlService(
     const std::string& wifi_instance_name,
     const std::string& supplicant_instance_name) {
@@ -230,21 +237,6 @@
         });
 }
 
-// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
-sp<ISupplicant> getSupplicant() {
-    sp<ISupplicant> supplicant =
-        ::testing::VtsHalHidlTargetTestBase::getService<ISupplicant>(
-            gEnv->getServiceName<ISupplicant>());
-    // For 1.1 supplicant, we need to add interfaces at initialization.
-    if (is_1_1(supplicant)) {
-        addSupplicantStaIface_1_1(supplicant);
-        if (gEnv->isP2pOn) {
-            addSupplicantP2pIface_1_1(supplicant);
-        }
-    }
-    return supplicant;
-}
-
 sp<ISupplicant> getSupplicant(const std::string& supplicant_instance_name,
                               bool isP2pOn) {
     sp<ISupplicant> supplicant =
@@ -259,12 +251,6 @@
     return supplicant;
 }
 
-// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
-sp<ISupplicantStaIface> getSupplicantStaIface() {
-    sp<ISupplicant> supplicant = getSupplicant();
-    return getSupplicantStaIface(supplicant);
-}
-
 sp<ISupplicantStaIface> getSupplicantStaIface(
     const sp<ISupplicant>& supplicant) {
     if (!supplicant.get()) {
@@ -290,11 +276,6 @@
     return sta_iface;
 }
 
-// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
-sp<ISupplicantStaNetwork> createSupplicantStaNetwork() {
-    return createSupplicantStaNetwork(getSupplicant());
-}
-
 sp<ISupplicantStaNetwork> createSupplicantStaNetwork(
     const sp<ISupplicant>& supplicant) {
     sp<ISupplicantStaIface> sta_iface = getSupplicantStaIface(supplicant);
@@ -317,11 +298,6 @@
     return sta_network;
 }
 
-// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
-sp<ISupplicantP2pIface> getSupplicantP2pIface() {
-    return getSupplicantP2pIface(getSupplicant());
-}
-
 sp<ISupplicantP2pIface> getSupplicantP2pIface(
     const sp<ISupplicant>& supplicant) {
     if (!supplicant.get()) {
@@ -347,11 +323,6 @@
     return p2p_iface;
 }
 
-// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
-bool turnOnExcessiveLogging() {
-    return turnOnExcessiveLogging(getSupplicant());
-}
-
 bool turnOnExcessiveLogging(const sp<ISupplicant>& supplicant) {
     if (!supplicant.get()) {
         return false;
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
index 40ad695..1ccf091 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
@@ -28,12 +28,9 @@
 #include "wifi_hidl_test_utils.h"
 
 // Used to stop the android wifi framework before every test.
-void stopWifiFramework();
 void stopWifiFramework(const std::string& wifi_instance_name);
-void startWifiFramework();
 void startWifiFramework(const std::string& wifi_instance_name);
 
-void stopSupplicant();
 void stopSupplicant(const std::string& wifi_instance_name);
 // Used to configure the chip, driver and start wpa_supplicant before every
 // test.
@@ -63,63 +60,6 @@
     const android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>&
         supplicant);
 
-// TODO(b/143892896): Remove old APIs after all supplicant tests are updated.
-void startSupplicantAndWaitForHidlService();
-android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicant>
-getSupplicant();
-android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface>
-getSupplicantStaIface();
-android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork>
-createSupplicantStaNetwork();
-android::sp<android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface>
-getSupplicantP2pIface();
-
 bool turnOnExcessiveLogging();
 
-class WifiSupplicantHidlEnvironment
-    : public ::testing::VtsHalHidlTargetTestEnvBase {
-   protected:
-    virtual void HidlSetUp() override { stopSupplicant(); }
-    virtual void HidlTearDown() override {
-        startSupplicantAndWaitForHidlService();
-    }
-
-   public:
-    // Whether P2P feature is supported on the device.
-    bool isP2pOn = true;
-
-    void usage(char* me, char* arg) {
-        fprintf(stderr,
-                "unrecognized option: %s\n\n"
-                "usage: %s <gtest options> <test options>\n\n"
-                "test options are:\n\n"
-                "-P, --p2p_on: Whether P2P feature is supported\n",
-                arg, me);
-    }
-
-    int initFromOptions(int argc, char** argv) {
-        static struct option options[] = {{"p2p_off", no_argument, 0, 'P'},
-                                          {0, 0, 0, 0}};
-
-        int c;
-        while ((c = getopt_long(argc, argv, "P", options, NULL)) >= 0) {
-            switch (c) {
-                case 'P':
-                    isP2pOn = false;
-                    break;
-                default:
-                    usage(argv[0], argv[optind]);
-                    return 2;
-            }
-        }
-
-        if (optind < argc) {
-            usage(argv[0], argv[optind]);
-            return 2;
-        }
-
-        return 0;
-    }
-};
-
 #endif /* SUPPLICANT_HIDL_TEST_UTILS_H */
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.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp
index 8457532..44b020e 100644
--- a/wifi/supplicant/1.1/vts/functional/Android.bp
+++ b/wifi/supplicant/1.1/vts/functional/Android.bp
@@ -19,7 +19,7 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["supplicant_hidl_test_utils_1_1.cpp"],
     export_include_dirs: [
-        "."
+        ".",
     ],
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
@@ -37,7 +37,6 @@
     name: "VtsHalWifiSupplicantV1_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiSupplicantV1_1TargetTest.cpp",
         "supplicant_hidl_test.cpp",
         "supplicant_sta_iface_hidl_test.cpp",
         "supplicant_sta_network_hidl_test.cpp",
@@ -54,5 +53,8 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
deleted file mode 100644
index 9063a3b..0000000
--- a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.1/IWifi.h>
-#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
-
-#include "supplicant_hidl_test_utils.h"
-#include "wifi_hidl_test_utils.h"
-
-class WifiSupplicantHidlEnvironment_1_1 : public WifiSupplicantHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiSupplicantHidlEnvironment_1_1* Instance() {
-        static WifiSupplicantHidlEnvironment_1_1* instance =
-            new WifiSupplicantHidlEnvironment_1_1;
-        return instance;
-    }
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::wifi::V1_0::IWifi>();
-        registerTestService<::android::hardware::wifi::V1_1::IWifi>();
-        registerTestService<
-            ::android::hardware::wifi::supplicant::V1_0::ISupplicant>();
-        registerTestService<
-            ::android::hardware::wifi::supplicant::V1_1::ISupplicant>();
-    }
-
-   private:
-    WifiSupplicantHidlEnvironment_1_1() {}
-};
-
-WifiSupplicantHidlEnvironment* gEnv =
-    WifiSupplicantHidlEnvironment_1_1::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        int status = RUN_ALL_TESTS();
-        LOG(INFO) << "Test result = " << status;
-    }
-    return status;
-}
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
index 28f980c..24a7ec3 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
@@ -17,10 +17,12 @@
 #include <android-base/logging.h>
 #include <cutils/properties.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/types.h>
 #include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "supplicant_hidl_test_utils.h"
 #include "supplicant_hidl_test_utils_1_1.h"
@@ -33,22 +35,11 @@
 using ::android::hardware::wifi::supplicant::V1_1::ISupplicant;
 using ::android::sp;
 
-extern WifiSupplicantHidlEnvironment* gEnv;
-
-class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantHidlTest : public SupplicantHidlTestBase {
    public:
-    virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        supplicant_ = getSupplicant_1_1();
-        ASSERT_NE(supplicant_.get(), nullptr);
-    }
-
-    virtual void TearDown() override { stopSupplicant(); }
+    virtual void SetUp() override { SupplicantHidlTestBase::SetUp(); }
 
    protected:
-    // ISupplicant object used for all tests in this fixture.
-    sp<ISupplicant> supplicant_;
-
     std::string getWlan0IfaceName() {
         std::array<char, PROPERTY_VALUE_MAX> buffer;
         property_get("wifi.interface", buffer.data(), "wlan0");
@@ -65,7 +56,7 @@
 /*
  * AddStaInterface
  */
-TEST_F(SupplicantHidlTest, AddStaInterface) {
+TEST_P(SupplicantHidlTest, AddStaInterface) {
     ISupplicant::IfaceInfo iface_info;
     iface_info.name = getWlan0IfaceName();
     iface_info.type = IfaceType::STA;
@@ -82,8 +73,8 @@
 /*
  * AddP2pInterface
  */
-TEST_F(SupplicantHidlTest, AddP2pInterface) {
-    if (!gEnv->isP2pOn) return;
+TEST_P(SupplicantHidlTest, AddP2pInterface) {
+    if (isP2pOn_) return;
     ISupplicant::IfaceInfo iface_info;
     iface_info.name = getP2pIfaceName();
     iface_info.type = IfaceType::P2P;
@@ -100,7 +91,7 @@
 /*
  * RemoveStaInterface
  */
-TEST_F(SupplicantHidlTest, RemoveStaInterface) {
+TEST_P(SupplicantHidlTest, RemoveStaInterface) {
     ISupplicant::IfaceInfo iface_info;
     iface_info.name = getWlan0IfaceName();
     iface_info.type = IfaceType::STA;
@@ -122,8 +113,8 @@
 /*
  * RemoveP2pInterface
  */
-TEST_F(SupplicantHidlTest, RemoveP2pInterface) {
-    if (!gEnv->isP2pOn) return;
+TEST_P(SupplicantHidlTest, RemoveP2pInterface) {
+    if (isP2pOn_) return;
     ISupplicant::IfaceInfo iface_info;
     iface_info.name = getP2pIfaceName();
     iface_info.type = IfaceType::P2P;
@@ -146,6 +137,23 @@
  * Terminate
  * This terminates the service.
  */
-TEST_F(SupplicantHidlTest, Terminate) {
-    supplicant_->terminate();
+TEST_P(SupplicantHidlTest, Terminate) { supplicant_->terminate(); }
+
+static std::vector<std::string> get_wifi_instances() {
+    std::vector<std::string> instances =
+        android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::V1_0::IWifi::descriptor);
+    // Also test when wifi instance is not set.
+    instances.push_back("");
+
+    return instances;
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantHidlTest,
+    testing::Combine(
+        testing::ValuesIn(get_wifi_instances()),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::supplicant::V1_1::ISupplicant::
+                descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
index 04a5ed9..b75a2fb 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 
 #include "supplicant_hidl_test_utils.h"
@@ -25,14 +24,19 @@
 using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaNetwork;
 using ::android::sp;
 
-sp<ISupplicant> getSupplicant_1_1() {
-    return ISupplicant::castFrom(getSupplicant());
+sp<ISupplicant> getSupplicant_1_1(const std::string& supplicant_instance_name,
+                                  bool isP2pOn) {
+    return ISupplicant::castFrom(
+        getSupplicant(supplicant_instance_name, isP2pOn));
 }
 
-sp<ISupplicantStaIface> getSupplicantStaIface_1_1() {
-    return ISupplicantStaIface::castFrom(getSupplicantStaIface());
+sp<ISupplicantStaIface> getSupplicantStaIface_1_1(
+    const sp<ISupplicant>& supplicant) {
+    return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant));
 }
 
-sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_1() {
-    return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork());
+sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_1(
+    const sp<ISupplicant>& supplicant) {
+    return ISupplicantStaNetwork::castFrom(
+        createSupplicantStaNetwork(supplicant));
 }
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
index 1c13325..3629882 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
@@ -14,20 +14,52 @@
  * limitations under the License.
  */
 
-#ifndef SUPPLICANT_HIDL_TEST_UTILS_1_1_H
-#define SUPPLICANT_HIDL_TEST_UTILS_1_1_H
+#pragma once
+#pragma clang diagnostic ignored "-Wweak-vtables"
 
+#include <VtsCoreUtil.h>
 #include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
 #include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIface.h>
 #include <android/hardware/wifi/supplicant/1.1/ISupplicantStaNetwork.h>
+#include <gtest/gtest.h>
 
 android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>
-    getSupplicant_1_1();
+getSupplicant_1_1(const std::string& supplicant_instance_name, bool isP2pOn);
 
 android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface>
-    getSupplicantStaIface_1_1();
+getSupplicantStaIface_1_1(
+    const android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>&
+        supplicant);
 
 android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicantStaNetwork>
-    createSupplicantStaNetwork_1_1();
+createSupplicantStaNetwork_1_1(
+    const android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>&
+        supplicant);
 
-#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_1_H */
+class SupplicantHidlTestBase
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+   public:
+    virtual void SetUp() override {
+        wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+        supplicant_v1_1_instance_name_ = std::get<1>(GetParam());
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        stopSupplicant(wifi_v1_0_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+                                             supplicant_v1_1_instance_name_);
+        supplicant_ =
+            getSupplicant_1_1(supplicant_v1_1_instance_name_, isP2pOn_);
+        ASSERT_NE(supplicant_.get(), nullptr);
+    }
+
+    virtual void TearDown() override {
+        stopSupplicant(wifi_v1_0_instance_name_);
+    }
+
+   protected:
+    android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>
+        supplicant_;
+    bool isP2pOn_ = false;
+    std::string wifi_v1_0_instance_name_;
+    std::string supplicant_v1_1_instance_name_;
+};
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
index c5e6319..8a1aecc 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -16,9 +16,13 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIface.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "supplicant_hidl_test_utils.h"
 #include "supplicant_hidl_test_utils_1_1.h"
@@ -29,26 +33,24 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface;
-using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIfaceCallback;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaIfaceCallback;
 
-class SupplicantStaIfaceHidlTest
-    : public ::testing::VtsHalHidlTargetTestBase {
- public:
-  virtual void SetUp() override {
-      startSupplicantAndWaitForHidlService();
-      EXPECT_TRUE(turnOnExcessiveLogging());
-      sta_iface_ = getSupplicantStaIface_1_1();
-      ASSERT_NE(sta_iface_.get(), nullptr);
-  }
+class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBase {
+   public:
+    virtual void SetUp() override {
+        SupplicantHidlTestBase::SetUp();
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_iface_ = getSupplicantStaIface_1_1(supplicant_);
+        ASSERT_NE(sta_iface_.get(), nullptr);
+    }
 
-  virtual void TearDown() override { stopSupplicant(); }
-
- protected:
-  // ISupplicantStaIface object used for all tests in this fixture.
-  sp<ISupplicantStaIface> sta_iface_;
+   protected:
+    // ISupplicantStaIface object used for all tests in this fixture.
+    sp<ISupplicantStaIface> sta_iface_;
 };
 
 class IfaceCallback : public ISupplicantStaIfaceCallback {
@@ -131,9 +133,19 @@
 /*
  * RegisterCallback_1_1
  */
-TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_1) {
-  sta_iface_->registerCallback_1_1(
-      new IfaceCallback(), [](const SupplicantStatus& status) {
-          EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-      });
+TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_1) {
+    sta_iface_->registerCallback_1_1(
+        new IfaceCallback(), [](const SupplicantStatus& status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaIfaceHidlTest,
+    testing::Combine(
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::V1_0::IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::supplicant::V1_1::ISupplicant::
+                descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp
index fa52556..a4b7d40 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -16,8 +16,11 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.1/ISupplicantStaNetwork.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "supplicant_hidl_test_utils.h"
 #include "supplicant_hidl_test_utils_1_1.h"
@@ -26,27 +29,26 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_1::ISupplicantStaNetwork;
+
 namespace {
 constexpr uint8_t kTestIdentity[] = {0x45, 0x67, 0x98, 0x67, 0x56};
 constexpr uint8_t kTestEncryptedIdentity[] = {0x35, 0x37, 0x58, 0x57, 0x26};
 }  // namespace
 
-class SupplicantStaNetworkHidlTest
-    : public ::testing::VtsHalHidlTargetTestBase {
- public:
-  virtual void SetUp() override {
-    startSupplicantAndWaitForHidlService();
-    EXPECT_TRUE(turnOnExcessiveLogging());
-    sta_network_ = createSupplicantStaNetwork_1_1();
-    ASSERT_NE(sta_network_.get(), nullptr);
-  }
+class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBase {
+   public:
+    virtual void SetUp() override {
+        SupplicantHidlTestBase::SetUp();
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_network_ = createSupplicantStaNetwork_1_1(supplicant_);
+        ASSERT_NE(sta_network_.get(), nullptr);
+    }
 
-  virtual void TearDown() override { stopSupplicant(); }
-
- protected:
-  // ISupplicantStaNetwork object used for all tests in this fixture.
-  sp<ISupplicantStaNetwork> sta_network_;
+   protected:
+    // ISupplicantStaNetwork object used for all tests in this fixture.
+    sp<ISupplicantStaNetwork> sta_network_;
 };
 
 /*
@@ -54,36 +56,49 @@
  * Ensures that an instance of the ISupplicantStaNetwork proxy object is
  * successfully created.
  */
-TEST(SupplicantStaNetworkHidlTestNoFixture, Create) {
-  startSupplicantAndWaitForHidlService();
-  EXPECT_NE(nullptr, createSupplicantStaNetwork_1_1().get());
-  stopSupplicant();
+TEST_P(SupplicantStaNetworkHidlTest, Create) {
+    stopSupplicant(wifi_v1_0_instance_name_);
+    startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+                                         supplicant_v1_1_instance_name_);
+    sp<ISupplicant> supplicant =
+        getSupplicant_1_1(supplicant_v1_1_instance_name_, isP2pOn_);
+    EXPECT_NE(nullptr, createSupplicantStaNetwork_1_1(supplicant).get());
 }
 
 /*
  * Ensure that the encrypted imsi identity is set successfully.
  */
-TEST_F(SupplicantStaNetworkHidlTest, setEapEncryptedImsiIdentity) {
-  std::vector<uint8_t> encrypted_identity(
-      kTestEncryptedIdentity,
-      kTestEncryptedIdentity + sizeof(kTestEncryptedIdentity));
-  sta_network_->setEapEncryptedImsiIdentity(
-      encrypted_identity, [](const SupplicantStatus &status) {
-        EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-      });
+TEST_P(SupplicantStaNetworkHidlTest, setEapEncryptedImsiIdentity) {
+    std::vector<uint8_t> encrypted_identity(
+        kTestEncryptedIdentity,
+        kTestEncryptedIdentity + sizeof(kTestEncryptedIdentity));
+    sta_network_->setEapEncryptedImsiIdentity(
+        encrypted_identity, [](const SupplicantStatus &status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
 }
 
 /*
  * Ensure that the identity and the encrypted imsi identity are sent
  * successfully.
  */
-TEST_F(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse_1_1) {
-  sta_network_->sendNetworkEapIdentityResponse_1_1(
-      std::vector<uint8_t>(kTestIdentity,
-                           kTestIdentity + sizeof(kTestIdentity)),
-      std::vector<uint8_t>(kTestEncryptedIdentity,
-                           kTestIdentity + sizeof(kTestEncryptedIdentity)),
-      [](const SupplicantStatus &status) {
-        EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-      });
+TEST_P(SupplicantStaNetworkHidlTest, SendNetworkEapIdentityResponse_1_1) {
+    sta_network_->sendNetworkEapIdentityResponse_1_1(
+        std::vector<uint8_t>(kTestIdentity,
+                             kTestIdentity + sizeof(kTestIdentity)),
+        std::vector<uint8_t>(kTestEncryptedIdentity,
+                             kTestIdentity + sizeof(kTestEncryptedIdentity)),
+        [](const SupplicantStatus &status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaNetworkHidlTest,
+    testing::Combine(
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::V1_0::IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::supplicant::V1_1::ISupplicant::
+                descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
diff --git a/wifi/supplicant/1.2/vts/functional/Android.bp b/wifi/supplicant/1.2/vts/functional/Android.bp
index b7949d1..c23585a 100644
--- a/wifi/supplicant/1.2/vts/functional/Android.bp
+++ b/wifi/supplicant/1.2/vts/functional/Android.bp
@@ -19,7 +19,7 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["supplicant_hidl_test_utils_1_2.cpp"],
     export_include_dirs: [
-        "."
+        ".",
     ],
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
@@ -39,7 +39,6 @@
     name: "VtsHalWifiSupplicantV1_2TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiSupplicantV1_2TargetTest.cpp",
         "supplicant_sta_iface_hidl_test.cpp",
         "supplicant_sta_network_hidl_test.cpp",
     ],
@@ -51,20 +50,23 @@
         "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",
         "android.hardware.wifi@1.1",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
 
 cc_test {
     name: "VtsHalWifiSupplicantP2pV1_2TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiSupplicantV1_2TargetTest.cpp",
         "supplicant_p2p_iface_hidl_test.cpp",
     ],
     static_libs: [
@@ -81,5 +83,8 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
-
diff --git a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp
deleted file mode 100644
index 267fa67..0000000
--- a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp
+++ /dev/null
@@ -1,60 +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 <android/hardware/wifi/1.1/IWifi.h>
-#include <android/hardware/wifi/supplicant/1.2/ISupplicant.h>
-
-#include "supplicant_hidl_test_utils.h"
-#include "wifi_hidl_test_utils.h"
-
-class WifiSupplicantHidlEnvironment_1_2 : public WifiSupplicantHidlEnvironment {
-   public:
-    // get the test environment singleton
-    static WifiSupplicantHidlEnvironment_1_2* Instance() {
-        static WifiSupplicantHidlEnvironment_1_2* instance =
-            new WifiSupplicantHidlEnvironment_1_2;
-        return instance;
-    }
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::wifi::V1_0::IWifi>();
-        registerTestService<::android::hardware::wifi::V1_1::IWifi>();
-        registerTestService<
-            ::android::hardware::wifi::supplicant::V1_0::ISupplicant>();
-        registerTestService<
-            ::android::hardware::wifi::supplicant::V1_1::ISupplicant>();
-        registerTestService<
-            ::android::hardware::wifi::supplicant::V1_2::ISupplicant>();
-    }
-
-   private:
-    WifiSupplicantHidlEnvironment_1_2() {}
-};
-
-WifiSupplicantHidlEnvironment* gEnv =
-    WifiSupplicantHidlEnvironment_1_2::Instance();
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        int status = RUN_ALL_TESTS();
-        LOG(INFO) << "Test result = " << status;
-    }
-    return status;
-}
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp
index f270bff..46d5a61 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 
 #include "supplicant_hidl_test_utils.h"
@@ -26,18 +25,24 @@
 using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface;
 using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
 
-sp<ISupplicant> getSupplicant_1_2() {
-    return ISupplicant::castFrom(getSupplicant());
+sp<ISupplicant> getSupplicant_1_2(const std::string& supplicant_instance_name,
+                                  bool isP2pOn) {
+    return ISupplicant::castFrom(
+        getSupplicant(supplicant_instance_name, isP2pOn));
 }
 
-sp<ISupplicantStaIface> getSupplicantStaIface_1_2() {
-    return ISupplicantStaIface::castFrom(getSupplicantStaIface());
+sp<ISupplicantStaIface> getSupplicantStaIface_1_2(
+    const sp<ISupplicant>& supplicant) {
+    return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant));
 }
 
-sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_2() {
-    return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork());
+sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_2(
+    const sp<ISupplicant>& supplicant) {
+    return ISupplicantStaNetwork::castFrom(
+        createSupplicantStaNetwork(supplicant));
 }
 
-sp<ISupplicantP2pIface> getSupplicantP2pIface_1_2() {
-    return ISupplicantP2pIface::castFrom(getSupplicantP2pIface());
+sp<ISupplicantP2pIface> getSupplicantP2pIface_1_2(
+    const sp<ISupplicant>& supplicant) {
+    return ISupplicantP2pIface::castFrom(getSupplicantP2pIface(supplicant));
 }
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h
index 8a7ccc5..5ecfdd4 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_hidl_test_utils_1_2.h
@@ -14,24 +14,59 @@
  * limitations under the License.
  */
 
-#ifndef SUPPLICANT_HIDL_TEST_UTILS_1_2_H
-#define SUPPLICANT_HIDL_TEST_UTILS_1_2_H
+#pragma once
+#pragma clang diagnostic ignored "-Wweak-vtables"
 
+#include <VtsCoreUtil.h>
 #include <android/hardware/wifi/supplicant/1.2/ISupplicant.h>
 #include <android/hardware/wifi/supplicant/1.2/ISupplicantP2pIface.h>
 #include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIface.h>
 #include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
+#include <gtest/gtest.h>
 
 android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>
-getSupplicant_1_2();
+getSupplicant_1_2(const std::string& supplicant_instance_name, bool isP2pOn);
 
 android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface>
-getSupplicantStaIface_1_2();
+getSupplicantStaIface_1_2(
+    const android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>&
+        supplicant);
 
 android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork>
-createSupplicantStaNetwork_1_2();
+createSupplicantStaNetwork_1_2(
+    const android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>&
+        supplicant);
 
 android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicantP2pIface>
-getSupplicantP2pIface_1_2();
+getSupplicantP2pIface_1_2(
+    const android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>&
+        supplicant);
 
-#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_2_H */
+class SupplicantHidlTestBase
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+   public:
+    virtual void SetUp() override {
+        wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+        supplicant_v1_2_instance_name_ = std::get<1>(GetParam());
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+        stopSupplicant(wifi_v1_0_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+                                             supplicant_v1_2_instance_name_);
+        supplicant_ =
+            getSupplicant_1_2(supplicant_v1_2_instance_name_, isP2pOn_);
+        ASSERT_NE(supplicant_.get(), nullptr);
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+    }
+
+    virtual void TearDown() override {
+        stopSupplicant(wifi_v1_0_instance_name_);
+    }
+
+   protected:
+    android::sp<android::hardware::wifi::supplicant::V1_2::ISupplicant>
+        supplicant_;
+    bool isP2pOn_ = false;
+    std::string wifi_v1_0_instance_name_;
+    std::string supplicant_v1_2_instance_name_;
+};
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
index 1b78ac3..1eb8eea 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_p2p_iface_hidl_test.cpp
@@ -16,9 +16,11 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.2/ISupplicantP2pIface.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "supplicant_hidl_test_utils.h"
 #include "supplicant_hidl_test_utils_1_2.h"
@@ -26,6 +28,7 @@
 using ::android::sp;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_2::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_2::ISupplicantP2pIface;
 
 namespace {
@@ -35,17 +38,18 @@
 constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0};
 }  // namespace
 
-class SupplicantP2pIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantP2pIfaceHidlTest : public SupplicantHidlTestBase {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        EXPECT_TRUE(turnOnExcessiveLogging());
-        p2p_iface_ = getSupplicantP2pIface_1_2();
+        SupplicantHidlTestBase::SetUp();
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct")) {
+            GTEST_SKIP() << "Wi-Fi Direct is not supported, skip this test.";
+        }
+        p2p_iface_ = getSupplicantP2pIface_1_2(supplicant_);
         ASSERT_NE(p2p_iface_.get(), nullptr);
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
-
    protected:
     // ISupplicantP2pIface object used for all tests in this fixture.
     sp<ISupplicantP2pIface> p2p_iface_;
@@ -54,7 +58,7 @@
 /*
  * Verify that AddGroup_1_2 could create a group successfully.
  */
-TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_Success) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_Success) {
     std::vector<uint8_t> ssid(kTestSsid, kTestSsid + sizeof(kTestSsid));
     std::string passphrase = kTestPassphrase;
     int freq = 0;
@@ -73,7 +77,7 @@
 /*
  * Verify that AddGroup_1_2 fails due to invalid SSID.
  */
-TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidSsid) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidSsid) {
     std::vector<uint8_t> ssid;
     std::string passphrase = kTestPassphrase;
     int freq = 0;
@@ -92,7 +96,7 @@
 /*
  * Verify that AddGroup_1_2 fails due to invalid passphrase.
  */
-TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidPassphrase) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidPassphrase) {
     std::vector<uint8_t> ssid(kTestSsid, kTestSsid + sizeof(kTestSsid));
     std::string passphrase = "1234";
     int freq = 0;
@@ -111,7 +115,7 @@
 /*
  * Verify that AddGroup_1_2 fails due to invalid frequency.
  */
-TEST_F(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidFrequency) {
+TEST_P(SupplicantP2pIfaceHidlTest, AddGroup_1_2_FailureInvalidFrequency) {
     std::vector<uint8_t> ssid(kTestSsid, kTestSsid + sizeof(kTestSsid));
     std::string passphrase = kTestPassphrase;
     int freq = 9999;
@@ -134,7 +138,7 @@
 /*
  * Verify that setMacRandomization successes.
  */
-TEST_F(SupplicantP2pIfaceHidlTest, EnableMacRandomization) {
+TEST_P(SupplicantP2pIfaceHidlTest, EnableMacRandomization) {
     p2p_iface_->setMacRandomization(true, [](const SupplicantStatus& status) {
         if (!isMacRandomizationSupported(status)) return;
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -157,3 +161,13 @@
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantP2pIfaceHidlTest,
+    testing::Combine(
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::V1_0::IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::supplicant::V1_2::ISupplicant::
+                descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 2ff7751..7377f78 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantStaIfaceCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/types.h>
 #include <android/hardware/wifi/supplicant/1.1/ISupplicantStaIfaceCallback.h>
@@ -22,7 +23,11 @@
 #include <android/hardware/wifi/supplicant/1.2/ISupplicantStaIfaceCallback.h>
 #include <android/hardware/wifi/supplicant/1.2/ISupplicantStaNetwork.h>
 #include <android/hardware/wifi/supplicant/1.2/types.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/types.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
 #include <hidl/Status.h>
 
 #include "supplicant_hidl_test_utils.h"
@@ -40,6 +45,7 @@
 using ::android::hardware::wifi::supplicant::V1_2::DppFailureCode;
 using ::android::hardware::wifi::supplicant::V1_2::DppNetRole;
 using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode;
+using ::android::hardware::wifi::supplicant::V1_2::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIface;
 using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaIfaceCallback;
 using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
@@ -47,18 +53,16 @@
 #define TIMEOUT_PERIOD 60
 class IfaceDppCallback;
 
-class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantStaIfaceHidlTest : public SupplicantHidlTestBase {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        EXPECT_TRUE(turnOnExcessiveLogging());
-        sta_iface_ = getSupplicantStaIface_1_2();
+        SupplicantHidlTestBase::SetUp();
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_iface_ = getSupplicantStaIface_1_2(supplicant_);
         ASSERT_NE(sta_iface_.get(), nullptr);
         count_ = 0;
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
-
     enum DppCallbackType {
         ANY_CALLBACK = -2,
         INVALID = -1,
@@ -99,6 +103,7 @@
    protected:
     // ISupplicantStaIface object used for all tests in this fixture.
     sp<ISupplicantStaIface> sta_iface_;
+
     bool isDppSupported() {
         uint32_t keyMgmtMask = 0;
 
@@ -106,9 +111,14 @@
         // If DPP is not supported, we just pass the test.
         sta_iface_->getKeyMgmtCapabilities(
             [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
-                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                // Since getKeyMgmtCapabilities() is overridden by an
+                // upgraded API in newer HAL versions, allow for
+                // FAILURE_UNKNOWN and return DPP is not supported.
+                if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                    EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
 
-                keyMgmtMask = keyMgmtMaskInternal;
+                    keyMgmtMask = keyMgmtMaskInternal;
+                }
             });
 
         if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) {
@@ -252,7 +262,7 @@
 /*
  * RegisterCallback_1_2
  */
-TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_2) {
+TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_2) {
     sta_iface_->registerCallback_1_2(
         new IfaceCallback(), [](const SupplicantStatus& status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -262,9 +272,13 @@
 /*
  * GetKeyMgmtCapabilities
  */
-TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) {
-    sta_iface_->getKeyMgmtCapabilities(
-        [&](const SupplicantStatus& status, uint32_t keyMgmtMask) {
+TEST_P(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) {
+    sta_iface_->getKeyMgmtCapabilities([&](const SupplicantStatus& status,
+                                           uint32_t keyMgmtMask) {
+        // Since this API is overridden by an upgraded API in newer HAL
+        // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+        // longer supported on newer HAL.
+        if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
 
             // Even though capabilities vary, these two are always set in HAL
@@ -272,13 +286,14 @@
             EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::NONE);
             EXPECT_TRUE(keyMgmtMask &
                         ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X);
-        });
+        }
+    });
 }
 
 /*
  * AddDppPeerUriAndRomveUri
  */
-TEST_F(SupplicantStaIfaceHidlTest, AddDppPeerUriAndRomveUri) {
+TEST_P(SupplicantStaIfaceHidlTest, AddDppPeerUriAndRomveUri) {
     // We need to first get the key management capabilities from the device.
     // If DPP is not supported, we just pass the test.
     if (!isDppSupported()) {
@@ -287,7 +302,8 @@
     }
 
     hidl_string uri =
-        "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+        "DPP:C:81/1,117/"
+        "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
         "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
     uint32_t peer_id = 0;
 
@@ -310,7 +326,7 @@
 /*
  * StartDppEnrolleeInitiator
  */
-TEST_F(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) {
+TEST_P(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) {
     // We need to first get the key management capabilities from the device.
     // If DPP is not supported, we just pass the test.
     if (!isDppSupported()) {
@@ -318,8 +334,22 @@
         return;
     }
 
+    /* Check if the underlying HAL version is 1.3 or higher and skip the test
+     * in this case. The 1.3 HAL uses different callbacks which are not
+     * supported by 1.2. This will cause this test to fail because the callbacks
+     * it is waiting for will never be called. Note that this test is also
+     * implemented in the 1.3 VTS test.
+     */
+    sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface> v1_3 =
+        ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface::
+            castFrom(sta_iface_);
+    if (v1_3 != nullptr) {
+        GTEST_SKIP() << "Test not supported with this HAL version";
+    }
+
     hidl_string uri =
-        "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+        "DPP:C:81/1,117/"
+        "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
         "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
     uint32_t peer_id = 0;
 
@@ -361,7 +391,7 @@
 /*
  * StartDppConfiguratorInitiator
  */
-TEST_F(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) {
+TEST_P(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) {
     // We need to first get the key management capabilities from the device.
     // If DPP is not supported, we just pass the test.
     if (!isDppSupported()) {
@@ -369,8 +399,24 @@
         return;
     }
 
+    /* Check if the underlying HAL version is 1.3 or higher and skip the test
+     * in this case. The 1.3 HAL uses different callbacks which are not
+     * supported by 1.2. This will cause this test to fail because the callbacks
+     * it is waiting for will never be called. Note that this test is also
+     * implemented in the 1.3 VTS test.
+     */
+    sp<::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface> v1_3 =
+        ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface::
+            castFrom(sta_iface_);
+
+    if (v1_3 != nullptr) {
+        GTEST_SKIP() << "Test not supported with this HAL version";
+        return;
+    }
+
     hidl_string uri =
-        "DPP:C:81/1;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+        "DPP:C:81/1,117/"
+        "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
         "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
     uint32_t peer_id = 0;
 
@@ -413,3 +459,13 @@
         EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
     });
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaIfaceHidlTest,
+    testing::Combine(
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::V1_0::IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::supplicant::V1_2::ISupplicant::
+                descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
index ed421d7..54ceb20 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -16,8 +16,12 @@
 
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
 #include <android/hardware/wifi/supplicant/1.1/ISupplicantStaNetwork.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include "supplicant_hidl_test_utils.h"
 #include "supplicant_hidl_test_utils_1_2.h"
@@ -26,24 +30,21 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_2::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_2::ISupplicantStaNetwork;
 // namespace {
 // constexpr uint8_t kTestIdentity[] = {0x45, 0x67, 0x98, 0x67, 0x56};
 // constexpr uint8_t kTestEncryptedIdentity[] = {0x35, 0x37, 0x58, 0x57, 0x26};
 //}  // namespace
 
-class SupplicantStaNetworkHidlTest
-    : public ::testing::VtsHalHidlTargetTestBase {
+class SupplicantStaNetworkHidlTest : public SupplicantHidlTestBase {
    public:
     virtual void SetUp() override {
-        startSupplicantAndWaitForHidlService();
-        EXPECT_TRUE(turnOnExcessiveLogging());
-        sta_network_ = createSupplicantStaNetwork_1_2();
+        SupplicantHidlTestBase::SetUp();
+        sta_network_ = createSupplicantStaNetwork_1_2(supplicant_);
         ASSERT_NE(sta_network_.get(), nullptr);
     }
 
-    virtual void TearDown() override { stopSupplicant(); }
-
    protected:
     // ISupplicantStaNetwork object used for all tests in this fixture.
     sp<ISupplicantStaNetwork> sta_network_;
@@ -52,7 +53,7 @@
 /*
  * SetGetSaePassword
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetSaePassword) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetSaePassword) {
     std::string password = "topsecret";
 
     sta_network_->setSaePassword(password, [](const SupplicantStatus &status) {
@@ -69,7 +70,7 @@
 /*
  * SetGetSaePasswordId
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetSaePasswordId) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetSaePasswordId) {
     std::string passwordId = "id1";
 
     sta_network_->setSaePasswordId(
@@ -87,7 +88,7 @@
 /*
  * SetGetGroupMgmtCipher
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupMgmtCipher) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupMgmtCipher) {
     uint32_t groupMgmtCipher =
         (uint32_t)ISupplicantStaNetwork::GroupMgmtCipherMask::BIP_GMAC_256;
 
@@ -107,64 +108,94 @@
 /*
  * SetGetKeyMgmt_1_2
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_2) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_2) {
     uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::SAE;
 
     sta_network_->setKeyMgmt_1_2(keyMgmt, [](const SupplicantStatus &status) {
-        EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        // Since this API is overridden by an upgraded API in newer HAL
+        // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+        // longer supported on newer HALs.
+        if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        }
     });
 
     sta_network_->getKeyMgmt_1_2(
         [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-            EXPECT_EQ(keyMgmtOut, keyMgmt);
+            // Since this API is overridden by an upgraded API in newer HAL
+            // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+            // longer supported on newer HALs.
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                EXPECT_EQ(keyMgmtOut, keyMgmt);
+            }
         });
 }
 
 /*
  * SetGetGroupCipher_1_2
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_2) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_2) {
     uint32_t groupCipher =
         (uint32_t)ISupplicantStaNetwork::GroupCipherMask::GCMP_256;
 
     sta_network_->setGroupCipher_1_2(
         groupCipher, [](const SupplicantStatus &status) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            // Since this API is overridden by an upgraded API in newer HAL
+            // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+            // longer supported on newer HALs.
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            }
         });
 
     sta_network_->getGroupCipher_1_2(
         [&groupCipher](const SupplicantStatus &status,
                        uint32_t groupCipherOut) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-            EXPECT_EQ(groupCipherOut, groupCipher);
+            // Since this API is overridden by an upgraded API in newer HAL
+            // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+            // longer supported on newer HALs.
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                EXPECT_EQ(groupCipherOut, groupCipher);
+            }
         });
 }
 
 /*
  * SetGetPairwiseCipher_1_2
  */
-TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_2) {
+TEST_P(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_2) {
     uint32_t pairwiseCipher =
         (uint32_t)ISupplicantStaNetwork::PairwiseCipherMask::GCMP_256;
 
     sta_network_->setPairwiseCipher_1_2(
         pairwiseCipher, [](const SupplicantStatus &status) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            // Since this API is overridden by an upgraded API in newer HAL
+            // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+            // longer supported on newer HALs.
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            }
         });
 
     sta_network_->getPairwiseCipher_1_2(
         [&pairwiseCipher](const SupplicantStatus &status,
                           uint32_t pairwiseCipherOut) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
-            EXPECT_EQ(pairwiseCipherOut, pairwiseCipher);
+            // Since this API is overridden by an upgraded API in newer HAL
+            // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+            // longer supported on newer HALs.
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                EXPECT_EQ(pairwiseCipherOut, pairwiseCipher);
+            }
         });
 }
 
 /*
  * EnableSuiteBEapOpenSslCiphers
  */
-TEST_F(SupplicantStaNetworkHidlTest, EnableSuiteBEapOpenSslCiphers) {
+TEST_P(SupplicantStaNetworkHidlTest, EnableSuiteBEapOpenSslCiphers) {
     sta_network_->enableSuiteBEapOpenSslCiphers(
         [](const SupplicantStatus &status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -179,7 +210,7 @@
 /*
  * EnableTlsSuiteBEapPhase1Param
  */
-TEST_F(SupplicantStaNetworkHidlTest, EnableTlsSuiteBEapPhase1Param) {
+TEST_P(SupplicantStaNetworkHidlTest, EnableTlsSuiteBEapPhase1Param) {
     sta_network_->enableTlsSuiteBEapPhase1Param(
         true, [](const SupplicantStatus &status) {
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
@@ -190,3 +221,13 @@
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
         });
 }
+
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaNetworkHidlTest,
+    testing::Combine(
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::V1_0::IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::supplicant::V1_2::ISupplicant::
+                descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.3/Android.bp b/wifi/supplicant/1.3/Android.bp
new file mode 100644
index 0000000..4268490
--- /dev/null
+++ b/wifi/supplicant/1.3/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi.supplicant@1.3",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "ISupplicant.hal",
+        "ISupplicantStaIface.hal",
+        "ISupplicantStaIfaceCallback.hal",
+        "ISupplicantStaNetwork.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hardware.wifi.supplicant@1.1",
+        "android.hardware.wifi.supplicant@1.2",
+        "android.hardware.wifi@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/wifi/supplicant/1.3/ISupplicant.hal b/wifi/supplicant/1.3/ISupplicant.hal
new file mode 100644
index 0000000..246ce1f
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicant.hal
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant@1.3;
+
+import @1.2::ISupplicant;
+
+/**
+ * Interface exposed by the supplicant HIDL service registered
+ * with the hardware service manager.
+ * This is the root level object for any the supplicant interactions.
+ * To use 1.3 features you must cast specific interfaces returned from the
+ * 1.2 HAL. For example V1_2::ISupplicant::addIface() adds V1_2::ISupplicantIface,
+ * which can be cast to V1_3::ISupplicantStaIface.
+ */
+interface ISupplicant extends @1.2::ISupplicant {};
diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal
new file mode 100644
index 0000000..4506f37
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant@1.3;
+
+import @1.0::SupplicantStatus;
+import @1.2::ISupplicantStaIface;
+import ISupplicantStaNetwork;
+import ISupplicantStaIfaceCallback;
+import @1.0::MacAddress;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * interface (e.g wlan0) it controls.
+ */
+interface ISupplicantStaIface extends @1.2::ISupplicantStaIface {
+    /**
+     * Register for callbacks from this interface.
+     *
+     * These callbacks are invoked for events that are specific to this interface.
+     * Registration of multiple callback objects is supported. These objects must
+     * be automatically deleted when the corresponding client process is dead or
+     * if this interface is removed.
+     *
+     * @param callback An instance of the |ISupplicantStaIfaceCallback| HIDL
+     *        interface object.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    registerCallback_1_3(ISupplicantStaIfaceCallback callback)
+        generates (SupplicantStatus status);
+
+    /**
+     * Get Connection capabilities
+     *
+     * @return status Status of the operation, and connection capabilities.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     */
+    getConnectionCapabilities()
+        generates (SupplicantStatus status, ConnectionCapabilities capabilities);
+
+    /**
+     * Get wpa driver capabilities.
+     *
+     * @return status Status of the operation, and a bitmap of wpa driver features.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     */
+    getWpaDriverCapabilities() generates (SupplicantStatus status,
+        bitfield<WpaDriverCapabilitiesMask> driverCapabilitiesMask);
+
+    /**
+     * 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.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setMboCellularDataStatus(bool available) generates (SupplicantStatus status);
+
+    /**
+     * Get Key management capabilities of the device
+     *
+     * @return status Status of the operation, and a bitmap of key management mask.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    getKeyMgmtCapabilities_1_3()
+        generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
+
+    /**
+     * 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:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    filsHlpFlushRequest() generates (SupplicantStatus status);
+
+    /**
+     * 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 packet starting from ethertype
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_DISABLED|
+     */
+    filsHlpAddRequest(MacAddress dst_mac, vec<uint8_t> pkt) generates (SupplicantStatus status);
+};
diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
new file mode 100644
index 0000000..c5da29c
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant@1.3;
+
+import @1.2::ISupplicantStaIfaceCallback;
+import @1.0::ISupplicantStaIfaceCallback.State;
+import @1.0::Bssid;
+import @1.0::SupplicantNetworkId;
+import @1.0::Ssid;
+
+/**
+ * Callback Interface exposed by the supplicant service
+ * for each station mode interface (ISupplicantStaIface).
+ *
+ * Clients need to host an instance of this HIDL interface object and
+ * pass a reference of the object to the supplicant via the
+ * corresponding |ISupplicantStaIface.registerCallback_1_3| method.
+ */
+interface ISupplicantStaIfaceCallback extends @1.2::ISupplicantStaIfaceCallback {
+    /**
+     * IEEE Std 802.11-2016 - Table 9-357.
+     * BTM status code filled in BSS transition management response frame.
+     */
+    enum BssTmStatusCode : uint8_t {
+        ACCEPT = 0,
+        REJECT_UNSPECIFIED = 1,
+        REJECT_INSUFFICIENT_BEACON = 2,
+        REJECT_INSUFFICIENT_CAPABITY = 3,
+        REJECT_BSS_TERMINATION_UNDESIRED = 4,
+        REJECT_BSS_TERMINATION_DELAY_REQUEST = 5,
+        REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+        REJECT_NO_SUITABLE_CANDIDATES = 7,
+        REJECT_LEAVING_ESS = 8,
+    };
+
+    /**
+     * Bitmask of various information retrieved from BSS transition management request frame.
+     */
+    enum BssTmDataFlagsMask : uint32_t {
+        /**
+         * Preferred candidate list included.
+         */
+        WNM_MODE_PREFERRED_CANDIDATE_LIST_INCLUDED = 1 << 0,
+        /**
+         * Abridged.
+         */
+        WNM_MODE_ABRIDGED = 1 << 1,
+        /**
+         * Disassociation Imminent.
+         */
+        WNM_MODE_DISASSOCIATION_IMMINENT = 1 << 2,
+        /**
+         * BSS termination included.
+         */
+        WNM_MODE_BSS_TERMINATION_INCLUDED = 1 << 3,
+        /**
+         * ESS Disassociation Imminent.
+         */
+        WNM_MODE_ESS_DISASSOCIATION_IMMINENT = 1 << 4,
+        /**
+         * MBO transition reason code included.
+         */
+        MBO_TRANSITION_REASON_CODE_INCLUDED = 1 << 5,
+        /**
+         * MBO retry delay time included.
+         */
+        MBO_ASSOC_RETRY_DELAY_INCLUDED = 1 << 6,
+        /**
+         * MBO cellular data connection preference value included.
+         */
+        MBO_CELLULAR_DATA_CONNECTION_PREFERENCE_INCLUDED = 1 << 7,
+    };
+
+    /**
+     *  MBO spec v1.2, 4.2.6 Table 18: MBO transition reason code attribute
+     *  values.
+     */
+    enum MboTransitionReasonCode : uint8_t {
+        UNSPECIFIED = 0,
+        EXCESSIVE_FRAME_LOSS = 1,
+        EXCESSIVE_TRAFFIC_DELAY = 2,
+        INSUFFICIENT_BANDWIDTH = 3,
+        LOAD_BALANCING = 4,
+        LOW_RSSI = 5,
+        RX_EXCESSIVE_RETRIES = 6,
+        HIGH_INTERFERENCE = 7,
+        GRAY_ZONE = 8,
+        TRANSITION_TO_PREMIUM_AP = 9,
+    };
+
+    /**
+     *  MBO spec v1.2, 4.2.5 Table 16: MBO Cellular Data connection preference
+     *  attribute values. AP use this to indicate STA, its preference for the
+     *  STA to move from BSS to cellular network.
+     */
+    enum MboCellularDataConnectionPrefValue : uint8_t {
+        EXCLUDED = 0,
+        NOT_PREFERRED = 1,
+        /*
+         * 2-254 Reserved.
+         */
+        PREFERRED = 255,
+    };
+
+    /**
+     * Data retrieved from received BSS transition management request frame.
+     */
+    struct BssTmData {
+        /*
+         * Status code filled in BSS transition management response frame
+         */
+        BssTmStatusCode status;
+
+        /*
+         * Bitmask of BssTmDataFlagsMask
+         */
+        bitfield<BssTmDataFlagsMask> flags;
+
+        /*
+         * Duration for which STA shouldn't try to re-associate.
+         */
+        uint32_t assocRetryDelayMs;
+
+        /*
+         * Reason for BSS transition request.
+         */
+        MboTransitionReasonCode mboTransitionReason;
+
+        /*
+         * Cellular Data Connection preference value.
+         */
+        MboCellularDataConnectionPrefValue mboCellPreference;
+    };
+
+    /**
+     * Indicates pairwise master key (PMK) cache added event.
+     *
+     * @param expirationTimeInSec expiration time in seconds
+     * @param serializedEntry is serialized PMK cache entry, the content is
+     *              opaque for the framework and depends on the native implementation.
+     */
+    oneway onPmkCacheAdded(int64_t expirationTimeInSec, vec<uint8_t> serializedEntry);
+
+    /**
+     * Indicates a DPP success event.
+     */
+    oneway onDppSuccess(DppSuccessCode code);
+
+    /**
+     * Indicates a DPP progress event.
+     */
+    oneway onDppProgress_1_3(DppProgressCode code);
+
+    /**
+     * Indicates a DPP failure event.
+     *
+     * ssid: A string indicating the SSID for the AP that the Enrollee attempted to connect.
+     * channelList: A string containing a list of operating channels and operating classes
+     *     indicating the channels that the Enrollee scanned in attempting to discover the AP.
+     *     The list conforms to the following ABNF syntax:
+     *         channel-list2 = class-and-channels *(“,” class-and-channels)
+     *         class-and-channels = class “/” channel *(“,” channel)
+     *         class = 1*3DIGIT
+     *         channel = 1*3DIGIT
+     * bandList: A list of band parameters that are supported by the Enrollee expressed as the
+     *     Operating Class.
+     */
+    oneway onDppFailure_1_3(DppFailureCode code, string ssid, string channelList,
+        vec<uint16_t> bandList);
+
+    /**
+     * Indicates BTM request frame handling status.
+     *
+     * @param BssTmData Data retrieved from received BSS transition management
+     * request frame.
+     */
+    oneway onBssTmHandlingDone(BssTmData tmData);
+
+    /**
+     * 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);
+
+    /**
+     * Used to indicate a state change event on this particular iface. If this
+     * event is triggered by a particular network, the |SupplicantNetworkId|,
+     * |ssid|, |bssid| parameters must indicate the parameters of the network/AP
+     * which caused this state transition.
+     *
+     * @param newState New State of the interface. This must be one of the |State|
+     *        values above.
+     * @param bssid BSSID of the corresponding AP which caused this state
+     *        change event. This must be zero'ed if this event is not
+     *        specific to a particular network.
+     * @param id ID of the corresponding network which caused this
+     *        state change event. This must be invalid (UINT32_MAX) if this
+     *        event is not specific to a particular network.
+     * @param ssid SSID of the corresponding network which caused this state
+     *        change event. This must be empty if this event is not specific
+     *        to a particular network.
+     * @param filsHlpSent If FILS HLP IEs were included in this association.
+     */
+    oneway onStateChanged_1_3(State newState, Bssid bssid, SupplicantNetworkId id, Ssid ssid,
+        bool filsHlpSent);
+};
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
new file mode 100644
index 0000000..2505912
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant@1.3;
+
+import @1.0::ISupplicantStaNetwork;
+import @1.0::SupplicantStatus;
+import @1.2::ISupplicantStaNetwork;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * configuration it controls.
+ */
+interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork {
+    /**
+     * Possible mask of values for Proto param.
+     */
+    enum ProtoMask : @1.0::ISupplicantStaNetwork.ProtoMask {
+        WAPI = 1 << 2,
+    };
+
+    /**
+     * Possible mask of values for KeyMgmt param.
+     */
+    enum KeyMgmtMask : @1.2::ISupplicantStaNetwork.KeyMgmtMask {
+        /*
+         * WAPI Psk
+         */
+        WAPI_PSK = 1 << 12,
+        /**
+         * WAPI Cert
+         */
+        WAPI_CERT = 1 << 13,
+        /**
+         * FILS shared key authentication with sha-256
+         */
+        FILS_SHA256 = 1 << 18,
+        /**
+         * FILS shared key authentication with sha-384
+         */
+        FILS_SHA384 = 1 << 19,
+    };
+
+    /**
+     * Possible mask of values for PairwiseCipher param.
+     */
+    enum PairwiseCipherMask : @1.2::ISupplicantStaNetwork.PairwiseCipherMask {
+        /**
+         * SMS4 Pairwise Cipher
+         */
+        SMS4 = 1 << 7,
+    };
+
+    /**
+     * Possible mask of values for GroupCipher param.
+     */
+    enum GroupCipherMask : @1.2::ISupplicantStaNetwork.GroupCipherMask {
+        /**
+         * SMS4 Group Cipher
+         */
+        SMS4 = 1 << 7,
+    };
+
+    /**
+     * Possible mask of values for AuthAlg param.
+     */
+    enum AuthAlgMask : @1.0::ISupplicantStaNetwork.AuthAlgMask {
+        SAE = 1 << 4,
+    };
+
+    /**
+     * Set OCSP (Online Certificate Status Protocol) type for this network.
+     *
+     * @param ocspType value to set.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    setOcsp(OcspType ocspType) generates (SupplicantStatus status);
+
+    /**
+     * Get OCSP (Online Certificate Status Protocol) type for this network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     * @return ocspType ocsp type.
+     */
+    getOcsp() generates (SupplicantStatus status, OcspType ocspType);
+
+    /**
+     * Set key management mask for the network.
+     *
+     * @param keyMgmtMask value to set.
+     *        Combination of |KeyMgmtMask| values.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setKeyMgmt_1_3(bitfield<KeyMgmtMask> keyMgmtMask) generates (SupplicantStatus status);
+
+    /**
+     * Get the key mgmt mask set for the network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return keyMgmtMask Combination of |KeyMgmtMask| values.
+     */
+    getKeyMgmt_1_3() generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
+
+    /**
+     * Set proto mask for the network.
+     *
+     * @param protoMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setProto_1_3(bitfield<ProtoMask> protoMask) generates (SupplicantStatus status);
+
+    /**
+     * Get the proto mask set for the network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return protoMask Combination of |ProtoMask| values.
+     */
+    getProto_1_3() generates (SupplicantStatus status, bitfield<ProtoMask> protoMask);
+
+    /**
+     * Set group cipher mask for the network.
+     *
+     * @param groupCipherMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setGroupCipher_1_3(bitfield<GroupCipherMask> groupCipherMask)
+        generates (SupplicantStatus status);
+
+    /**
+     * Get the pairwise cipher mask set for the network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return pairwiseCipherMask Combination of |PairwiseCipherMask| values.
+     */
+    getPairwiseCipher_1_3()
+        generates (SupplicantStatus status, bitfield<PairwiseCipherMask> pairwiseCipherMask);
+
+    /**
+     * Set pairwise cipher mask for the network.
+     *
+     * @param pairwiseCipherMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setPairwiseCipher_1_3(bitfield<PairwiseCipherMask> pairwiseCipherMask)
+        generates (SupplicantStatus status);
+
+    /**
+     * Get the group cipher mask set for the network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return groupCipherMask Combination of |GroupCipherMask| values.
+     */
+    getGroupCipher_1_3()
+        generates (SupplicantStatus status, bitfield<GroupCipherMask> groupCipherMask);
+
+    /**
+     * Set WAPI certificate suite name for this network.
+     *
+     * @param suite value to set.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setWapiCertSuite(string suite) generates (SupplicantStatus status);
+
+    /**
+     * Get WAPI certificate suite name set for this network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return suite The name of a suite.
+     */
+    getWapiCertSuite() generates (SupplicantStatus status, string suite);
+
+    /**
+     * 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.
+     * @return status Status of the operation
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    setPmkCache(vec<uint8_t> serializedEntry) generates (SupplicantStatus status);
+
+    /**
+     * Set auth alg mask for the network.
+     *
+     * @param authAlgMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    setAuthAlg_1_3(bitfield<AuthAlgMask> authAlgMask) generates (SupplicantStatus status);
+
+    /**
+     * Get the auth alg mask set for the network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     * @return authAlgMask Combination of |AuthAlgMask| values.
+     */
+    getAuthAlg_1_3() generates (SupplicantStatus status, bitfield<AuthAlgMask> authAlgMask);
+
+    /**
+     * Enable Extensible Authentication (EAP) - Re-authentication Protocol (ERP) for this network.
+     *
+     * @param enable true to set, false otherwise.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    setEapErp(bool enable) generates (SupplicantStatus status);
+};
diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal
new file mode 100644
index 0000000..a4b2ff7
--- /dev/null
+++ b/wifi/supplicant/1.3/types.hal
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi.supplicant@1.3;
+
+import @1.2::DppProgressCode;
+import @1.2::DppFailureCode;
+
+import android.hardware.wifi@1.0::WifiChannelWidthInMhz;
+
+/**
+ * OcspType: The type of OCSP request.
+ */
+enum OcspType : uint32_t {
+    NONE,
+    REQUEST_CERT_STATUS,
+    REQUIRE_CERT_STATUS,
+    REQUIRE_ALL_CERTS_STATUS,
+};
+
+/**
+ * Wifi Technologies
+ */
+enum WifiTechnology : uint32_t {
+    UNKNOWN = 0,
+    /**
+     * For 802.11a/b/g
+     */
+    LEGACY = 1,
+    /**
+     * For 802.11n
+     */
+    HT = 2,
+    /**
+     * For 802.11ac
+     */
+    VHT = 3,
+    /**
+     * For 802.11ax
+     */
+    HE = 4,
+};
+
+/**
+ * Connection Capabilities supported by current network and device
+ */
+struct ConnectionCapabilities {
+    /**
+     * Wifi Technology
+     */
+    WifiTechnology technology;
+    /**
+     * channel bandwidth
+     */
+    WifiChannelWidthInMhz channelBandwidth;
+    /**
+     * max number of Tx spatial streams
+     */
+    uint32_t maxNumberTxSpatialStreams;
+    /**
+     * max number of Rx spatial streams
+     */
+    uint32_t maxNumberRxSpatialStreams;
+};
+
+/**
+ * WPA Driver capability.
+ */
+enum WpaDriverCapabilitiesMask : uint32_t {
+    /**
+     * Multi Band Operation.
+     */
+    MBO = 1 << 0,
+    /**
+     * Optimized Connectivity Experience.
+     */
+    OCE = 1 << 1,
+};
+
+/**
+ * DppProgressCode: Progress codes for DPP (Easy Connect)
+ */
+enum DppProgressCode : @1.2::DppProgressCode {
+    CONFIGURATION_SENT_WAITING_RESPONSE,
+    CONFIGURATION_ACCEPTED,
+};
+
+/**
+ * DppSuccessCode: Success codes for DPP (Easy Connect) Configurator
+ */
+enum DppSuccessCode : uint32_t {
+    /*
+     * Replaces @1.2::onDppSuccessConfigSent()
+     */
+    CONFIGURATION_SENT,
+    CONFIGURATION_APPLIED,
+};
+
+/**
+ * DppFailureCode: Error codes for DPP (Easy Connect)
+ */
+enum DppFailureCode : @1.2::DppFailureCode {
+    CONFIGURATION_REJECTED,
+    CANNOT_FIND_NETWORK,
+    ENROLLEE_AUTHENTICATION,
+};
diff --git a/wifi/1.3/default/OWNERS b/wifi/supplicant/1.3/vts/OWNERS
similarity index 100%
copy from wifi/1.3/default/OWNERS
copy to wifi/supplicant/1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.3/vts/functional/Android.bp b/wifi/supplicant/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..68c2929
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/Android.bp
@@ -0,0 +1,68 @@
+//
+// 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_library_static {
+    name: "VtsHalWifiSupplicantV1_3TargetTestUtil",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["supplicant_hidl_test_utils_1_3.cpp"],
+    export_include_dirs: [
+        ".",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_1TargetTestUtil",
+        "VtsHalWifiSupplicantV1_2TargetTestUtil",
+        "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",
+        "libwifi-system-iface",
+    ],
+}
+
+cc_test {
+    name: "VtsHalWifiSupplicantV1_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "supplicant_sta_iface_hidl_test.cpp",
+        "supplicant_sta_network_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_1TargetTestUtil",
+        "VtsHalWifiSupplicantV1_2TargetTestUtil",
+        "VtsHalWifiSupplicantV1_3TargetTestUtil",
+        "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",
+        "android.hardware.wifi@1.1",
+        "libgmock",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    disable_framework: true,
+}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp
new file mode 100644
index 0000000..424c107
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_3.h"
+
+using ::android::sp;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
+
+sp<ISupplicantStaIface> getSupplicantStaIface_1_3(
+    const android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>&
+        supplicant) {
+    return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant));
+}
+
+sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_3(
+    const android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>&
+        supplicant) {
+    return ISupplicantStaNetwork::castFrom(
+        createSupplicantStaNetwork(supplicant));
+}
+
+sp<ISupplicant> getSupplicant_1_3(const std::string& supplicant_instance_name,
+                                  bool isP2pOn) {
+    return ISupplicant::castFrom(
+        getSupplicant(supplicant_instance_name, isP2pOn));
+}
+
+bool isFilsSupported(sp<ISupplicantStaIface> sta_iface) {
+    uint32_t keyMgmtMask = 0;
+    sta_iface->getKeyMgmtCapabilities_1_3(
+        [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            keyMgmtMask = keyMgmtMaskInternal;
+        });
+
+    return (keyMgmtMask & (ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA256 |
+                           ISupplicantStaNetwork::KeyMgmtMask::FILS_SHA384));
+}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h
new file mode 100644
index 0000000..69fc598
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h
@@ -0,0 +1,37 @@
+/*
+ * 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 SUPPLICANT_HIDL_TEST_UTILS_1_3_H
+#define SUPPLICANT_HIDL_TEST_UTILS_1_3_H
+
+#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+
+android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface>
+getSupplicantStaIface_1_3(
+    const android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>&
+        supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork>
+createSupplicantStaNetwork_1_3(
+    const android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>&
+        supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicant>
+getSupplicant_1_3(const std::string& supplicant_instance_name, bool isP2pOn);
+bool isFilsSupported(
+    android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface>
+        sta_iface);
+#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_3_H */
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
new file mode 100644
index 0000000..12bd122
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -0,0 +1,584 @@
+/*
+ * 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 <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
+#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.2/types.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+#include <android/hardware/wifi/supplicant/1.3/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_3.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_2::DppAkm;
+using ::android::hardware::wifi::supplicant::V1_2::DppFailureCode;
+using ::android::hardware::wifi::supplicant::V1_2::DppNetRole;
+using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode;
+using ::android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities;
+using ::android::hardware::wifi::supplicant::V1_3::DppSuccessCode;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIfaceCallback;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
+using ::android::hardware::wifi::supplicant::V1_3::WpaDriverCapabilitiesMask;
+
+#define TIMEOUT_PERIOD 60
+class IfaceDppCallback;
+
+class SupplicantStaIfaceHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+   public:
+    virtual void SetUp() override {
+        wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+        supplicant_v1_3_instance_name_ = std::get<1>(GetParam());
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+
+        stopSupplicant(wifi_v1_0_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+                                             supplicant_v1_3_instance_name_);
+        supplicant_ =
+            getSupplicant_1_3(supplicant_v1_3_instance_name_, isP2pOn_);
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_iface_ = getSupplicantStaIface_1_3(supplicant_);
+        ASSERT_NE(sta_iface_.get(), nullptr);
+    }
+
+    virtual void TearDown() override {
+        stopSupplicant(wifi_v1_0_instance_name_);
+    }
+
+    int64_t pmkCacheExpirationTimeInSec;
+    std::vector<uint8_t> serializedPmkCacheEntry;
+
+    // Data retrieved from BSS transition management frame.
+    ISupplicantStaIfaceCallback::BssTmData tmData;
+
+    enum DppCallbackType {
+        ANY_CALLBACK = -2,
+        INVALID = -1,
+
+        EVENT_SUCCESS = 0,
+        EVENT_PROGRESS,
+        EVENT_FAILURE,
+    };
+
+    DppCallbackType dppCallbackType;
+    uint32_t code;
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    inline void notify() {
+        std::unique_lock<std::mutex> lock(mtx_);
+        count_++;
+        cv_.notify_one();
+    }
+
+    /* Test code calls this function to wait for data/event callback */
+    inline std::cv_status wait(DppCallbackType waitForCallbackType) {
+        std::unique_lock<std::mutex> lock(mtx_);
+        EXPECT_NE(INVALID, waitForCallbackType);  // can't ASSERT in a
+                                                  // non-void-returning method
+        auto now = std::chrono::system_clock::now();
+        std::cv_status status =
+            cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        return status;
+    }
+
+   private:
+    // synchronization objects
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int count_;
+
+   protected:
+    // ISupplicantStaIface object used for all tests in this fixture.
+    sp<ISupplicantStaIface> sta_iface_;
+    sp<ISupplicant> supplicant_;
+    bool isP2pOn_ = false;
+    std::string wifi_v1_0_instance_name_;
+    std::string supplicant_v1_3_instance_name_;
+
+    bool isDppSupported() {
+        uint32_t keyMgmtMask = 0;
+
+        // We need to first get the key management capabilities from the device.
+        // If DPP is not supported, we just pass the test.
+        sta_iface_->getKeyMgmtCapabilities_1_3(
+            [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                keyMgmtMask = keyMgmtMaskInternal;
+            });
+
+        if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) {
+            // DPP not supported
+            return false;
+        }
+
+        return true;
+    }
+};
+
+class IfaceCallback : public ISupplicantStaIfaceCallback {
+    Return<void> onNetworkAdded(uint32_t /* id */) override { return Void(); }
+    Return<void> onNetworkRemoved(uint32_t /* id */) override { return Void(); }
+    Return<void> onStateChanged(
+        ISupplicantStaIfaceCallback::State /* newState */,
+        const hidl_array<uint8_t, 6>& /*bssid */, uint32_t /* id */,
+        const hidl_vec<uint8_t>& /* ssid */) override {
+        return Void();
+    }
+    Return<void> onAnqpQueryDone(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        const ISupplicantStaIfaceCallback::AnqpData& /* data */,
+        const ISupplicantStaIfaceCallback::Hs20AnqpData& /* hs20Data */)
+        override {
+        return Void();
+    }
+    virtual Return<void> onHs20IconQueryDone(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        const hidl_string& /* fileName */,
+        const hidl_vec<uint8_t>& /* data */) override {
+        return Void();
+    }
+    virtual Return<void> onHs20SubscriptionRemediation(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        ISupplicantStaIfaceCallback::OsuMethod /* osuMethod */,
+        const hidl_string& /* url*/) override {
+        return Void();
+    }
+    Return<void> onHs20DeauthImminentNotice(
+        const hidl_array<uint8_t, 6>& /* bssid */, uint32_t /* reasonCode */,
+        uint32_t /* reAuthDelayInSec */,
+        const hidl_string& /* url */) override {
+        return Void();
+    }
+    Return<void> onDisconnected(const hidl_array<uint8_t, 6>& /* bssid */,
+                                bool /* locallyGenerated */,
+                                ISupplicantStaIfaceCallback::ReasonCode
+                                /* reasonCode */) override {
+        return Void();
+    }
+    Return<void> onAssociationRejected(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        ISupplicantStaIfaceCallback::StatusCode /* statusCode */,
+        bool /*timedOut */) override {
+        return Void();
+    }
+    Return<void> onAuthenticationTimeout(
+        const hidl_array<uint8_t, 6>& /* bssid */) override {
+        return Void();
+    }
+    Return<void> onBssidChanged(
+        ISupplicantStaIfaceCallback::BssidChangeReason /* reason */,
+        const hidl_array<uint8_t, 6>& /* bssid */) override {
+        return Void();
+    }
+    Return<void> onEapFailure() override { return Void(); }
+    Return<void> onEapFailure_1_1(
+        ISupplicantStaIfaceCallback::EapErrorCode /* eapErrorCode */) override {
+        return Void();
+    }
+    Return<void> onEapFailure_1_3(uint32_t /* eapErrorCode */) override {
+        return Void();
+    }
+    Return<void> onWpsEventSuccess() override { return Void(); }
+    Return<void> onWpsEventFail(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        ISupplicantStaIfaceCallback::WpsConfigError /* configError */,
+        ISupplicantStaIfaceCallback::WpsErrorIndication /* errorInd */)
+        override {
+        return Void();
+    }
+    Return<void> onWpsEventPbcOverlap() override { return Void(); }
+    Return<void> onExtRadioWorkStart(uint32_t /* id */) override {
+        return Void();
+    }
+    Return<void> onExtRadioWorkTimeout(uint32_t /* id*/) override {
+        return Void();
+    }
+    Return<void> onDppSuccessConfigReceived(
+        const hidl_vec<uint8_t>& /* ssid */, const hidl_string& /* password */,
+        const hidl_array<uint8_t, 32>& /* psk */,
+        DppAkm /* securityAkm */) override {
+        return Void();
+    }
+    Return<void> onDppSuccessConfigSent() override { return Void(); }
+    Return<void> onDppProgress(DppProgressCode /* code */) override {
+        return Void();
+    }
+    Return<void> onDppFailure(DppFailureCode /* code */) override {
+        return Void();
+    }
+    Return<void> onDppSuccess(DppSuccessCode /* code */) override {
+        return Void();
+    }
+    Return<void> onDppProgress_1_3(
+        ::android::hardware::wifi::supplicant::V1_3::DppProgressCode /* code */)
+        override {
+        return Void();
+    }
+    Return<void> onDppFailure_1_3(
+        ::android::hardware::wifi::supplicant::V1_3::DppFailureCode /* code */,
+        const hidl_string& /* ssid */, const hidl_string& /* channelList */,
+        const hidl_vec<uint16_t>& /* bandList */) override {
+        return Void();
+    }
+    Return<void> onPmkCacheAdded(
+        int64_t /* expirationTimeInSec */,
+        const hidl_vec<uint8_t>& /* serializedEntry */) override {
+        return Void();
+    }
+    Return<void> onBssTmHandlingDone(
+        const ISupplicantStaIfaceCallback::BssTmData& /* data */) override {
+        return Void();
+    }
+    Return<void> onStateChanged_1_3(
+        ISupplicantStaIfaceCallback::State /* newState */,
+        const hidl_array<uint8_t, 6>& /*bssid */, uint32_t /* id */,
+        const hidl_vec<uint8_t>& /* ssid */, bool /* filsHlpSent */) override {
+        return Void();
+    }
+};
+
+class IfacePmkCacheCallback : public IfaceCallback {
+    SupplicantStaIfaceHidlTest& parent_;
+    Return<void> onPmkCacheAdded(
+        int64_t expirationTimeInSec,
+        const hidl_vec<uint8_t>& serializedEntry) override {
+        parent_.pmkCacheExpirationTimeInSec = expirationTimeInSec;
+        parent_.serializedPmkCacheEntry = serializedEntry;
+        return Void();
+    }
+
+   public:
+    IfacePmkCacheCallback(SupplicantStaIfaceHidlTest& parent)
+        : parent_(parent) {}
+};
+
+class IfaceDppCallback : public IfaceCallback {
+    SupplicantStaIfaceHidlTest& parent_;
+    Return<void> onDppSuccess(DppSuccessCode code) override {
+        parent_.code = (uint32_t)code;
+        parent_.dppCallbackType =
+            SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_SUCCESS;
+        parent_.notify();
+        return Void();
+    }
+    Return<void> onDppProgress_1_3(
+        ::android::hardware::wifi::supplicant::V1_3::DppProgressCode code)
+        override {
+        parent_.code = (uint32_t)code;
+        parent_.dppCallbackType =
+            SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_PROGRESS;
+        parent_.notify();
+        return Void();
+    }
+    Return<void> onDppFailure_1_3(
+        ::android::hardware::wifi::supplicant::V1_3::DppFailureCode code,
+        const hidl_string& ssid __attribute__((unused)),
+        const hidl_string& channelList __attribute__((unused)),
+        const hidl_vec<uint16_t>& bandList __attribute__((unused))) override {
+        parent_.code = (uint32_t)code;
+        parent_.dppCallbackType =
+            SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE;
+        parent_.notify();
+        return Void();
+    }
+
+   public:
+    IfaceDppCallback(SupplicantStaIfaceHidlTest& parent) : parent_(parent){};
+};
+
+class IfaceBssTmHandlingDoneCallback : public IfaceCallback {
+    SupplicantStaIfaceHidlTest& parent_;
+    Return<void> onBssTmHandlingDone(
+        const ISupplicantStaIfaceCallback::BssTmData& data) override {
+        parent_.tmData = data;
+        return Void();
+    }
+
+   public:
+    IfaceBssTmHandlingDoneCallback(SupplicantStaIfaceHidlTest& parent)
+        : parent_(parent) {}
+};
+
+/*
+ * RegisterCallback_1_3
+ */
+TEST_P(SupplicantStaIfaceHidlTest, RegisterCallback_1_3) {
+    sta_iface_->registerCallback_1_3(
+        new IfaceCallback(), [](const SupplicantStatus& status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
+
+/*
+ * getConnectionCapabilities
+ */
+TEST_P(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) {
+    sta_iface_->getConnectionCapabilities(
+        [&](const SupplicantStatus& status,
+            ConnectionCapabilities /* capabilities */) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
+
+/*
+ * GetWpaDriverCapabilities
+ */
+TEST_P(SupplicantStaIfaceHidlTest, GetWpaDriverCapabilities) {
+    sta_iface_->getWpaDriverCapabilities(
+        [&](const SupplicantStatus& status, uint32_t) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
+
+/*
+ * SetMboCellularDataStatus
+ */
+TEST_P(SupplicantStaIfaceHidlTest, SetMboCellularDataStatus) {
+    uint32_t driverCapMask = 0;
+
+    // Get MBO support from the device.
+    sta_iface_->getWpaDriverCapabilities(
+        [&](const SupplicantStatus& status, uint32_t driverCapMaskInternal) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+
+            driverCapMask = driverCapMaskInternal;
+        });
+
+    SupplicantStatusCode expectedStatusCode =
+        (driverCapMask & WpaDriverCapabilitiesMask::MBO)
+            ? SupplicantStatusCode::SUCCESS
+            : SupplicantStatusCode::FAILURE_UNKNOWN;
+
+    sta_iface_->setMboCellularDataStatus(
+        true, [expectedStatusCode](const SupplicantStatus& status) {
+            EXPECT_EQ(expectedStatusCode, status.code);
+        });
+}
+
+/*
+ * GetKeyMgmtCapabilities_1_3
+ */
+TEST_P(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities_1_3) {
+    sta_iface_->getKeyMgmtCapabilities_1_3([&](const SupplicantStatus& status,
+                                               uint32_t keyMgmtMask) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        } else {
+            // Even though capabilities vary, these two are always set in HAL
+            // v1.3
+            EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::NONE);
+            EXPECT_TRUE(keyMgmtMask &
+                        ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X);
+        }
+    });
+}
+
+/*
+ * StartDppEnrolleeInitiator
+ */
+TEST_P(SupplicantStaIfaceHidlTest, StartDppEnrolleeInitiator) {
+    // We need to first get the key management capabilities from the device.
+    // If DPP is not supported, we just pass the test.
+    if (!isDppSupported()) {
+        // DPP not supported
+        return;
+    }
+
+    hidl_string uri =
+        "DPP:C:81/1,117/"
+        "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+        "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
+    uint32_t peer_id = 0;
+
+    // Register callbacks
+    sta_iface_->registerCallback_1_3(
+        new IfaceDppCallback(*this), [](const SupplicantStatus& status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+
+    // Add a peer URI
+    sta_iface_->addDppPeerUri(
+        uri, [&](const SupplicantStatus& status, uint32_t id) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            EXPECT_NE(0, id);
+            EXPECT_NE(-1, id);
+
+            peer_id = id;
+        });
+
+    // Start DPP as Enrollee-Initiator. Since this operation requires two
+    // devices, we start the operation and expect a timeout.
+    sta_iface_->startDppEnrolleeInitiator(
+        peer_id, 0, [&](const SupplicantStatus& status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+
+    // Wait for the timeout callback
+    ASSERT_EQ(std::cv_status::no_timeout,
+              wait(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE));
+    ASSERT_EQ(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE,
+              dppCallbackType);
+
+    // ...and then remove the peer URI.
+    sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) {
+        EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+    });
+}
+
+/*
+ * StartDppConfiguratorInitiator
+ */
+TEST_P(SupplicantStaIfaceHidlTest, StartDppConfiguratorInitiator) {
+    // We need to first get the key management capabilities from the device.
+    // If DPP is not supported, we just pass the test.
+    if (!isDppSupported()) {
+        // DPP not supported
+        return;
+    }
+
+    hidl_string uri =
+        "DPP:C:81/1,117/"
+        "40;M:48d6d5bd1de1;I:G1197843;K:MDkwEwYHKoZIzj0CAQYIKoZIzj"
+        "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
+    uint32_t peer_id = 0;
+
+    // Register callbacks
+    sta_iface_->registerCallback_1_3(
+        new IfaceDppCallback(*this), [](const SupplicantStatus& status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+
+    // Add a peer URI
+    sta_iface_->addDppPeerUri(
+        uri, [&](const SupplicantStatus& status, uint32_t id) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            EXPECT_NE(0, id);
+            EXPECT_NE(-1, id);
+
+            peer_id = id;
+        });
+
+    std::string ssid =
+        "6D795F746573745F73736964";  // 'my_test_ssid' encoded in hex
+    std::string password = "746F70736563726574";  // 'topsecret' encoded in hex
+
+    // Start DPP as Configurator-Initiator. Since this operation requires two
+    // devices, we start the operation and expect a timeout.
+    sta_iface_->startDppConfiguratorInitiator(
+        peer_id, 0, ssid, password, NULL, DppNetRole::STA, DppAkm::PSK,
+        [&](const SupplicantStatus& status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+
+    // Wait for the timeout callback
+    ASSERT_EQ(std::cv_status::no_timeout,
+              wait(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE));
+    ASSERT_EQ(SupplicantStaIfaceHidlTest::DppCallbackType::EVENT_FAILURE,
+              dppCallbackType);
+
+    // ...and then remove the peer URI.
+    sta_iface_->removeDppUri(peer_id, [&](const SupplicantStatus& status) {
+        EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+    });
+}
+
+/*
+ * FilsHlpAddRequest
+ */
+TEST_P(SupplicantStaIfaceHidlTest, FilsHlpAddRequest) {
+    if (!isFilsSupported(sta_iface_)) {
+        GTEST_SKIP()
+            << "Skipping test since driver/supplicant doesn't support FILS";
+    }
+    uint8_t destMacAddr[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
+    std::vector<uint8_t> pktBuffer = {
+        0x08, 0x00, 0x45, 0x10, 0x01, 0x3a, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,
+        0x39, 0xa4, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x44,
+        0x00, 0x43, 0x01, 0x26, 0x77, 0x1e, 0x01, 0x01, 0x06, 0x00, 0x81, 0xf9,
+        0xf7, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xc3,
+        0x65, 0xca, 0x34, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x01, 0x3d,
+        0x07, 0x01, 0x86, 0xc3, 0x65, 0xca, 0x34, 0x63, 0x39, 0x02, 0x05, 0xdc,
+        0x3c, 0x0e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2d, 0x64, 0x68,
+        0x63, 0x70, 0x2d, 0x52, 0x37, 0x0a, 0x01, 0x03, 0x06, 0x0f, 0x1a, 0x1c,
+        0x33, 0x3a, 0x3b, 0x2b, 0xff, 0x00};
+
+    sta_iface_->filsHlpAddRequest(
+        destMacAddr, pktBuffer, [](const SupplicantStatus& status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
+
+/*
+ * FilsHlpFlushRequest
+ */
+TEST_P(SupplicantStaIfaceHidlTest, FilsHlpFlushRequest) {
+    if (!isFilsSupported(sta_iface_)) {
+        GTEST_SKIP()
+            << "Skipping test since driver/supplicant doesn't support FILS";
+    }
+
+    sta_iface_->filsHlpFlushRequest([](const SupplicantStatus& status) {
+        EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+    });
+}
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaIfaceHidlTest,
+    testing::Combine(
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::V1_0::IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::supplicant::V1_3::ISupplicant::
+                descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
new file mode 100644
index 0000000..25091a5
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -0,0 +1,355 @@
+/*
+ * 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 <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_3.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
+using ::android::hardware::wifi::supplicant::V1_3::OcspType;
+namespace {
+constexpr OcspType kTestOcspType = OcspType::REQUEST_CERT_STATUS;
+constexpr OcspType kTestInvalidOcspType = (OcspType)-1;
+}  // namespace
+
+class SupplicantStaNetworkHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+   public:
+    virtual void SetUp() override {
+        wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+        supplicant_v1_3_instance_name_ = std::get<1>(GetParam());
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+
+        stopSupplicant(wifi_v1_0_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+                                             supplicant_v1_3_instance_name_);
+        supplicant_ =
+            getSupplicant_1_3(supplicant_v1_3_instance_name_, isP2pOn_);
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_iface_ = getSupplicantStaIface_1_3(supplicant_);
+        ASSERT_NE(nullptr, sta_iface_.get());
+        sta_network_ = createSupplicantStaNetwork_1_3(supplicant_);
+        ASSERT_NE(sta_network_.get(), nullptr);
+    }
+
+    virtual void TearDown() override {
+        stopSupplicant(wifi_v1_0_instance_name_);
+    }
+
+   protected:
+    sp<ISupplicantStaIface> sta_iface_;
+    // ISupplicantStaNetwork object used for all tests in this fixture.
+    sp<ISupplicantStaNetwork> sta_network_;
+    sp<ISupplicant> supplicant_;
+    bool isP2pOn_ = false;
+    std::string wifi_v1_0_instance_name_;
+    std::string supplicant_v1_3_instance_name_;
+
+    bool isWapiSupported() {
+        uint32_t keyMgmtMask = 0;
+
+        // We need to first get the key management capabilities from the device.
+        // If WAPI is not supported, we just pass the test.
+        sta_iface_->getKeyMgmtCapabilities_1_3(
+            [&](const SupplicantStatus &status, uint32_t keyMgmtMaskInternal) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                keyMgmtMask = keyMgmtMaskInternal;
+            });
+
+        if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK)) {
+            // WAPI not supported
+            return false;
+        }
+
+        return true;
+    }
+};
+
+/*
+ * SetGetOcsp
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetGetOcsp) {
+    OcspType testOcspType = kTestOcspType;
+
+    sta_network_->setOcsp(testOcspType, [](const SupplicantStatus &status) {
+        EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+    });
+
+    sta_network_->setOcsp(
+        kTestInvalidOcspType, [](const SupplicantStatus &status) {
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_ARGS_INVALID, status.code);
+        });
+
+    sta_network_->getOcsp(
+        [testOcspType](const SupplicantStatus &status, OcspType ocspType) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            EXPECT_EQ(testOcspType, ocspType);
+        });
+}
+
+/*
+ * SetPmkCacheEntry
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetPmkCache) {
+    uint8_t bytes[128] = {0};
+    std::vector<uint8_t> serializedEntry(bytes, bytes + sizeof(bytes));
+
+    sta_network_->setPmkCache(
+        serializedEntry, [](const SupplicantStatus &status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
+
+/*
+ * SetGetKeyMgmt_1_3, check new WAPI proto support
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_3) {
+    uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK;
+
+    sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        }
+    });
+
+    sta_network_->getKeyMgmt_1_3(
+        [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            } else {
+                EXPECT_EQ(keyMgmtOut, keyMgmt);
+            }
+        });
+
+    keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_CERT;
+    sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        }
+    });
+
+    sta_network_->getKeyMgmt_1_3(
+        [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            } else {
+                EXPECT_EQ(keyMgmtOut, keyMgmt);
+            }
+        });
+}
+
+/*
+ * SetGetProto_1_3, check new WAPI proto support
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetGetProto_1_3) {
+    uint32_t wapiProto = (uint32_t)ISupplicantStaNetwork::ProtoMask::WAPI;
+    sta_network_->setProto(wapiProto, [](const SupplicantStatus &status) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        }
+    });
+    sta_network_->getProto([&](const SupplicantStatus &status, uint32_t proto) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        } else {
+            EXPECT_EQ(proto, wapiProto);
+        }
+    });
+}
+
+/*
+ * SetGetGroupCipher_1_3, check new WAPI support
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_3) {
+    uint32_t groupCipher =
+        (uint32_t)ISupplicantStaNetwork::GroupCipherMask::SMS4;
+
+    sta_network_->setGroupCipher_1_3(
+        groupCipher, [](const SupplicantStatus &status) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            }
+        });
+
+    sta_network_->getGroupCipher_1_3(
+        [&groupCipher](const SupplicantStatus &status,
+                       uint32_t groupCipherOut) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            } else {
+                EXPECT_EQ(groupCipherOut, groupCipher);
+            }
+        });
+}
+
+/*
+ * SetGetPairwiseCipher_1_3, check new WAPI support
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_3) {
+    uint32_t pairwiseCipher =
+        (uint32_t)ISupplicantStaNetwork::PairwiseCipherMask::SMS4;
+
+    sta_network_->setPairwiseCipher_1_3(
+        pairwiseCipher, [](const SupplicantStatus &status) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            }
+        });
+
+    sta_network_->getPairwiseCipher_1_3(
+        [&pairwiseCipher](const SupplicantStatus &status,
+                          uint32_t pairwiseCipherOut) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            } else {
+                EXPECT_EQ(pairwiseCipherOut, pairwiseCipher);
+            }
+        });
+}
+
+/*
+ * SetGetWapiCertSuite
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetGetWapiCertSuite) {
+    hidl_string testWapiCertSuite = "suite";
+
+    if (isWapiSupported()) {
+        sta_network_->setWapiCertSuite(
+            testWapiCertSuite, [](const SupplicantStatus &status) {
+                if (SupplicantStatusCode::SUCCESS != status.code) {
+                    // for unsupport case
+                    EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN,
+                              status.code);
+                }
+            });
+
+        sta_network_->getWapiCertSuite([testWapiCertSuite](
+                                           const SupplicantStatus &status,
+                                           const hidl_string &wapiCertSuite) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            } else {
+                EXPECT_EQ(testWapiCertSuite, wapiCertSuite);
+            }
+        });
+    } else {
+        sta_network_->setWapiCertSuite(
+            testWapiCertSuite, [](const SupplicantStatus &status) {
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            });
+
+        sta_network_->getWapiCertSuite(
+            [testWapiCertSuite](const SupplicantStatus &status,
+                                const hidl_string &wapiCertSuite __unused) {
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            });
+    }
+}
+
+/*
+ * SetGetWapiPsk
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetGetWapiPsk) {
+    uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK;
+    char kTestPskPassphrase[] = "\"123456780abcdef0123456780abcdef0deadbeef\"";
+    char kTestPskHex[] = "12345678";
+
+    if (!isWapiSupported()) {
+        GTEST_SKIP() << "Skipping test since WAPI is not supported.";
+    }
+
+    sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        }
+    });
+
+    sta_network_->setPskPassphrase(
+        kTestPskPassphrase, [](const SupplicantStatus &status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+
+    sta_network_->getPskPassphrase(
+        [&](const SupplicantStatus &status, const hidl_string &psk) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            EXPECT_EQ(kTestPskPassphrase, std::string(psk.c_str()));
+        });
+
+    sta_network_->setPskPassphrase(
+        kTestPskHex, [](const SupplicantStatus &status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+
+    sta_network_->getPskPassphrase(
+        [&](const SupplicantStatus &status, const hidl_string &psk) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            EXPECT_EQ(kTestPskHex, std::string(psk.c_str()));
+        });
+}
+
+/*
+ * SetEapErp
+ */
+TEST_P(SupplicantStaNetworkHidlTest, SetEapErp) {
+    if (!isFilsSupported(sta_iface_)) {
+        GTEST_SKIP()
+            << "Skipping test since driver/supplicant doesn't support FILS";
+    }
+
+    sta_network_->setEapErp(true, [](const SupplicantStatus &status) {
+        EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+    });
+}
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaNetworkHidlTest,
+    testing::Combine(
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::V1_0::IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::supplicant::V1_3::ISupplicant::
+                descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);