[automerger skipped] Merge "Add NNAPI loop timeout VTS test" am: 2225653ff1 am: fbcf4ca055 -s ours
am skip reason: Change-Id I642772d3c00c12d72380598d9d86743706179d72 with SHA-1 cc873aee8f is in history

Change-Id: I01930ec9e93cd791167a948ee930df5b76718918
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/audio/6.0/Android.bp b/audio/6.0/Android.bp
index dc6bb98..16abc52 100644
--- a/audio/6.0/Android.bp
+++ b/audio/6.0/Android.bp
@@ -15,6 +15,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..de17d73
--- /dev/null
+++ b/audio/6.0/IStreamOutEventCallback.hal
@@ -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.
+ */
+
+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.
+     *
+     * @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. See
+     *     `system/media/audio_utils/include/audio_utils/Metadata.h` for
+     *     more details.
+     */
+    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/Android.bp b/audio/core/all-versions/default/Android.bp
index 6f18d1d..b8b7fee 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -26,6 +26,7 @@
         "libhardware",
         "libhidlbase",
         "liblog",
+        "libmedia_helper",
         "libutils",
         "android.hardware.audio.common-util",
     ],
@@ -37,10 +38,6 @@
         "libhardware_headers",
         "libmedia_headers",
     ],
-
-    whole_static_libs: [
-        "libmedia_helper",
-    ],
 }
 
 cc_library_shared {
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..150d641 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>
@@ -582,6 +584,65 @@
 }
 #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);
+    switch (event) {
+        case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED: {
+            hidl_vec<uint8_t> audioMetadata;
+            audioMetadata.setToExternal((uint8_t*)param, strlen((char*)param));
+            eventCallback->onCodecFormatChanged(audioMetadata);
+        } break;
+        default:
+            ALOGW("%s unknown event %d", __func__, event);
+            break;
+    }
+    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 2afbbb8..b40a329 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -181,3 +181,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/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index d3545c8..715f376 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -19,12 +19,13 @@
     defaults: ["VtsHalTargetTestDefaults"],
     static_libs: [
         "android.hardware.audio.common.test.utility",
+        "libaudiofoundation",
         "libaudiopolicycomponents",
         "libmedia_helper",
         "libxml2",
     ],
     shared_libs: [
-        "libaudiofoundation",
+        "libbinder",
         "libfmq",
     ],
     header_libs: [
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index d0d39e8..b77aec9 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -140,6 +140,11 @@
 class HidlTest : public HidlTestBase {
   public:
     virtual ~HidlTest() = default;
+    // public access to avoid annoyances when using this method in template classes
+    // derived from test classes
+    sp<IDevice> getDevice() const {
+        return DeviceManager::getInstance().get(getFactoryName(), getDeviceName());
+    }
 
   protected:
     // Factory and device name getters to be overridden in subclasses.
@@ -149,9 +154,6 @@
     sp<IDevicesFactory> getDevicesFactory() const {
         return DevicesFactoryManager::getInstance().get(getFactoryName());
     }
-    sp<IDevice> getDevice() const {
-        return DeviceManager::getInstance().get(getFactoryName(), getDeviceName());
-    }
     bool resetDevice() const {
         return DeviceManager::getInstance().reset(getFactoryName(), getDeviceName());
     }
@@ -419,7 +421,8 @@
         ASSERT_TRUE(getDevice() != nullptr);
     }
 
-  protected:
+    // public access to avoid annoyances when using this method in template classes
+    // derived from test classes
     sp<IPrimaryDevice> getDevice() const {
         return DeviceManager::getInstance().getPrimary(getFactoryName());
     }
@@ -450,15 +453,15 @@
     /** Test a property getter and setter.
      *  The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL.
      */
-    template <Optionality optionality = REQUIRED, class Getter, class Setter>
-    void testAccessors(const string& propertyName, const Initial expectedInitial,
-                       list<Property> valuesToTest, Setter setter, Getter getter,
-                       const vector<Property>& invalidValues = {}) {
+    template <Optionality optionality = REQUIRED, class IUTGetter, class Getter, class Setter>
+    void testAccessors(IUTGetter iutGetter, const string& propertyName,
+                       const Initial expectedInitial, list<Property> valuesToTest, Setter setter,
+                       Getter getter, const vector<Property>& invalidValues = {}) {
         const auto expectedResults = {Result::OK,
                                       optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
 
         Property initialValue = expectedInitial.value;
-        ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, initialValue)));
+        ASSERT_OK(((this->*iutGetter)().get()->*getter)(returnIn(res, initialValue)));
         ASSERT_RESULT(expectedResults, res);
         if (res == Result::OK && expectedInitial.check == REQUIRED) {
             EXPECT_EQ(expectedInitial.value, initialValue);
@@ -469,7 +472,7 @@
         for (Property setValue : valuesToTest) {
             SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
                          testing::PrintToString(setValue));
-            auto ret = (BaseTestClass::getDevice().get()->*setter)(setValue);
+            auto ret = ((this->*iutGetter)().get()->*setter)(setValue);
             ASSERT_RESULT(expectedResults, ret);
             if (ret == Result::NOT_SUPPORTED) {
                 doc::partialTest(propertyName + " setter is not supported");
@@ -477,7 +480,7 @@
             }
             Property getValue;
             // Make sure the getter returns the same value just set
-            ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, getValue)));
+            ASSERT_OK(((this->*iutGetter)().get()->*getter)(returnIn(res, getValue)));
             ASSERT_RESULT(expectedResults, res);
             if (res == Result::NOT_SUPPORTED) {
                 doc::partialTest(propertyName + " getter is not supported");
@@ -490,11 +493,18 @@
             SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
                          testing::PrintToString(invalidValue));
             EXPECT_RESULT(invalidArgsOrNotSupported,
-                          (BaseTestClass::getDevice().get()->*setter)(invalidValue));
+                          ((this->*iutGetter)().get()->*setter)(invalidValue));
         }
 
         // Restore initial value
-        EXPECT_RESULT(expectedResults, (BaseTestClass::getDevice().get()->*setter)(initialValue));
+        EXPECT_RESULT(expectedResults, ((this->*iutGetter)().get()->*setter)(initialValue));
+    }
+    template <Optionality optionality = REQUIRED, class Getter, class Setter>
+    void testAccessors(const string& propertyName, const Initial expectedInitial,
+                       list<Property> valuesToTest, Setter setter, Getter getter,
+                       const vector<Property>& invalidValues = {}) {
+        testAccessors<optionality>(&BaseTestClass::getDevice, propertyName, expectedInitial,
+                                   valuesToTest, setter, getter, invalidValues);
     }
 };
 
@@ -872,6 +882,11 @@
 
 template <class Stream>
 class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
+  public:
+    // public access to avoid annoyances when using this method in template classes
+    // derived from test classes
+    sp<Stream> getStream() const { return stream; }
+
   protected:
     OpenStreamTest() : AudioHidlTestWithDeviceConfigParameter(), helper(stream) {}
     template <class Open>
diff --git a/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/2.0/Android.bp b/automotive/audiocontrol/2.0/Android.bp
new file mode 100644
index 0000000..2a9f849
--- /dev/null
+++ b/automotive/audiocontrol/2.0/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.audiocontrol@2.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IAudioControl.hal",
+        "ICloseHandle.hal",
+        "IFocusListener.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+        "android.hardware.audio.common@6.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..6505e34
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp
@@ -0,0 +1,60 @@
+#include "AudioControl.h"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "CloseHandle.h"
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+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) {
+    // For completeness, lets bounds check the input...
+    if (isValidValue(value)) {
+        LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
+    } else {
+        // Just log in this default mock implementation
+        LOG(INFO) << "Balance set to " << value;
+    }
+    return Void();
+}
+
+Return<void> AudioControl::setFadeTowardFront(float value) {
+    // For completeness, lets bounds check the input...
+    if (isValidValue(value)) {
+        LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
+    } else {
+        // Just log in this default mock implementation
+        LOG(INFO) << "Fader set to " << value;
+    }
+    return Void();
+}
+
+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();
+}
+
+}  // 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..475a693
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/AudioControl.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.
+ */
+
+#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;
+
+    // Implementation details
+    AudioControl();
+
+  private:
+    sp<IFocusListener> mFocusListener;
+    static bool isValidValue(float value) { return (value > 1.0f) || (value < -1.0f); }
+};
+
+}  // 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..65b0988
--- /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 : uint32_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..2221e66
--- /dev/null
+++ b/automotive/can/1.0/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.can@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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..ee2e92b
--- /dev/null
+++ b/automotive/can/1.0/default/Android.bp
@@ -0,0 +1,55 @@
+//
+// 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",
+    ],
+}
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
new file mode 100644
index 0000000..9f704c1
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -0,0 +1,346 @@
+/*
+ * 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) {
+    // TODO(b/144458917) add testing for this to VTS tests
+    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";
+        // TODO(b/144458917) consider providing different values for isFatal, depending on error
+        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..d15905d
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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) {
+        LOG(ERROR) << "Failed to get the name of the created device: " << strerror(errno);
+        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()) {
+        LOG(ERROR) << "SLCAN Failed to open " << mUartName << ": " << strerror(errno);
+        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) {
+        LOG(ERROR) << "Failed to read attrs of" << mUartName << ": " << strerror(errno);
+        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) {
+        LOG(ERROR) << "Failed to read serial settings from " << mUartName << ": "
+                   << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+    // set low latency mode
+    serialSettings.flags |= ASYNC_LOW_LATENCY;
+    // apply serial settings
+    if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) {
+        LOG(ERROR) << "Failed to set low latency mode on " << mUartName << ": " << strerror(errno);
+        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) {
+        LOG(ERROR) << "Failed to apply terminal settings to " << mUartName << ": "
+                   << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // apply speed setting for CAN
+    if (write(mFd.get(), canBitrateCommand->c_str(), canBitrateCommand->length()) <= 0) {
+        LOG(ERROR) << "Failed to apply CAN bitrate: " << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // set open flag TODO: also support listen only
+    if (write(mFd.get(), slcanprotocol::kOpenCommand.c_str(),
+              slcanprotocol::kOpenCommand.length()) <= 0) {
+        LOG(ERROR) << "Failed to set open flag: " << strerror(errno);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    // set line discipline to slcan
+    if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) {
+        LOG(ERROR) << "Failed to set line discipline to slcan: " << strerror(errno);
+        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..0700c77
--- /dev/null
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 <regex>
+
+namespace android::hardware::automotive::can::V1_0::implementation {
+
+using IfId = ICanController::BusConfig::InterfaceId;
+using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator;
+
+Return<void> CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) {
+    _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN,
+              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);
+}
+
+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;
+
+    if (config.interfaceId.getDiscriminator() == IfIdDisc::socketcan) {
+        // TODO(b/142654031): support serialno
+        auto& socketcan = config.interfaceId.socketcan();
+        if (socketcan.getDiscriminator() == IfId::Socketcan::hidl_discriminator::ifname) {
+            busService = new CanBusNative(socketcan.ifname(), config.bitrate);
+        } else {
+            return ICanController::Result::BAD_INTERFACE_ID;
+        }
+    } else if (config.interfaceId.getDiscriminator() == IfIdDisc::virtualif) {
+        busService = new CanBusVirtual(config.interfaceId.virtualif().ifname);
+    } else if (config.interfaceId.getDiscriminator() == IfIdDisc::slcan) {
+        // TODO(b/142654031): support serialno
+        auto& slcan = config.interfaceId.slcan();
+        if (slcan.getDiscriminator() == IfId::Slcan::hidl_discriminator::ttyname) {
+            busService = new CanBusSlcan(slcan.ttyname(), config.bitrate);
+        } else {
+            return ICanController::Result::BAD_INTERFACE_ID;
+        }
+    } 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..86ccc0e
--- /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) {
+        LOG(DEBUG) << "CanSocket send failed: " << errno;
+        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) {
+            LOG(ERROR) << "Select failed: " << errno;
+            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;
+            LOG(ERROR) << "Failed to read CAN packet: " << strerror(errno) << " (" << errno << ")";
+            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/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..6a7f506
--- /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()) {
+        LOG(ERROR) << "Can't open Netlink socket: " << errno;
+        mFailed = true;
+        return;
+    }
+
+    struct sockaddr_nl sa = {};
+    sa.nl_family = AF_NETLINK;
+
+    if (bind(mFd.get(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)) < 0) {
+        LOG(ERROR) << "Can't bind Netlink socket: " << errno;
+        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) {
+        LOG(ERROR) << "Can't send Netlink message: " << errno;
+        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) {
+        LOG(ERROR) << "Failed to receive Netlink message: " << errno;
+        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..06d45d3
--- /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) {
+        LOG(ERROR) << "Can't receive error frames, CAN setsockpt failed: " << strerror(errno);
+        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..aee8205
--- /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) {
+        LOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed: " << errno;
+        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..21f364b
--- /dev/null
+++ b/automotive/can/1.0/tools/Android.bp
@@ -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.
+//
+
+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",
+    ],
+}
+
+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",
+    ],
+}
+
+cc_binary {
+    name: "canhalsend",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "canhalsend.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+    ],
+}
diff --git a/automotive/can/1.0/tools/canhalctrl.cpp b/automotive/can/1.0/tools/canhalctrl.cpp
new file mode 100644
index 0000000..33755bf
--- /dev/null
+++ b/automotive/can/1.0/tools/canhalctrl.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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/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 {
+
+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 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));
+    if (services.size() == 0) {
+        std::cerr << "No ICanController services registered (missing privileges?)" << std::endl;
+        exit(-1);
+    }
+    return services;
+}
+
+static 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);
+}
+
+static int up(const std::string& busName, ICanController::InterfaceType type,
+              const std::string& interface, uint32_t bitrate) {
+    bool anySupported = false;
+    for (auto&& service : getControlServices()) {
+        auto ctrl = ICanController::getService(service);
+        if (ctrl == nullptr) {
+            std::cerr << "Couldn't open ICanController/" << service;
+            continue;
+        }
+
+        if (!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) {
+            auto idx = std::stol(interface);
+            if (idx < 0 || idx > UINT8_MAX) {
+                std::cerr << "Interface index out of range: " << idx;
+                return -1;
+            }
+            config.interfaceId.indexed({uint8_t(idx)});
+        } else {
+            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 : 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;
+        }
+
+        long long bitrate = 0;
+        if (argc == 4) {
+            bitrate = std::stoll(argv[3]);
+        }
+
+        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..7e6833a
--- /dev/null
+++ b/automotive/can/1.0/tools/canhalsend.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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/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 << "cansend - 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 be published" << std::endl;
+    std::cerr << " can id - such as 1a5" << std::endl;
+    std::cerr << " data - such as deadbeef or 010203" << 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, V1_0::CanMessageId msgid,
+                   std::vector<uint8_t> payload) {
+    auto bus = tryOpen(busname);
+    if (bus == nullptr) {
+        std::cerr << "Bus " << busname << " is not available" << std::endl;
+        return -1;
+    }
+
+    V1_0::CanMessage msg = {};
+    msg.id = msgid;
+    msg.payload = payload;
+
+    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<std::tuple<V1_0::CanMessageId, std::vector<uint8_t>>> 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);
+
+    size_t idx = 0;
+    V1_0::CanMessageId msgid = std::stoi(msgidStr, &idx, 16);
+    if (msgidStr[idx] != '\0') return std::nullopt;
+
+    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);
+        payload.emplace_back(std::stoi(byteStr, &idx, 16));
+        if (byteStr[idx] != '\0') return std::nullopt;
+    }
+
+    return {{msgid, payload}};
+}
+
+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;
+    }
+    const auto [msgid, payload] = *canmsg;
+
+    return cansend(busname, msgid, payload);
+}
+
+}  // 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/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..e3e770b
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/Android.bp
@@ -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.
+//
+
+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"],
+}
+
+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.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/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 47702fd..9f7cd3f 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-core"],
     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..f9bccef
--- /dev/null
+++ b/automotive/evs/1.1/Android.bp
@@ -0,0 +1,28 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.evs@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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..38e6c42
--- /dev/null
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -0,0 +1,218 @@
+/*
+ * 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);
+};
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..d843167
--- /dev/null
+++ b/automotive/evs/1.1/default/Android.bp
@@ -0,0 +1,55 @@
+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",
+    ],
+}
+
+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..5196c95
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -0,0 +1,716 @@
+/*
+ * 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();
+}
+
+
+
+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..0fa83b4
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -0,0 +1,161 @@
+/*
+ * 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;
+
+    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/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..b34e7e7
--- /dev/null
+++ b/automotive/evs/1.1/types.hal
@@ -0,0 +1,370 @@
+/*
+ * 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;
+
+    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,
+};
+
+/**
+ * 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..cde8048
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -0,0 +1,2327 @@
+/*
+ * 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 <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include <android/log.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 <system/camera_metadata.h>
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.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_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);
+
+        mIsHwModule = pEnumerator->isHardware();
+    }
+
+    virtual void TearDown() override {
+        // Attempt to close any active camera
+        for (auto &&c : activeCameras) {
+            sp<IEvsCamera_1_1> cam = c.promote();
+            if (cam != nullptr) {
+                pEnumerator->closeCamera(cam);
+            }
+        }
+    }
+
+protected:
+    void loadCameraList() {
+        // SetUp() must run first!
+        assert(pEnumerator != nullptr);
+
+        // Get the camera list
+        pEnumerator->getCameraList_1_1(
+            [this](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);
+                }
+            }
+        );
+    }
+
+    void loadUltrasonicsArrayList() {
+        // SetUp() must run first!
+        assert(pEnumerator != nullptr);
+
+        // Get the ultrasonics array list
+        pEnumerator->getUltrasonicsArrayList([this](hidl_vec<UltrasonicsArrayDesc> ultraList) {
+            ALOGI("Ultrasonics array list callback received %zu arrays", ultraList.size());
+            ultrasonicsArraysInfo.reserve(ultraList.size());
+            for (auto&& ultraArray : ultraList) {
+                ALOGI("Found ultrasonics array %s", ultraArray.ultrasonicsArrayId.c_str());
+                ultrasonicsArraysInfo.push_back(ultraArray);
+            }
+        });
+    }
+
+    bool isLogicalCamera(const camera_metadata_t *metadata) {
+        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.
+            ALOGI("%s is not a logical camera device.", id.c_str());
+            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);
+        ALOGE_IF(rc, "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;
+            }
+        }
+
+        ALOGI("%s consists of %d physical camera devices.", id.c_str(), (int)physicalCameras.size());
+        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<wp<IEvsCamera_1_1>>  activeCameras; // A list of active camera handles that are
+                                                   // needed to be cleaned up.
+    std::vector<UltrasonicsArrayDesc>
+            ultrasonicsArraysInfo;                           // Empty unless/until
+                                                             // loadUltrasonicsArrayList() is called
+    std::deque<wp<IEvsCamera_1_1>> activeUltrasonicsArrays;  // A list of active ultrasonic array
+                                                             // handles that are to be cleaned up.
+};
+
+
+// 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) {
+    ALOGI("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) {
+            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            continue;
+        }
+
+        for (int pass = 0; pass < 2; pass++) {
+            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);
+
+            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) {
+                                        ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+                                        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_EQ(EvsResult::INVALID_ARG, err);
+
+            pCam->getExtendedInfo_1_1(id, [](const auto& result, const auto& data) {
+                ASSERT_EQ(EvsResult::INVALID_ARG, result);
+                ASSERT_EQ(0, data.size());
+            });
+
+            // Explicitly close the camera so resources are released right away
+            pEnumerator->closeCamera(pCam);
+        }
+    }
+}
+
+
+/*
+ * 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) {
+    ALOGI("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) {
+            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            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) {
+                                    ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+                                    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);
+
+        // Verify that the second camera instance self-identifies correctly
+        pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) {
+                                     ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+                                     EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+                                 }
+        );
+
+        // Close the second camera instance
+        pEnumerator->closeCamera(pCam2);
+    }
+
+    // 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) {
+    ALOGI("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) {
+            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            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);
+
+        // 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);
+        ALOGI("%s: Measured time to first frame %0.2f ms",
+              cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
+
+        // 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);
+        ALOGI("Measured camera rate %3.2f fps", framesPerSecond);
+        EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond);
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam);
+    }
+}
+
+
+/*
+ * 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) {
+    ALOGI("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) {
+            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            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);
+
+        // 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);
+    }
+}
+
+
+/*
+ * 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) {
+    ALOGI("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);
+    ALOGI("Display %d is in use.", targetDisplayId);
+
+    // Get the display descriptor
+    pDisplay->getDisplayInfo_1_1([](const auto& config, const auto& state) {
+        android::DisplayConfig* pConfig = (android::DisplayConfig*)config.data();
+        const auto width = pConfig->resolution.getWidth();
+        const auto height = pConfig->resolution.getHeight();
+        ALOGI("    Resolution: %dx%d", width, height);
+        ASSERT_GT(width, 0);
+        ASSERT_GT(height, 0);
+
+        android::ui::DisplayState* pState = (android::ui::DisplayState*)state.data();
+        ASSERT_NE(pState->layerStack, -1);
+    });
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        bool isLogicalCam = false;
+        getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
+        if (mIsHwModule && isLogicalCam) {
+            ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+            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);
+
+        // 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);
+    }
+
+    // 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) {
+    ALOGI("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) {
+        activeCameras.clear();
+        // 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);
+        ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+        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);
+
+        // 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) {
+    ALOGI("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.
+            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            continue;
+        }
+
+        activeCameras.clear();
+        // 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);
+    }
+}
+
+
+/*
+ * CameraMasterRelease
+ * Verify that non-master client gets notified when the master client either
+ * terminates or releases a role.
+ */
+TEST_P(EvsHidlTest, CameraMasterRelease) {
+    ALOGI("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.
+            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            continue;
+        }
+
+        activeCameras.clear();
+        // 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)) {
+                    ALOGW("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)) {
+                    ALOGW("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);
+    }
+}
+
+
+/*
+ * MultiCameraParameter:
+ * Verify that master and non-master clients behave as expected when they try to adjust
+ * camera parameters.
+ */
+TEST_P(EvsHidlTest, MultiCameraParameter) {
+    ALOGI("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.
+            ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+            continue;
+        }
+
+        activeCameras.clear();
+        // 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)) {
+                        ALOGW("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)) {
+                        ALOGW("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)) {
+                    ALOGW("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)) {
+                        ALOGW("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)) {
+                        ALOGW("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);
+    }
+}
+
+
+/*
+ * 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) {
+    ALOGI("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) {
+        activeCameras.clear();
+
+        // 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)) {
+                        ALOGW("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)) {
+                    ALOGW("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)) {
+                    ALOGW("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)) {
+                        ALOGW("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)) {
+                    ALOGW("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);
+    }
+
+    // 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) {
+    ALOGI("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) {
+        activeCameras.clear();
+        // 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);
+    }
+
+    // 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) {
+    ALOGI("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) {
+        activeCameras.clear();
+        // 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) {
+            ALOGI("Device %s does not provide a list of supported stream configurations, skipped",
+                  cam.v1.cameraId.c_str());
+
+            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);
+        ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+        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);
+    }
+}
+
+
+/*
+ * 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) {
+    ALOGI("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.";
+        }
+    }
+}
+
+
+/*
+ * UltrasonicsArrayOpenClean:
+ * Opens each ultrasonics arrays reported by the enumerator and then explicitly closes it via a
+ * call to closeUltrasonicsArray. Then repeats the test to ensure all ultrasonics arrays
+ * can be reopened.
+ */
+TEST_P(EvsHidlTest, UltrasonicsArrayOpenClean) {
+    ALOGI("Starting UltrasonicsArrayOpenClean test");
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // Open and close each ultrasonics array twice
+    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
+        for (int pass = 0; pass < 2; pass++) {
+            sp<IEvsUltrasonicsArray> pUltrasonicsArray =
+                    pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
+            ASSERT_NE(pUltrasonicsArray, nullptr);
+
+            // Verify that this ultrasonics array self-identifies correctly
+            pUltrasonicsArray->getUltrasonicArrayInfo([&ultraInfo](UltrasonicsArrayDesc desc) {
+                ALOGD("Found ultrasonics array %s", ultraInfo.ultrasonicsArrayId.c_str());
+                EXPECT_EQ(ultraInfo.ultrasonicsArrayId, desc.ultrasonicsArrayId);
+            });
+
+            // Explicitly close the ultrasonics array so resources are released right away
+            pEnumerator->closeUltrasonicsArray(pUltrasonicsArray);
+        }
+    }
+}
+
+
+// Starts a stream and verifies all data received is valid.
+TEST_P(EvsHidlTest, UltrasonicsVerifyStreamData) {
+    ALOGI("Starting UltrasonicsVerifyStreamData");
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // For each ultrasonics array.
+    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
+        ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str());
+
+        sp<IEvsUltrasonicsArray> pUltrasonicsArray =
+                pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
+        ASSERT_NE(pUltrasonicsArray, nullptr);
+
+        sp<FrameHandlerUltrasonics> frameHandler = new FrameHandlerUltrasonics(pUltrasonicsArray);
+
+        // Start stream.
+        EvsResult result = pUltrasonicsArray->startStream(frameHandler);
+        ASSERT_EQ(result, EvsResult::OK);
+
+        // Wait 5 seconds to receive frames.
+        sleep(5);
+
+        // Stop stream.
+        pUltrasonicsArray->stopStream();
+
+        EXPECT_GT(frameHandler->getReceiveFramesCount(), 0);
+        EXPECT_TRUE(frameHandler->areAllFramesValid());
+
+        // Explicitly close the ultrasonics array so resources are released right away
+        pEnumerator->closeUltrasonicsArray(pUltrasonicsArray);
+    }
+}
+
+
+// Sets frames in flight before and after start of stream and verfies success.
+TEST_P(EvsHidlTest, UltrasonicsSetFramesInFlight) {
+    ALOGI("Starting UltrasonicsSetFramesInFlight");
+
+    // Get the ultrasonics array list
+    loadUltrasonicsArrayList();
+
+    // For each ultrasonics array.
+    for (auto&& ultraInfo : ultrasonicsArraysInfo) {
+        ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str());
+
+        sp<IEvsUltrasonicsArray> pUltrasonicsArray =
+                pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
+        ASSERT_NE(pUltrasonicsArray, nullptr);
+
+        EvsResult result = pUltrasonicsArray->setMaxFramesInFlight(10);
+        EXPECT_EQ(result, EvsResult::OK);
+
+        sp<FrameHandlerUltrasonics> frameHandler = new FrameHandlerUltrasonics(pUltrasonicsArray);
+
+        // Start stream.
+        result = pUltrasonicsArray->startStream(frameHandler);
+        ASSERT_EQ(result, EvsResult::OK);
+
+        result = pUltrasonicsArray->setMaxFramesInFlight(5);
+        EXPECT_EQ(result, EvsResult::OK);
+
+        // Stop stream.
+        pUltrasonicsArray->stopStream();
+
+        // Explicitly close the ultrasonics array so resources are released right away
+        pEnumerator->closeUltrasonicsArray(pUltrasonicsArray);
+    }
+}
+
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance,
+    EvsHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEvsEnumerator::descriptor)),
+    android::hardware::PrintInstanceNameToString);
+
diff --git a/automotive/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..face235
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/Android.bp
@@ -0,0 +1,18 @@
+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,
+            },
+        },
+    },
+}
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..769bdc6
--- /dev/null
+++ b/automotive/sv/1.0/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.sv@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ISurroundViewStream.hal",
+        "ISurroundViewSession.hal",
+        "ISurroundView2dSession.hal",
+        "ISurroundView3dSession.hal",
+        "ISurroundViewService.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+    ],
+    gen_java: true,
+}
diff --git a/automotive/sv/1.0/ISurroundView2dSession.hal b/automotive/sv/1.0/ISurroundView2dSession.hal
new file mode 100644
index 0000000..fa49674
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundView2dSession.hal
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import ISurroundViewSession;
+
+/**
+ * Interface representing a surround view 2d session.
+ *
+ * Surround view 2d provides a top/bird's eye view of the car and its surroundings.
+ */
+interface ISurroundView2dSession extends ISurroundViewSession {
+
+    /**
+     * Gets mapping information for 2d surround view.
+     *
+     * Mapping information maps the output frame of 2d surround view to actual dimensions
+     * covered on the ground. Mapping information is fixed for a car and is based upon its camera
+     * coverage. Mapping information can be used for doing overlays of objects in 3d space
+     * onto the surround view 2d output frame.
+     *
+     * @param sv2dConfig Configuration to set.
+     * @return sv2dMappingInfo mapping information of the 2d surround view.
+     */
+    get2dMappingInfo() generates (Sv2dMappingInfo sv2dMappingInfo);
+
+    /**
+     * Sets the configuration of 2d surround view.
+     *
+     * Configuration is used for supported different target use-cases of the surround view eg.
+     * fullscreen or preview. Default configuration is FULLSCREEN.
+     * A set config call can be performed at any time (before or after startStream) of the session.
+     * Once config change is complete, a CONFIG_CHANGED event is sent, after which
+     * all frames received will be of the updated config.
+     *
+     * @param sv2dConfig Configuration to set.
+     * @return svResult  Returns OK if successful, appropriate error result otherwise.
+     */
+    set2dConfig(Sv2dConfig sv2dConfig) generates (SvResult svResult);
+
+    /**
+     * Gets the current configuration of the 2d surround view.
+     *
+     * Configuration is used for supported different target use-cases of the surround view eg.
+     * fullscreen view or preview. Use setConfig call to set a configuration.
+     *
+     * @return sv2dConfig the active current configuration of the 2d session.
+     */
+    get2dConfig() generates (Sv2dConfig sv2dConfig);
+
+    /**
+     * Projects points on camera image to surround view 2d image.
+     *
+     * Useful for mapping points detected on individual camera frames onto the surround view 2d
+     * output frame.
+     *
+     * @param cameraPoints  List of camera pixel points to be projected in range including (0, 0)
+     *                      and (width - 1, height -1) of camera frame. If point is outside camera
+                            frame INVALID_ARG error is returned.
+     * @param cameraId      Id of the EvsCamera to use for projecting points. Id must be one of the
+     *                      cameras as returned by getCameraIds() else INVALID_ARG error is returned
+     * @return points2d     Returns a list of 2d pixel points projecting into surround view 2d
+     *                      frame in the same order as cameraPoints. Point projected maybe outside
+     *                      surround view frame i.e. outside (0, 0) and
+     *                      (sv_width - 1, sv_height - 1). Points that do not project to ground
+     *                      plane are set with inValid true.
+     */
+    projectCameraPoints(vec<Point2dInt> cameraPoints, string cameraId) generates (
+            vec<Point2dFloat> points2d);
+};
diff --git a/automotive/sv/1.0/ISurroundView3dSession.hal b/automotive/sv/1.0/ISurroundView3dSession.hal
new file mode 100644
index 0000000..d2b0c53
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundView3dSession.hal
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import ISurroundViewSession;
+
+/**
+ * Interface representing a surround view 3d session.
+ *
+ * Surround view 3d provides a virtual view from any desired position in the 3d space around the
+ * car. Surround view 3d creates an approximate 3d surface around the car to match the surrounds
+ * and provides a virtual view as seen on this surface.
+ */
+interface ISurroundView3dSession extends ISurroundViewSession {
+
+    /**
+     * Sets the desired views of surround view 3d.
+     *
+     * Surround view 3d takes a list of desired virtual view points and provides an output frame
+     * for each view. Default view list is a single view from behind the car front facing in the
+     * front direction.
+     * A call to setViews() results in the views set by a previous call to be discarded.
+     * Each view set is identified by an Id which is returned with the corresponding output frame
+     * of that view.
+     * Clients can call setViews() at any stage of the session (before/after startStream). Client
+     * may continue to receive frames of previous views after setViews() call for a while and can
+     * identify updated set of views once effective using the view Id provided in the updated
+     * views frames.
+     *
+     * @param views     List of desired views to generate output frames.
+     * @return svResult Returns OK if successful, appropriate error result otherwise.
+     */
+    setViews(vec<View3d> views) generates (SvResult svResult);
+
+    /**
+     * Sets the configuration of 3d surround view.
+     *
+     * Configuration is used for supported different target use-cases of the surround view eg.
+     * fullscreen view or preview. A set config call can be performed at anytime (before or after
+     * startStream) of the session.
+     * Once config change is complete, a CONFIG_CHANGED event is sent, after which
+     * all frames received will be of the updated config.
+     *
+     * @param sv3dConfig Configuration to set.
+     * @return svResult  Returns OK if successful, appropriate error result otherwise.
+     */
+    set3dConfig(Sv3dConfig sv3dConfig) generates (SvResult svResult);
+
+    /**
+     * Gets the current configuration of the 3d surround view.
+     *
+     * Configuration is used for supported different target use-cases of the surround view eg.
+     * fullscreen view or preview. Use setConfig call to set a configuration.
+     *
+     * @return sv3dConfig The current active configuration of the 3d session.
+     */
+    get3dConfig() generates (Sv3dConfig sv3dConfig);
+
+    /**
+     * Updates 3d overlays in scene.
+     *
+     * updateOverlays() provides a way to set a 3d overlay object in the scene. An overlay is an
+     * 3d object in the scene which can be a visual indicator to provide additional information eg.
+     * parking sensor distance indicators or overlays for objects in scene.
+     *
+     * An overlay object is defined by a set of points (forming triangles) with some color and
+     * transparency values and each overlay is identified by an overlay Id.
+     * When an overlay with a new Id is passed, a new overlay is added to the scene.
+     * When an overlay with previous id is passed, its vertices/color are updated with passed data.
+     * If the overlay data is empty, the overlay is removed from the scene.
+     *
+     * @param overlaysData   Object with shared memory containing overlays to add/update in the
+     *                       scene. Refer to OverlaysData structure for layout in shared memory.
+     * @return svResult      Returns OK if successful, appropriate error result otherwise.
+     */
+    updateOverlays(OverlaysData overlaysData) generates (SvResult svResult);
+
+    /**
+     * Projects points on camera image to surround view 3D surface.
+     *
+     * Useful for mapping points detected on individual camera frames onto the surround view 3D
+     * surface, these 3d points can then be used to set overlays using the updateOverlays() for
+     * the detected objects in the scene.
+     * Note:
+     * 3d points returned are projected on an approximate 3d surface and do not provide the exact
+     * 3d location.
+     *
+     * @param cameraPoints  List of camera pixel points to be projected in range including (0, 0)
+     *                      and (width - 1, height -1) of camera frame. If point is outside camera
+                            frame INVALID_ARG error is returned.
+     * @param cameraId      Id of the EvsCamera to use for projecting points. Id must be one of the
+     *                      cameras as returned by getCameraIds() else INVALID_ARG error is returned
+     * @return points3d     Returns a list of 3d points on the approximate 3d surface in the
+     *                      automotive coordinate system in the same order as cameraPoints.
+     *                      Points that do not project to 3d surface are set with inValid true.
+     */
+    projectCameraPointsTo3dSurface(vec<Point2dInt> cameraPoints, string cameraId) generates (
+            vec<Point3dFloat> points3d);
+};
diff --git a/automotive/sv/1.0/ISurroundViewService.hal b/automotive/sv/1.0/ISurroundViewService.hal
new file mode 100644
index 0000000..7de0bd1
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundViewService.hal
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import ISurroundView2dSession;
+import ISurroundView3dSession;
+
+/**
+ * Interface representing entry point for surround view.
+ *
+ * Surround view service has two types of sessions 2d and 3d. Refer to their respective interface
+ * for more details.
+ */
+interface ISurroundViewService {
+
+    /**
+     * Gets a list of camera ids that are used for generating surround view.
+     * For 4 camera configuration, the cameras ids are ordered in clockwise direction
+     * when viewed from top of the car starting with the front camera. i.e. FRONT, RIGHT, REAR and
+     * LEFT. All other configurations must follow clockwise order.
+     *
+     * @result cameraIds List of camera ids that matching the Id of EVS Cameras used by service.
+     */
+    getCameraIds() generates (vec<string> cameraIds);
+
+    /**
+     * Starts a surround view 2d session.
+     *
+     * @result sv2dSession Returns a new 2d session that was created.
+     *         result      Returns OK if successful, appropriate error result otherwise.
+     */
+    start2dSession() generates (ISurroundView2dSession sv2dSession, SvResult result);
+
+    /**
+     * Stops a surround view 2d session.
+     *
+     * @param sv2dSession Valid 2d session to be stopped.
+     * @return svResult   Returns OK if successful, appropriate error result otherwise.
+     */
+    stop2dSession(ISurroundView2dSession sv2dSession) generates (SvResult result);
+
+    /**
+     * Starts a surround view 3d session.
+     *
+     * @result sv3dSession Returns a new 3d session that was created.
+     *         result      Returns OK if successful, appropriate error result otherwise.
+     */
+    start3dSession() generates (ISurroundView3dSession sv3dSession, SvResult result);
+
+    /**
+     * Stops a surround view 2d session.
+     *
+     * @param sv2dSession Valid 2d session to be stopped.
+     * @return svResult  Returns OK if successful, appropriate error result otherwise.
+     */
+    stop3dSession(ISurroundView3dSession sv3dSession) generates (SvResult result);
+};
diff --git a/automotive/sv/1.0/ISurroundViewSession.hal b/automotive/sv/1.0/ISurroundViewSession.hal
new file mode 100644
index 0000000..62cfac0
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundViewSession.hal
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import ISurroundViewStream;
+
+/**
+ * Common interface for surround view session extended by surround view 2d and 3d
+ * session.
+ */
+interface ISurroundViewSession {
+    /**
+     * Requests to start receiving surround view frames.
+     *
+     * For surround view 3d, setViews() must be set before calling startStream().
+     *
+     * @param stream     Stream to receiving callbacks for the session.
+     * @return svResult  Returns OK if successful, returns VIEW_NOT_SET if setViews() is not
+     *                   called for surround view 3d, appropriate error results otherwise.
+     */
+    startStream(ISurroundViewStream stream) generates (SvResult svResult);
+
+    /**
+     * Requests to stop stream.
+     *
+     * Frames may continue to arrive after call returns. Each must be returned until
+     * the closure of the stream is signaled by the ISurroundViewStream.
+     */
+    stopStream();
+
+    /**
+     * Signal from client that a frame, which was delivered by the stream, has been consumed.
+     *
+     * @param  svFramesDesc Descriptor to signal done with frame.
+     */
+    oneway doneWithFrames(SvFramesDesc svFramesDesc);
+};
diff --git a/automotive/sv/1.0/ISurroundViewStream.hal b/automotive/sv/1.0/ISurroundViewStream.hal
new file mode 100644
index 0000000..22d610f
--- /dev/null
+++ b/automotive/sv/1.0/ISurroundViewStream.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+/**
+ * Interface representing a surround view stream.
+ *
+ * This interface is to be implemented by client to receive callback for output frames and events.
+ */
+interface ISurroundViewStream {
+    /**
+     * Receives callback of surround view 2d/3d frames.
+     *
+     * @param svFramesDesc Frames descriptor containing the output frames.
+     */
+    oneway receiveFrames(SvFramesDesc svFramesDesc);
+
+    /**
+     * Receives callback for surround view events.
+     *
+     * @param svEvent Surround view event.
+    */
+    oneway notify(SvEvent svEvent);
+};
diff --git a/automotive/sv/1.0/default/Android.bp b/automotive/sv/1.0/default/Android.bp
new file mode 100644
index 0000000..8417949
--- /dev/null
+++ b/automotive/sv/1.0/default/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+    name: "android.hardware.automotive.sv@1.0-service",
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "service.cpp",
+        "SurroundViewService.cpp",
+        "SurroundView2dSession.cpp",
+        "SurroundView3dSession.cpp",
+    ],
+    init_rc: ["android.hardware.automotive.sv@1.0-service.rc"],
+    vintf_fragments: ["android.hardware.automotive.sv@1.0-service.xml"],
+    shared_libs: [
+        "android.hardware.automotive.sv@1.0",
+        "android.hidl.memory@1.0",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libui",
+        "libutils",
+        "libhidlmemory",
+    ],
+
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/automotive/sv/1.0/default/SurroundView2dSession.cpp b/automotive/sv/1.0/default/SurroundView2dSession.cpp
new file mode 100644
index 0000000..4f97598
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView2dSession.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundView2dSession.h"
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+SurroundView2dSession::SurroundView2dSession() :
+    mStreamState(STOPPED) {
+    mEvsCameraIds = {"0" , "1", "2", "3"};
+
+    mConfig.width = 640;
+    mConfig.blending = SvQuality::HIGH;
+
+    framesRecord.frames.svBuffers.resize(1);
+    framesRecord.frames.svBuffers[0].viewId = 0;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle =
+        new native_handle_t();
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
+        mConfig.width;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
+        mConfig.width * 3 / 4;
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
+Return<SvResult> SurroundView2dSession::startStream(
+    const sp<ISurroundViewStream>& stream) {
+    ALOGD("SurroundView2dSession::startStream");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    if (mStreamState != STOPPED) {
+        ALOGE("ignoring startVideoStream call"
+              "when a stream is already running.");
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    mStream = stream;
+
+    ALOGD("Notify SvEvent::STREAM_STARTED");
+    mStream->notify(SvEvent::STREAM_STARTED);
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = std::thread([this](){ generateFrames(); });
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::stopStream() {
+    ALOGD("SurroundView2dSession::stopStream");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    if (mStreamState == RUNNING) {
+        // Tell the GenerateFrames loop we want it to stop
+        mStreamState = STOPPING;
+
+        // Block outside the mutex until the "stop" flag has been acknowledged
+        // We won't send any more frames, but the client might still get some
+        // already in flight
+        ALOGD("Waiting for stream thread to end...");
+        lock.unlock();
+        mCaptureThread.join();
+        lock.lock();
+
+        mStreamState = STOPPED;
+        mStream = nullptr;
+        ALOGD("Stream marked STOPPED.");
+    }
+
+    return android::hardware::Void();
+}
+
+Return<void> SurroundView2dSession::doneWithFrames(
+    const SvFramesDesc& svFramesDesc){
+    ALOGD("SurroundView2dSession::doneWithFrames");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    framesRecord.inUse = false;
+
+    (void)svFramesDesc;
+    return android::hardware::Void();
+}
+
+// Methods from ISurroundView2dSession follow.
+Return<void> SurroundView2dSession::get2dMappingInfo(
+    get2dMappingInfo_cb _hidl_cb) {
+    ALOGD("SurroundView2dSession::get2dMappingInfo");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    Sv2dMappingInfo info;
+    info.width = 8; // keeps ratio to 4:3
+    info.height = 6;
+    info.center.isValid = true;
+    info.center.x = 0;
+    info.center.y = 0;
+    _hidl_cb(info);
+    return android::hardware::Void();
+}
+
+Return<SvResult> SurroundView2dSession::set2dConfig(
+    const Sv2dConfig& sv2dConfig) {
+    ALOGD("SurroundView2dSession::setConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    mConfig.width = sv2dConfig.width;
+    mConfig.blending = sv2dConfig.blending;
+    ALOGD("Notify SvEvent::CONFIG_UPDATED");
+    mStream->notify(SvEvent::CONFIG_UPDATED);
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) {
+    ALOGD("SurroundView2dSession::getConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    _hidl_cb(mConfig);
+    return android::hardware::Void();
+}
+
+Return<void> SurroundView2dSession::projectCameraPoints(
+        const hidl_vec<Point2dInt>& points2dCamera,
+        const hidl_string& cameraId,
+        projectCameraPoints_cb _hidl_cb) {
+    ALOGD("SurroundView2dSession::projectCameraPoints");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    bool cameraIdFound = false;
+    for (auto evsCameraId : mEvsCameraIds) {
+      if (cameraId == evsCameraId) {
+          cameraIdFound = true;
+          ALOGI("Camera id found.");
+          break;
+      }
+    }
+
+    if (!cameraIdFound) {
+        ALOGE("Camera id not found.");
+        _hidl_cb(hidl_vec<Point2dFloat>());
+        return android::hardware::Void();
+    }
+
+    hidl_vec<Point2dFloat> outPoints;
+    outPoints.resize(points2dCamera.size());
+
+    int width = mConfig.width;
+    int height = mConfig.width * 3 / 4;
+    for (int i=0; i<points2dCamera.size(); i++) {
+        // Assuming all the points in the image frame can be projected into 2d
+        // Surround View space. Otherwise cannot.
+        if (points2dCamera[i].x < 0 || points2dCamera[i].y > width-1 ||
+            points2dCamera[i].x < 0 || points2dCamera[i].y > height-1) {
+            ALOGW("SurroundView2dSession::projectCameraPoints "
+                  "gets invalid 2d camera points. Ignored");
+            outPoints[i].isValid = false;
+            outPoints[i].x = 10000;
+            outPoints[i].y = 10000;
+        } else {
+            outPoints[i].isValid = true;
+            outPoints[i].x = 0;
+            outPoints[i].y = 0;
+        }
+    }
+
+    _hidl_cb(outPoints);
+    return android::hardware::Void();
+}
+
+void SurroundView2dSession::generateFrames() {
+    ALOGD("SurroundView2dSession::generateFrames");
+
+    int sequenceId = 0;
+
+    while(true) {
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (mStreamState != RUNNING) {
+                // Break out of our main thread loop
+                break;
+            }
+
+            framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
+                mConfig.width;
+            framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
+                mConfig.width * 3 / 4;
+        }
+
+        usleep(100 * 1000);
+
+        framesRecord.frames.timestampNs = elapsedRealtimeNano();
+        framesRecord.frames.sequenceId = sequenceId++;
+
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (framesRecord.inUse) {
+                ALOGD("Notify SvEvent::FRAME_DROPPED");
+                mStream->notify(SvEvent::FRAME_DROPPED);
+            } else {
+                framesRecord.inUse = true;
+                mStream->receiveFrames(framesRecord.frames);
+            }
+        }
+    }
+
+    // If we've been asked to stop, send an event to signal the actual
+    // end of stream
+    ALOGD("Notify SvEvent::STREAM_STOPPED");
+    mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView2dSession.h b/automotive/sv/1.0/default/SurroundView2dSession.h
new file mode 100644
index 0000000..ee751e7
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView2dSession.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::mutex;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView2dSession : public ISurroundView2dSession {
+public:
+    SurroundView2dSession();
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+    Return<SvResult> startStream(
+        const sp<ISurroundViewStream>& stream) override;
+    Return<void> stopStream() override;
+    Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+    // Methods from ISurroundView2dSession follow.
+    Return<void> get2dMappingInfo(get2dMappingInfo_cb _hidl_cb) override;
+    Return<SvResult> set2dConfig(const Sv2dConfig& sv2dConfig) override;
+    Return<void> get2dConfig(get2dConfig_cb _hidl_cb) override;
+    Return<void> projectCameraPoints(
+        const hidl_vec<Point2dInt>& points2dCamera,
+        const hidl_string& cameraId,
+        projectCameraPoints_cb _hidl_cb) override;
+
+    // TODO(tanmayp): Make private and add set/get method.
+    // Stream subscribed for the session.
+    sp<ISurroundViewStream> mStream;
+
+private:
+    void generateFrames();
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+    StreamStateValues mStreamState;
+
+    Sv2dConfig mConfig;
+
+    std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+    struct FramesRecord {
+        SvFramesDesc frames;
+        bool inUse = false;
+    };
+
+    FramesRecord framesRecord;
+
+    // Synchronization necessary to deconflict mCaptureThread from the main service thread
+    std::mutex mAccessLock;
+
+    std::vector<std::string> mEvsCameraIds;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView3dSession.cpp b/automotive/sv/1.0/default/SurroundView3dSession.cpp
new file mode 100644
index 0000000..da36f32
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView3dSession.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundView3dSession.h"
+
+#include <set>
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::hidl_memory;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+SurroundView3dSession::SurroundView3dSession() :
+    mStreamState(STOPPED){
+
+    mEvsCameraIds = {"0" , "1", "2", "3"};
+
+    mConfig.width = 640;
+    mConfig.height = 480;
+    mConfig.carDetails = SvQuality::HIGH;
+
+    framesRecord.frames.svBuffers.resize(1);
+    framesRecord.frames.svBuffers[0].viewId = 0;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle = new native_handle_t();
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] = mConfig.width;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] = mConfig.height;
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+Return<SvResult> SurroundView3dSession::startStream(
+    const sp<ISurroundViewStream>& stream) {
+    ALOGD("SurroundView3dSession::startStream");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    if (mStreamState != STOPPED) {
+        ALOGE("ignoring startVideoStream call when a stream is already running.");
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (mViews.empty()) {
+        ALOGE("No views have been set for current Surround View 3d Session. "
+              "Please call setViews before starting the stream.");
+        return SvResult::VIEW_NOT_SET;
+    }
+
+    mStream = stream;
+
+    ALOGD("Notify SvEvent::STREAM_STARTED");
+    mStream->notify(SvEvent::STREAM_STARTED);
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = std::thread([this](){ generateFrames(); });
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::stopStream() {
+    ALOGD("SurroundView3dSession::stopStream");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    if (mStreamState == RUNNING) {
+        // Tell the GenerateFrames loop we want it to stop
+        mStreamState = STOPPING;
+
+        // Block outside the mutex until the "stop" flag has been acknowledged
+        // We won't send any more frames, but the client might still get some already in flight
+        ALOGD("Waiting for stream thread to end...");
+        lock.unlock();
+        mCaptureThread.join();
+        lock.lock();
+
+        mStreamState = STOPPED;
+        mStream = nullptr;
+        ALOGD("Stream marked STOPPED.");
+    }
+
+    return android::hardware::Void();
+}
+
+Return<void> SurroundView3dSession::doneWithFrames(
+    const SvFramesDesc& svFramesDesc){
+    ALOGD("SurroundView3dSession::doneWithFrames");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    framesRecord.inUse = false;
+
+    (void)svFramesDesc;
+    return android::hardware::Void();
+}
+
+// Methods from ISurroundView3dSession follow.
+Return<SvResult> SurroundView3dSession::setViews(const hidl_vec<View3d>& views) {
+    ALOGD("SurroundView3dSession::stopStream");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    mViews.resize(views.size());
+    for (int i=0; i<views.size(); i++) {
+        mViews[i] = views[i];
+    }
+
+    return SvResult::OK;
+}
+
+Return<SvResult> SurroundView3dSession::set3dConfig(const Sv3dConfig& sv3dConfig) {
+    ALOGD("SurroundView3dSession::set3dConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    mConfig.width = sv3dConfig.width;
+    mConfig.height = sv3dConfig.height;
+    mConfig.carDetails = sv3dConfig.carDetails;
+    ALOGD("Notify SvEvent::CONFIG_UPDATED");
+    mStream->notify(SvEvent::CONFIG_UPDATED);
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::get3dConfig(get3dConfig_cb _hidl_cb) {
+    ALOGD("SurroundView3dSession::get3dConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    _hidl_cb(mConfig);
+    return android::hardware::Void();
+}
+
+bool VerifyOverlayData(const OverlaysData& overlaysData) {
+    // Check size of shared memory matches overlaysMemoryDesc.
+    const int kVertexSize = 16;
+    const int kIdSize = 2;
+    int memDescSize = 0;
+    for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+        memDescSize += kIdSize + kVertexSize * overlayMemDesc.verticesCount;
+    }
+    if (memDescSize != overlaysData.overlaysMemory.size()) {
+        ALOGE("shared memory and overlaysMemoryDesc size mismatch.");
+        return false;
+    }
+
+    // Map memory.
+    sp<IMemory> pSharedMemory = mapMemory(overlaysData.overlaysMemory);
+    if(pSharedMemory.get() == nullptr) {
+        ALOGE("mapMemory failed.");
+        return false;
+    }
+
+    // Get Data pointer.
+    uint8_t* pData = (uint8_t*)((void*)pSharedMemory->getPointer());
+    if (pData == nullptr) {
+        ALOGE("Shared memory getPointer() failed.");
+        return false;
+    }
+
+    int idOffset = 0;
+    std::set<uint16_t> overlayIdSet;
+    for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+
+        if (overlayIdSet.find(overlayMemDesc.id) != overlayIdSet.end()) {
+            ALOGE("Duplicate id within memory descriptor.");
+            return false;
+        }
+        overlayIdSet.insert(overlayMemDesc.id);
+
+        if(overlayMemDesc.verticesCount < 3) {
+            ALOGE("Less than 3 vertices.");
+            return false;
+        }
+
+        if (overlayMemDesc.overlayPrimitive == OverlayPrimitive::TRIANGLES &&
+                overlayMemDesc.verticesCount % 3 != 0) {
+            ALOGE("Triangles primitive does not have vertices multiple of 3.");
+            return false;
+        }
+
+        uint16_t overlayId = *((uint16_t*)(pData + idOffset));
+
+        if (overlayId != overlayMemDesc.id) {
+            ALOGE("Overlay id mismatch %d , %d", overlayId, overlayMemDesc.id);
+            return false;
+        }
+
+        idOffset += kIdSize + (kVertexSize * overlayMemDesc.verticesCount);
+    }
+
+    return true;
+}
+
+Return<SvResult>  SurroundView3dSession::updateOverlays(
+        const OverlaysData& overlaysData) {
+
+    if(!VerifyOverlayData(overlaysData)) {
+        ALOGE("VerifyOverlayData failed.");
+        return SvResult::INVALID_ARG;
+    }
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::projectCameraPointsTo3dSurface(
+    const hidl_vec<Point2dInt>& cameraPoints,
+    const hidl_string& cameraId,
+    projectCameraPointsTo3dSurface_cb _hidl_cb) {
+
+    std::vector<Point3dFloat> points3d;
+    bool cameraIdFound = false;
+    for (auto evsCameraId : mEvsCameraIds) {
+      if (cameraId == evsCameraId) {
+          cameraIdFound = true;
+          ALOGI("Camera id found.");
+          break;
+      }
+    }
+
+    if (!cameraIdFound) {
+        ALOGE("Camera id not found.");
+        _hidl_cb(points3d);
+        return android::hardware::Void();
+    }
+
+    for (const auto cameraPoint : cameraPoints) {
+        Point3dFloat point3d;
+        point3d.isValid = true;
+
+        if (cameraPoint.x < 0 || cameraPoint.x >= mConfig.width-1 ||
+                cameraPoint.y < 0 || cameraPoint.y >= mConfig.height-1) {
+            ALOGE("Camera point out of bounds.");
+            point3d.isValid = false;
+        }
+        points3d.push_back(point3d);
+    }
+    _hidl_cb(points3d);
+    return android::hardware::Void();
+}
+
+void SurroundView3dSession::generateFrames() {
+    ALOGD("SurroundView3dSession::generateFrames");
+
+    int sequenceId = 0;
+
+    while(true) {
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (mStreamState != RUNNING) {
+                // Break out of our main thread loop
+                break;
+            }
+        }
+
+        usleep(100 * 1000);
+
+        framesRecord.frames.timestampNs = elapsedRealtimeNano();
+        framesRecord.frames.sequenceId = sequenceId++;
+
+        framesRecord.frames.svBuffers.resize(mViews.size());
+        for (int i=0; i<mViews.size(); i++) {
+            framesRecord.frames.svBuffers[i].viewId = mViews[i].viewId;
+            framesRecord.frames.svBuffers[i].hardwareBuffer.nativeHandle = new native_handle_t();
+            framesRecord.frames.svBuffers[i].hardwareBuffer.description[0] = mConfig.width; // width
+            framesRecord.frames.svBuffers[i].hardwareBuffer.description[1] = mConfig.height; // height
+        }
+
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (framesRecord.inUse) {
+                ALOGD("Notify SvEvent::FRAME_DROPPED");
+                mStream->notify(SvEvent::FRAME_DROPPED);
+            } else {
+                framesRecord.inUse = true;
+                mStream->receiveFrames(framesRecord.frames);
+            }
+        }
+    }
+
+    // If we've been asked to stop, send an event to signal the actual end of stream
+    ALOGD("Notify SvEvent::STREAM_STOPPED");
+    mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView3dSession.h b/automotive/sv/1.0/default/SurroundView3dSession.h
new file mode 100644
index 0000000..5c638db
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView3dSession.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::mutex;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView3dSession : public ISurroundView3dSession {
+public:
+    SurroundView3dSession();
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+    Return<SvResult> startStream(
+        const sp<ISurroundViewStream>& stream) override;
+    Return<void> stopStream() override;
+    Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+    // Methods from ISurroundView3dSession follow.
+    Return<SvResult> setViews(const hidl_vec<View3d>& views) override;
+    Return<SvResult> set3dConfig(const Sv3dConfig& sv3dConfig) override;
+    Return<void> get3dConfig(get3dConfig_cb _hidl_cb) override;
+    Return<SvResult>  updateOverlays(const OverlaysData& overlaysData);
+    Return<void> projectCameraPointsTo3dSurface(
+        const hidl_vec<Point2dInt>& cameraPoints,
+        const hidl_string& cameraId,
+        projectCameraPointsTo3dSurface_cb _hidl_cb);
+
+    // Stream subscribed for the session.
+    // TODO(tanmayp): Make private and add set/get method.
+    sp<ISurroundViewStream> mStream;
+
+private:
+    void generateFrames();
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+    StreamStateValues mStreamState;
+
+    std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+    struct FramesRecord {
+        SvFramesDesc frames;
+        bool inUse = false;
+    };
+
+    FramesRecord framesRecord;
+
+    // Synchronization necessary to deconflict mCaptureThread from the main service thread
+    std::mutex mAccessLock;
+
+    std::vector<View3d> mViews;
+
+    Sv3dConfig mConfig;
+
+    std::vector<std::string> mEvsCameraIds;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/sv/1.0/default/SurroundViewService.cpp b/automotive/sv/1.0/default/SurroundViewService.cpp
new file mode 100644
index 0000000..fe89dd5
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundViewService.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundViewService.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+const std::string kCameraIds[] = {"0", "1", "2", "3"};
+
+Return<void> SurroundViewService::getCameraIds(getCameraIds_cb _hidl_cb) {
+  std::vector<hidl_string> cameraIds = {kCameraIds[0], kCameraIds[1],
+          kCameraIds[2], kCameraIds[3]};
+  _hidl_cb(cameraIds);
+  return android::hardware::Void();
+}
+
+Return<void> SurroundViewService::start2dSession(start2dSession_cb _hidl_cb) {
+    ALOGD("SurroundViewService::start2dSession");
+    if (mSurroundView2dSession != nullptr) {
+        ALOGW("Only one 2d session is supported at the same time");
+        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+    } else {
+        mSurroundView2dSession = new SurroundView2dSession();
+        _hidl_cb(mSurroundView2dSession, SvResult::OK);
+    }
+    return android::hardware::Void();
+}
+
+Return<SvResult> SurroundViewService::stop2dSession(
+    const sp<ISurroundView2dSession>& sv2dSession) {
+    ALOGD("SurroundViewService::stop2dSession");
+    if (sv2dSession != nullptr && sv2dSession == mSurroundView2dSession) {
+        mSurroundView2dSession = nullptr;
+        return SvResult::OK;
+    } else {
+        ALOGE("Invalid arg for stop2dSession");
+        return SvResult::INVALID_ARG;
+    }
+}
+
+Return<void> SurroundViewService::start3dSession(start3dSession_cb _hidl_cb) {
+    ALOGD("SurroundViewService::start3dSession");
+    if (mSurroundView3dSession != nullptr) {
+        ALOGW("Only one 3d session is supported at the same time");
+        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+    } else {
+        mSurroundView3dSession = new SurroundView3dSession();
+        _hidl_cb(mSurroundView3dSession, SvResult::OK);
+    }
+    return android::hardware::Void();
+}
+
+Return<SvResult> SurroundViewService::stop3dSession(
+    const sp<ISurroundView3dSession>& sv3dSession) {
+    ALOGD("SurroundViewService::stop3dSession");
+    if (sv3dSession != nullptr && sv3dSession == mSurroundView3dSession) {
+        mSurroundView3dSession = nullptr;
+        return SvResult::OK;
+    } else {
+        ALOGE("Invalid arg for stop3dSession");
+        return SvResult::INVALID_ARG;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundViewService.h b/automotive/sv/1.0/default/SurroundViewService.h
new file mode 100644
index 0000000..9e0e151
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundViewService.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SurroundView2dSession.h"
+#include "SurroundView3dSession.h"
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundViewService : public ISurroundViewService {
+public:
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewService follow.
+    Return<void> getCameraIds(getCameraIds_cb _hidl_cb) override;
+    Return<void> start2dSession(start2dSession_cb _hidl_cb) override;
+    Return<SvResult> stop2dSession(
+        const sp<ISurroundView2dSession>& sv2dSession) override;
+
+    Return<void> start3dSession(start3dSession_cb _hidl_cb) override;
+    Return<SvResult> stop3dSession(
+        const sp<ISurroundView3dSession>& sv3dSession) override;
+
+private:
+    sp<SurroundView2dSession> mSurroundView2dSession;
+    sp<SurroundView3dSession> mSurroundView3dSession;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc
new file mode 100644
index 0000000..e822017
--- /dev/null
+++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc
@@ -0,0 +1,5 @@
+service sv_service /vendor/bin/hw/android.hardware.automotive.sv@1.0-service
+    class hal
+    user automotive_evs
+    group automotive_evs
+    disabled
diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml
new file mode 100644
index 0000000..ba8e5ac
--- /dev/null
+++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.automotive.sv</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ISurroundViewService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/automotive/sv/1.0/default/service.cpp b/automotive/sv/1.0/default/service.cpp
new file mode 100644
index 0000000..fae7425
--- /dev/null
+++ b/automotive/sv/1.0/default/service.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.automotive.sv@1.0-service"
+
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware_buffer.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <thread>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/SystemClock.h>
+
+#include "SurroundViewService.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// implementation:
+using android::hardware::automotive::sv::V1_0::implementation::SurroundViewService;
+
+int main() {
+    ALOGI("ISurroundViewService default implementation is starting");
+    android::sp<ISurroundViewService> service = new SurroundViewService();
+
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    // Register our service -- if somebody is already registered by our name,
+    // they will be killed (their thread pool will throw an exception).
+    android::status_t status = service->registerAsService();
+
+    LOG_ALWAYS_FATAL_IF(status != android::OK,
+                        "Could not register default Surround View Service (%d)",
+                        status);
+
+    joinRpcThreadpool();
+
+    // In normal operation, we don't expect the thread pool to exit
+    ALOGE("Surround View Service is shutting down");
+    return 1;
+}
diff --git a/automotive/sv/1.0/types.hal b/automotive/sv/1.0/types.hal
new file mode 100644
index 0000000..573bf11
--- /dev/null
+++ b/automotive/sv/1.0/types.hal
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.sv@1.0;
+
+import android.hardware.graphics.common@1.2::HardwareBuffer;
+
+/** Structure for translation with x, y and z units. */
+struct Translation {
+    float x;
+    float y;
+    float z;
+};
+
+/**
+ * Structure for rotation expressed as quaternions.
+ * Convention used: Unit quaternion with hamilton convention.
+ */
+struct RotationQuat {
+    float x;
+    float y;
+    float z;
+    float w;
+};
+
+/** Structure representing a 2D point with integers. Units are pixels. */
+struct Point2dInt {
+    uint32_t x;
+    uint32_t y;
+};
+
+/** Structure representing a 2D point with floats. */
+struct Point2dFloat {
+    /** Boolean flag to indicate the (x, y) data is valid. */
+    bool isValid;
+
+    /** (x, y) data is only valid if isValid is true. Units are pixels or milli-meters. */
+    float x;
+    float y;
+};
+
+/** Structure representing a 3D point with floats. */
+struct Point3dFloat {
+    /** Boolean flag to indicate the (x, y, z) data is valid. */
+    bool isValid;
+
+    /**
+     * (x, y, z) data is only valid if isValid is true. Units are milli-meters.
+     */
+    float x;
+    float y;
+    float z;
+};
+
+/**
+ * Structure defining the pose in 3D space.
+ */
+struct Pose {
+    /**
+     * Rotation part of the pose, expressed as a unit quaternion.
+     */
+    RotationQuat rotation;
+
+    /**
+     * Translation part of the pose, in (x, y, z) format with milli-meter units.
+     */
+    Translation translation;
+};
+
+/**
+ * Struct defining a virtual view in the 3d space around the car.
+ */
+struct View3d {
+    /**
+     * Id to identify each custom view, this is passed along in each result SvBuffer.
+     * Recommend client to have a unique id for each different view.
+     */
+    uint32_t viewId;
+
+    /**
+     * Pose of the view. Describes the orientation and location of a virtual view relative to the
+     * android automotive coordinate system:
+     * https://source.android.com/devices/sensors/sensor-types#auto_axes
+     * The virtual view axes are defined as +Y as look-at direction, +X as right direction and
+     * +Z as up direction.
+     * The rotation and translation of the virtual view axes w.r.t the android automotive axes is
+     * specified by the rotation and tranlation component of the pose respectively.
+     * Example: A virtual view points to the right face of the car, located on right side of
+     * the car at (4, 2, 0) and is upright w.r.t the ground :
+     *         ______
+     *  front |      |
+     *        | car  |    ↑X
+     *        |  ↑Y  |  Y←∘  view
+     *  rear  |  ∘→X |  (4,2)
+     *        |(0,0) |
+     *        |______|
+     *
+     * Here the view axes are rotated by 90 counter-clockwise w.r.t android automotive axes.
+     * For this example the rotation and translation will be:
+     * Rotation = + 90 degrees around Z axis = (0.7071, 0, 0, 0.7071) as a unit quaternion.
+     * Translation = (4, 2, 0) in meters = (2000, 4000, 0) in milli-meters.
+     */
+    Pose pose;
+
+    /**
+     * Horizontal field of view of the virtual view in degrees. Vertical fov is scaled accordingly
+     * to maintain the aspect ratio of the output frame. Must be in range (20,
+     */
+    float horizontalFov;
+};
+
+/**
+ * Memory Buffer that stores the output of a single view from 2d/3d surround view.
+ */
+struct SvBuffer {
+    /**
+     * viewId identifying the view as passed by the client in setViews() call for
+     * surround view 3d. Id value is 0 for 2d surround view frame.
+     */
+    uint32_t viewId;
+
+    /** Hardware buffer containing the surround view 2d/3d result. */
+    HardwareBuffer hardwareBuffer;
+};
+
+/**
+ * Structure describing a set of frames to be returned as output from 2d/3d surround view.
+ */
+struct SvFramesDesc {
+    /**
+     * Elapsed real-time nanoseconds of earliest camera frame from the set of camera
+     * frames used to generate the view.
+     */
+    uint64_t timestampNs;
+
+    /**
+     * Incremental counter for client to keep track of frames.
+     */
+    uint32_t sequenceId;
+
+    /**
+     * Frames generated with different views.
+     * 2d surround view has only a single svBuffer with Id 0.
+     */
+    vec<SvBuffer> svBuffers;
+};
+
+/**
+ * Enumerator for list of result returns by surround view .
+ */
+enum SvResult : uint32_t {
+    /** Operation was successful. */
+    OK = 0,
+
+    /** Invalid argument to function was provided. */
+    INVALID_ARG,
+
+    /** Error indicating the particular operation is not supported. */
+    NOT_SUPPORTED,
+
+    /** Error indicating view not set before starting stream. */
+    VIEW_NOT_SET,
+
+    /**
+     * Error indicating system does not currently have enough resources to
+     * allocate for a new requested session.
+     * Clients may retry request for session if resources become available.
+     */
+    NO_RESOURCE,
+
+    /** Internal error in surround view service. */
+    INTERNAL_ERROR,
+};
+
+/**
+ * Enumerator listing events for surround view.
+ */
+enum SvEvent : uint32_t {
+    STREAM_STARTED = 1,
+
+    STREAM_STOPPED,
+
+    /**
+     * Event sent after service switches to an updated config, all frames
+     * streamed after this event are of the updated config.
+     */
+    CONFIG_UPDATED,
+
+    /** Each frame dropped will be notified with this event. */
+    FRAME_DROPPED,
+
+    /**
+     * Timeout event occurs if any individual camera stream has a timeout.
+     * Frames will not be delivered and clients must stop the stream.
+     */
+    TIMEOUT,
+};
+
+/**
+ * Structure defining the mapping information for 2d surround view.
+ *
+ * Mapping information provides the area on ground (width and height) and
+ * position w.r.t the car that the surround view 2d covers. This can be used for
+ * mapping (linear transformation) with other sensors whose data is available in
+ * the car coordinate system (eg. Ultrasonics).
+ * Axes and origin are as per the android automotive axes:
+ * https://source.android.com/devices/sensors/sensor-types#auto_axes
+ */
+struct Sv2dMappingInfo {
+    /** Width in milli-meters of the 2d surround view along the ground plane. */
+    float width;
+
+    /** Height in milli-meters of the 2d surround view along the ground plane. */
+    float height;
+
+    /**
+     * Coordinates (x, y) of the center of the view in android automotive coordinate system on the
+     * ground plane. Units are milli-meters.
+     */
+    Point2dFloat center;
+};
+
+/**
+ * Enumerator for quality presets for 2d/3d surround view.
+ * Details of each preset are specified in the respective 2d/3d config structures.
+ */
+enum SvQuality : uint32_t {
+    HIGH = 0,
+    LOW,
+};
+
+/** Structure for surround view 2d configuration. */
+struct Sv2dConfig {
+    /**
+     * Desired output width in pixels. Must be in range (0, 4096].
+     * Height is computed keeping the aspect ratio of the mapping info,
+     * Example: If width = 1080 px and mapping_width = 5000 mm, mapping_height = 10000 mm.
+     *          then, height = width * (mapping_height / mapping_width) = 2160 px.
+     * Height is set to the floor value in case of (mapping_height / mapping_width) is not integer.
+     * Mapping width, height is fixed for a car and is based on camera parameters and their ground
+     * coverage.
+     */
+    uint32_t width;
+
+    /**
+     * Blending quality preset to use.
+     * HIGH: High quality blending (eg. multiband blending) that consumes more resources.
+     * LOW: Low quality blending (eg. alpha blending) that consumes less resources.
+     */
+    SvQuality blending;
+};
+
+/** Structure for surround view 3d configuration. */
+struct Sv3dConfig {
+    /** Desired output width in pixels. Must be in range (0, 4096]. */
+    uint32_t width;
+
+    /** Desired output height in pixels. Must be in range (0, 4096]. */
+    uint32_t height;
+
+    /**
+     * Car model rendering details level.
+     * HIGH: Rendering includes shadows and reflections. Default option.
+     * LOW: Rendering with no shadows and reflections.
+     */
+    SvQuality carDetails;
+};
+
+/**
+ * Enumerator for a list of overlay primitives.
+ *
+ * Given a list of vertices for an overlay, a primitive type defines which vertices are used to form
+ * the surfaces of the overlay object.
+ */
+enum OverlayPrimitive : uint32_t {
+    /**
+     * Consecutive vertices picked in order 3 at a time form a triangle.
+     * Eg: In a list of vertices (V1, V2, V3, V4, V5, V6)
+     * (V1, V2, V3) form a triangle and (V4, V5, V6) form a triangle.
+     */
+    TRIANGLES = 0,
+
+    /**
+     * Every 3 consecutive vertices form a triangle.
+     * Example in a list of vertices V1, V2, V3, V4, V5, V6
+     * (V1, V2, V3), (V2, V3, V4), (V3, V4, V5) and (V4, V5, V6) form triangles.
+     */
+    TRIANGLES_STRIP,
+};
+
+/**
+ * Structure identifying an overlay and describing the size and arrangement of its data in
+ * shared memory.
+ */
+struct OverlayMemoryDesc {
+    /** Identifier of the overlay. */
+    uint16_t id;
+
+    /** Number of vertices in the overlay. */
+    uint32_t verticesCount;
+
+    /** Primitive for the overlay. */
+    OverlayPrimitive overlayPrimitive;
+};
+
+/**
+ *  Structure containing the overlays data in shared memory.
+ */
+struct OverlaysData {
+    /** List of overlay memory descriptors, describing the data in the shared memory */
+    vec<OverlayMemoryDesc> overlaysMemoryDesc;
+
+    /**
+     * Shared memory object containing a list of vertices for each overlay as described by
+     * overlaysMemoryDesc.
+     *
+     * Each vertex comprises of:
+     * | PositionX | PositionY | PositionZ |   RGBA       |
+     * |   float   |   float   |   float   |  4 * uint8_t |
+     *
+     * Each vertex is of 3 floats and 4 bytes = 16 bytes.
+     *
+     * Layout of vertices in shared memory is in order:
+     *
+     * Bytes: | 0-1 | 2-18 | 19-34 | 35-50 | 51-66 | 67-68 | 69-84 | 85-100 | 101-116  |...
+     * Data:  | id1 |  V1  |  V2   |   V3  |   V4  |  id2  |   V1  |   V2   |  V3      |...
+     *        |           overlay1                 |          overlay 2                |
+     *
+     * The order of overlays must match the order as specified in the overlaysMemoryDesc.
+     * The number of vertices each overlay has must match the verticesCount in overlaysMemoryDesc.
+     * The id must match the id specificed in the OverlayMemoryDesc. This is used for verification.
+     * For each overlay the number of vertices must be 3 or greater.
+     * For TRIANGLES primitive the number of vertices must be a multiple of 3.
+     * The overlay vertices are grouped as per the overlayPrimitive specified in overlaysMemoryDesc,
+     * eg: If primitive is TRIANGLES, (V1, V2, V3) and (V4, V5, V6) form a triangle.
+     */
+    memory overlaysMemory;
+};
diff --git a/automotive/sv/1.0/vts/functional/Android.bp b/automotive/sv/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..0e5d3df
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/Android.bp
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalSurroundViewV1_0TargetTest",
+    srcs: [
+        "VtsHalSurroundViewV1_0TargetTest.cpp",
+        "SurroundViewStreamHandler.cpp",
+    ],
+    defaults: ["VtsHalTargetTestDefaults"],
+    static_libs: [
+        "libnativewindow",
+        "android.hardware.automotive.sv@1.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+    ],
+    shared_libs: [
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+    ],
+    test_suites: ["general-tests", "vts-core"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp
new file mode 100644
index 0000000..cb45caa
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurroundViewStreamHandler.h"
+
+#include <utils/Log.h>
+
+using std::lock_guard;
+
+SurroundViewServiceHandler::SurroundViewServiceHandler(sp<ISurroundViewSession> pSession) :
+    mSession(pSession),
+    mReceiveFramesCount(0),
+    mDoNotReturnFrames(false) {
+    // Nothing but member initialization
+}
+
+Return<void> SurroundViewServiceHandler::notify(SvEvent svEvent) {
+    ALOGD("SurroundViewServiceHandler::notify %d", svEvent);
+
+    lock_guard<mutex> lock(mLock);
+    switch (svEvent) {
+        case SvEvent::STREAM_STARTED:
+        case SvEvent::CONFIG_UPDATED:
+        case SvEvent::STREAM_STOPPED:
+        case SvEvent::FRAME_DROPPED:
+        case SvEvent::TIMEOUT:
+            mReceivedEvents.emplace_back(svEvent);
+            break;
+        default:
+            ALOGI("[SurroundViewLog] Received other event");
+    }
+
+    return android::hardware::Void();
+}
+
+Return<void> SurroundViewServiceHandler::receiveFrames(const SvFramesDesc& svFramesDesc) {
+    ALOGD("SurroundViewServiceHandler::receiveFrames");
+
+    lock_guard<mutex> lock(mLock);
+    unsigned long timestampNs = svFramesDesc.timestampNs;
+    unsigned sequenceId = svFramesDesc.sequenceId;
+    ALOGD("receiveFrames count: %d", mReceiveFramesCount);
+    ALOGD("timestampNs: %lu, sequenceId: %u", timestampNs, sequenceId);
+    if (mReceiveFramesCount != 0
+        && (mLastReceivedFrames.timestampNs >= svFramesDesc.timestampNs
+            || mLastReceivedFrames.sequenceId >= svFramesDesc.sequenceId)) {
+        mAllFramesValid = false;
+        ALOGD("The incoming frames are with invalid timestamp or sequenceId!");
+    }
+
+    for (int i=0; i<svFramesDesc.svBuffers.size(); i++) {
+        if (svFramesDesc.svBuffers[i].hardwareBuffer.nativeHandle == nullptr) {
+            mAllFramesValid = false;
+            ALOGD("The incoming frames are with invalid nativeHandle!");
+            break;
+        }
+    }
+
+    mReceiveFramesCount++;
+
+    // Store all the information except for the handle
+    mLastReceivedFrames.timestampNs = svFramesDesc.timestampNs;
+    mLastReceivedFrames.sequenceId = svFramesDesc.sequenceId;
+    mLastReceivedFrames.svBuffers.resize(svFramesDesc.svBuffers.size());
+    for (int i=0; i<svFramesDesc.svBuffers.size(); i++) {
+        mLastReceivedFrames.svBuffers[i].viewId = svFramesDesc.svBuffers[i].viewId;
+        mLastReceivedFrames.svBuffers[i].hardwareBuffer.description =
+            svFramesDesc.svBuffers[i].hardwareBuffer.description;
+    }
+
+    if (!mDoNotReturnFrames) {
+        mSession->doneWithFrames(svFramesDesc);
+    }
+
+    return android::hardware::Void();
+}
+
+bool SurroundViewServiceHandler::checkEventReceived(SvEvent svEvent) {
+    ALOGD("SurroundViewServiceHandler::checkEventReceived");
+    int size = mReceivedEvents.size(); // work around
+    ALOGD("Received event number: %d", size);
+    auto iter = find(mReceivedEvents.begin(), mReceivedEvents.end(), svEvent);
+    return iter != mReceivedEvents.end();
+}
+
+SvFramesDesc SurroundViewServiceHandler::getLastReceivedFrames() {
+    return mLastReceivedFrames;
+}
+
+int SurroundViewServiceHandler::getReceiveFramesCount() {
+    return mReceiveFramesCount;
+}
+
+bool SurroundViewServiceHandler::areAllFramesValid() {
+    return mAllFramesValid;
+}
+
+void SurroundViewServiceHandler::setDoNotReturnFrames(bool flag) {
+    mDoNotReturnFrames = flag;
+}
diff --git a/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h
new file mode 100644
index 0000000..7d3f61d
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/SurroundViewStreamHandler.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SURROUND_VIEW_STREAM_HANDLER_H
+#define SURROUND_VIEW_STREAM_HANDLER_H
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewSession.h>
+
+#include <thread>
+#include <vector>
+
+using std::vector;
+using std::mutex;
+using android::hardware::Return;
+using android::sp;
+using namespace ::android::hardware::automotive::sv::V1_0;
+
+class SurroundViewServiceHandler : public ISurroundViewStream {
+public:
+    SurroundViewServiceHandler(sp<ISurroundViewSession> session);
+
+    Return<void> notify(SvEvent svEvent) override;
+    Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
+
+    bool checkEventReceived(SvEvent svEvent);
+    SvFramesDesc getLastReceivedFrames();
+    int getReceiveFramesCount();
+    bool areAllFramesValid();
+    void setDoNotReturnFrames(bool flag);
+
+private:
+    mutex mLock;
+
+    vector<SvEvent> mReceivedEvents;
+    sp<ISurroundViewSession> mSession;
+    SvFramesDesc mLastReceivedFrames; // only use timestampNs and sequenceId
+    int mReceiveFramesCount; // TODO(haoxiangl): figure out a better name
+    bool mAllFramesValid = true;
+    bool mDoNotReturnFrames;
+};
+
+#endif //SURROUND_VIEW_STREAM_HANDLER_H
diff --git a/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
new file mode 100644
index 0000000..b1b9d16
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
@@ -0,0 +1,1137 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#define LOG_TAG "VtsHalSurroundViewTest"
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <android/hardware_buffer.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+#include <math.h>
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "SurroundViewStreamHandler.h"
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::hidl_memory;
+
+const int kVertexByteSize = (3 * sizeof(float)) + 4;
+const int kIdByteSize = 2;
+
+// The main test class for Surround View Service
+class SurroundViewHidlTest : public ::testing::TestWithParam<std::string> {
+public:
+    virtual void SetUp() override {
+        mSurroundViewService = ISurroundViewService::getService(GetParam());
+        ASSERT_NE(mSurroundViewService.get(), nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+    sp<ISurroundViewService> mSurroundViewService;    // Every test needs access to the service
+};
+
+TEST_P(SurroundViewHidlTest, startAndStop2dSession) {
+    ALOGD("SurroundViewHidlTest::startAndStop2dSession");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    SvResult result = mSurroundViewService->stop2dSession(surroundView2dSession);
+    ASSERT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, stopInvalid2dSession) {
+    ALOGD("SurroundViewHidlTest::stopInvalid2dSession");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    SvResult result = mSurroundViewService->stop2dSession(surroundView2dSession);
+    ASSERT_NE(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, startAndStop2dStream) {
+    ALOGD("SurroundViewHidlTest::startAndStop2dStream");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+    surroundView2dSession->stopStream();
+
+    sleep(1);
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+    result = mSurroundViewService->stop2dSession(surroundView2dSession);
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, start2dStreamWithoutReturningFrames) {
+    ALOGD("SurroundViewHidlTest::start2dStreamWithoutReturningFrames");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+    handler->setDoNotReturnFrames(true);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::FRAME_DROPPED));
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+    surroundView2dSession->stopStream();
+
+    sleep(1);
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+    result = mSurroundViewService->stop2dSession(surroundView2dSession);
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, duplicateStart2dStream) {
+    ALOGD("SurroundViewHidlTest, duplicateStart2dStream");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    result = surroundView2dSession->startStream(handler);
+    EXPECT_NE(result, SvResult::OK);
+
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, stopInvalid2dStream) {
+    ALOGD("SurroundViewHidlTest, stopInvalid2dStream");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, validate2dSvFramesDesc) {
+    ALOGD("SurroundViewHidlTest, validate2dSvFramesDesc");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    // Validate timestampNs and sequenceId
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+    EXPECT_TRUE(handler->areAllFramesValid());
+
+    // Validate 2d SvFramesDesc. Do not compare nativeHandle since it is not
+    // stored and already verified on the fly.
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+
+    SvBuffer svBuffer2d = frames.svBuffers[0];
+    EXPECT_EQ(svBuffer2d.viewId, 0);
+
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+    float mapWidth, mapHeight;
+    surroundView2dSession->get2dMappingInfo([&mapWidth, &mapHeight] (Sv2dMappingInfo info) {
+        mapWidth = info.width;
+        mapHeight = info.height;
+    });
+    EXPECT_EQ(pDesc->height, floor(pDesc->width * (mapHeight / mapWidth)));
+
+    // Clean up
+    surroundView2dSession->stopStream();
+    result = mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, get2dMappingInfo) {
+    ALOGD("SurroundViewHidlTest, get2dMappingInfo");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    surroundView2dSession->get2dMappingInfo([] (Sv2dMappingInfo info) {
+        EXPECT_GT(info.width, 0);
+        EXPECT_GT(info.height, 0);
+    });
+
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set2dConfigResolution) {
+    ALOGD("SurroundViewHidlTest, set2dConfigResolution");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Change config
+    Sv2dConfig config;
+    config.width = 1920;
+    config.blending = SvQuality::HIGH;
+    surroundView2dSession->set2dConfig(config);
+
+    sleep(1);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+    // Check width has been changed but not the ratio
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer2d = frames.svBuffers[0];
+    EXPECT_EQ(svBuffer2d.viewId, 0);
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+    EXPECT_EQ(pDesc->width, config.width);
+
+    float mapWidth, mapHeight;
+    surroundView2dSession->get2dMappingInfo([&mapWidth, &mapHeight] (Sv2dMappingInfo info) {
+        mapWidth = info.width;
+        mapHeight = info.height;
+    });
+    EXPECT_EQ(pDesc->height, floor (pDesc->width * (mapHeight / mapWidth)));
+
+    // Clean up
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set2dConfigBlending) {
+    ALOGD("SurroundViewHidlTest, set2dConfigBlending");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Get the width before config changed
+    int oldWidth;
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer2d = frames.svBuffers[0];
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+    oldWidth = pDesc->width;
+
+    // Change config
+    Sv2dConfig config;
+    config.width = oldWidth;
+    config.blending = SvQuality::LOW;
+    surroundView2dSession->set2dConfig(config);
+
+    sleep(1);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+    Sv2dConfig retConfig;
+    surroundView2dSession->get2dConfig([&retConfig] (Sv2dConfig config) {
+        retConfig.width = config.width;
+        retConfig.blending = config.blending;
+    });
+
+    // Check config blending has been changed but not the width
+    EXPECT_EQ(retConfig.blending, config.blending);
+    EXPECT_EQ(retConfig.width, oldWidth);
+
+    // Clean up
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectCameraPointsWithValidCameraId) {
+    ALOGD("SurroundViewHidlTest, projectCameraPointsWithValidCameraId");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    hidl_vec<hidl_string> cameraIds;
+    mSurroundViewService->getCameraIds([&cameraIds](
+            const hidl_vec<hidl_string>& camIds) {
+        cameraIds = camIds;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView2dSession);
+
+    SvResult result = surroundView2dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Get the width and height of the frame
+    int width, height;
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer2d = frames.svBuffers[0];
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+    width = pDesc->width;
+    height = pDesc->height;
+
+    float mapWidth, mapHeight, mapCenter[2];
+    surroundView2dSession->get2dMappingInfo(
+        [&mapWidth, &mapHeight, &mapCenter] (Sv2dMappingInfo info) {
+        mapWidth = info.width;
+        mapHeight = info.height;
+        mapCenter[0] = info.center.x;
+        mapCenter[1] = info.center.y;
+    });
+
+    // Set one valid point and one invalid point
+    hidl_vec<Point2dInt> points2dCamera;
+    points2dCamera.resize(2);
+    points2dCamera[0].x = 0;
+    points2dCamera[0].y = 0;
+    points2dCamera[1].x = width * 2;
+    points2dCamera[1].y = height * 2;
+
+    surroundView2dSession->projectCameraPoints(
+        points2dCamera,
+        cameraIds[0],
+        [&mapWidth, &mapHeight, &mapCenter] (
+            const hidl_vec<Point2dFloat>& outPoints) {
+            // Make sure point[0] is valid.
+            EXPECT_TRUE(outPoints[0].isValid);
+            EXPECT_GE(outPoints[0].x, mapCenter[0] - mapWidth);
+            EXPECT_LE(outPoints[0].x, mapCenter[0] + mapWidth);
+            EXPECT_GE(outPoints[0].y, mapCenter[1] - mapHeight);
+            EXPECT_LE(outPoints[0].y, mapCenter[1] + mapHeight);
+
+            // Make sure point[1] is invalid.
+            EXPECT_FALSE(outPoints[1].isValid);
+        });
+
+    // Clean up
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectCameraPointsWithInvalidCameraId) {
+    ALOGD("SurroundViewHidlTest, projectCameraPointsWithInvalidCameraId");
+    sp<ISurroundView2dSession> surroundView2dSession;
+    mSurroundViewService->start2dSession(
+        [&surroundView2dSession](
+            const sp<ISurroundView2dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView2dSession = session;
+    });
+
+    hidl_vec<hidl_string> cameraIds;
+    mSurroundViewService->getCameraIds([&cameraIds](
+            const hidl_vec<hidl_string>& camIds) {
+        cameraIds = camIds;
+    });
+
+    hidl_string invalidCameraId = "INVALID_CAMERA_ID";
+
+    // In case one of the camera id happens to be identical to
+    // the invalid camera id.
+    for (auto cameraId : cameraIds) {
+        ASSERT_NE(cameraId, invalidCameraId);
+    }
+
+    // Set one valid point
+    hidl_vec<Point2dInt> points2dCamera;
+    points2dCamera.resize(1);
+    points2dCamera[0].x = 0;
+    points2dCamera[0].y = 0;
+
+    surroundView2dSession->projectCameraPoints(
+        points2dCamera,
+        invalidCameraId,
+        [] (const hidl_vec<Point2dFloat>& outPoints) {
+            // No points are return due to invalid camera id
+            EXPECT_EQ(outPoints.size(), 0);
+        });
+
+    // Clean up
+    surroundView2dSession->stopStream();
+    mSurroundViewService->stop2dSession(surroundView2dSession);
+}
+
+TEST_P(SurroundViewHidlTest, startAndStop3dSession) {
+    ALOGD("SurroundViewHidlTest, startAndStop3dSession");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    SvResult result = mSurroundViewService->stop3dSession(surroundView3dSession);
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, stopInvalid3dSession) {
+    ALOGD("SurroundViewHidlTest, stopInvalid3dSession");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    SvResult result = mSurroundViewService->stop3dSession(surroundView3dSession);
+    EXPECT_NE(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, startAndStop3dStream) {
+    ALOGD("SurroundViewHidlTest::startAndStop3dStream");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::vector<View3d> views(1);
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+    surroundView3dSession->stopStream();
+
+    sleep(1);
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+    result = mSurroundViewService->stop3dSession(surroundView3dSession);
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, start3dStreamWithoutReturningFrames) {
+    ALOGD("SurroundViewHidlTest::start3dStreamWithoutReturningFrames");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::vector<View3d> views(1);
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+    handler->setDoNotReturnFrames(true);
+
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STARTED));
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::FRAME_DROPPED));
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+
+    surroundView3dSession->stopStream();
+
+    sleep(1);
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::STREAM_STOPPED));
+
+    result = mSurroundViewService->stop3dSession(surroundView3dSession);
+    EXPECT_EQ(result, SvResult::OK);
+}
+
+TEST_P(SurroundViewHidlTest, duplicateStart3dStream) {
+    ALOGD("SurroundViewHidlTest, duplicateStart3dStream");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::vector<View3d> views(1);
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    result = surroundView3dSession->startStream(handler);
+    EXPECT_NE(result, SvResult::OK);
+
+    surroundView3dSession->stopStream();
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, start3dStreamNoViewSetFail) {
+    ALOGD("SurroundViewHidlTest, start3dStreamNoViewSetFail");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::VIEW_NOT_SET);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, validate3dSvFramesDesc) {
+    ALOGD("SurroundViewHidlTest, validate3dSvFramesDesc");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    std::vector<View3d> views(1);
+    views[0].viewId = 0;
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(5);
+
+    EXPECT_GT(handler->getReceiveFramesCount(), 0);
+    EXPECT_TRUE(handler->areAllFramesValid());
+
+    // Validate 3d SvFramesDesc when only one view is set.
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    EXPECT_EQ(frames.svBuffers[0].viewId, 0);
+
+    views.resize(3);
+    views[0].viewId = 0;
+    views[1].viewId = 1;
+    views[2].viewId = 2;
+    setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+
+    sleep(1);
+
+    // Validate 3d SvFramesDesc when multiple views are set.
+    EXPECT_TRUE(handler->areAllFramesValid());
+    frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 3);
+    EXPECT_EQ(frames.svBuffers[0].viewId, 0);
+    EXPECT_EQ(frames.svBuffers[1].viewId, 1);
+    EXPECT_EQ(frames.svBuffers[2].viewId, 2);
+    EXPECT_EQ(frames.svBuffers[0].hardwareBuffer.description[0],
+              frames.svBuffers[1].hardwareBuffer.description[0]);
+    EXPECT_EQ(frames.svBuffers[0].hardwareBuffer.description[1],
+              frames.svBuffers[1].hardwareBuffer.description[1]);
+    EXPECT_EQ(frames.svBuffers[1].hardwareBuffer.description[0],
+              frames.svBuffers[2].hardwareBuffer.description[0]);
+    EXPECT_EQ(frames.svBuffers[1].hardwareBuffer.description[1],
+              frames.svBuffers[2].hardwareBuffer.description[1]);
+
+    // Clean up
+    surroundView3dSession->stopStream();
+    result = mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set3dConfigResolution) {
+    ALOGD("SurroundViewHidlTest, set3dConfigResolution");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    std::vector<View3d> views(1);
+    views[0].viewId = 0;
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Change config
+    Sv3dConfig config;
+    config.width = 1920;
+    config.height = 1080;
+    config.carDetails = SvQuality::HIGH;
+    surroundView3dSession->set3dConfig(config);
+
+    sleep(1);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+    // Check width has been changed but not the ratio
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer3d = frames.svBuffers[0];
+    EXPECT_EQ(svBuffer3d.viewId, 0);
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer3d.hardwareBuffer.description);
+    EXPECT_EQ(pDesc->width, config.width);
+    EXPECT_EQ(pDesc->height, config.height);
+
+    // Clean up
+    surroundView3dSession->stopStream();
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, set3dConfigCarDetails) {
+    ALOGD("SurroundViewHidlTest, set3dConfigCarDetails");
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    std::vector<View3d> views(1);
+    views[0].viewId = 0;
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Get the width before config changed
+    int oldWidth, oldHeight;
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer3d = frames.svBuffers[0];
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer3d.hardwareBuffer.description);
+    oldWidth = pDesc->width;
+    oldHeight = pDesc->height;
+
+    // Change config
+    Sv3dConfig config;
+    config.width = oldWidth;
+    config.height = oldHeight;
+    config.carDetails = SvQuality::LOW;
+    surroundView3dSession->set3dConfig(config);
+
+    sleep(1);
+
+    EXPECT_TRUE(handler->checkEventReceived(SvEvent::CONFIG_UPDATED));
+
+    Sv3dConfig retConfig;
+    surroundView3dSession->get3dConfig([&retConfig] (Sv3dConfig config) {
+        retConfig.width = config.width;
+        retConfig.height = config.height;
+        retConfig.carDetails = config.carDetails;
+    });
+
+    // Check config blending has been changed but not the width
+    EXPECT_EQ(retConfig.carDetails, config.carDetails);
+    EXPECT_EQ(retConfig.width, oldWidth);
+    EXPECT_EQ(retConfig.height, oldHeight);
+
+    // Clean up
+    surroundView3dSession->stopStream();
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+std::pair<hidl_memory, sp<IMemory>> GetMappedSharedMemory(int bytesSize) {
+
+    const auto nullResult = std::make_pair(hidl_memory(), nullptr);
+
+    sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
+    if (ashmemAllocator.get() == nullptr) {
+        ALOGE("SurroundViewHidlTest getService ashmem failed");
+        return nullResult;
+    }
+
+    // Allocate shared memory.
+    hidl_memory hidlMemory;
+    bool allocateSuccess = false;
+    Return<void> result = ashmemAllocator->allocate(bytesSize,
+            [&](bool success, const hidl_memory& hidlMem) {
+                if (!success) {
+                    return;
+                }
+                allocateSuccess = success;
+                hidlMemory = hidlMem;
+            });
+
+    // Check result of allocated memory.
+    if (!result.isOk() || !allocateSuccess) {
+        ALOGE("SurroundViewHidlTest allocate shared memory failed");
+        return nullResult;
+    }
+
+    // Map shared memory.
+    sp<IMemory> pIMemory = mapMemory(hidlMemory);
+    if (pIMemory.get() == nullptr) {
+        ALOGE("SurroundViewHidlTest map shared memory failed");
+        return nullResult;
+    }
+
+    return std::make_pair(hidlMemory, pIMemory);
+}
+
+void SetIndexOfOverlaysMemory(
+        const std::vector<OverlayMemoryDesc>& overlaysMemDesc,
+        sp<IMemory> pIMemory, int indexPosition, uint16_t indexValue) {
+
+    // Count the number of vertices until the index.
+    int totalVerticesCount = 0;
+    for (int i = 0; i < indexPosition; i++) {
+        totalVerticesCount += overlaysMemDesc[i].verticesCount;
+    }
+
+    const int indexBytePosition = (indexPosition * kIdByteSize) +
+            (kVertexByteSize * totalVerticesCount);
+
+    uint8_t* pSharedMemoryData = (uint8_t*)((void*)pIMemory->getPointer());
+    pSharedMemoryData += indexBytePosition;
+    uint16_t* pIndex16bit = (uint16_t*)pSharedMemoryData;
+
+    ALOGD("Setting index at pos %d", indexBytePosition);
+
+    // Modify shared memory.
+    pIMemory->update();
+    *pIndex16bit = indexValue;
+    pIMemory->commit();
+}
+
+std::pair<OverlaysData, sp<IMemory>> GetSampleOverlaysData() {
+    OverlaysData overlaysData;
+    overlaysData.overlaysMemoryDesc.resize(2);
+
+    int sharedMemBytesSize = 0;
+    OverlayMemoryDesc overlayMemDesc1, overlayMemDesc2;
+    overlayMemDesc1.id = 0;
+    overlayMemDesc1.verticesCount = 6;
+    overlayMemDesc1.overlayPrimitive = OverlayPrimitive::TRIANGLES;
+    overlaysData.overlaysMemoryDesc[0] = overlayMemDesc1;
+    sharedMemBytesSize += kIdByteSize +
+            kVertexByteSize * overlayMemDesc1.verticesCount;
+
+    overlayMemDesc2.id = 1;
+    overlayMemDesc2.verticesCount = 4;
+    overlayMemDesc2.overlayPrimitive = OverlayPrimitive::TRIANGLES_STRIP;
+    overlaysData.overlaysMemoryDesc[1] = overlayMemDesc2;
+    sharedMemBytesSize += kIdByteSize +
+            kVertexByteSize * overlayMemDesc2.verticesCount;
+
+    std::pair<hidl_memory, sp<IMemory>> sharedMem =
+            GetMappedSharedMemory(sharedMemBytesSize);
+    sp<IMemory> pIMemory = sharedMem.second;
+    if (pIMemory.get() == nullptr) {
+        return std::make_pair(OverlaysData(), nullptr);
+    }
+
+    // Get pointer to shared memory data and set all bytes to 0.
+    uint8_t* pSharedMemoryData = (uint8_t*)((void*)pIMemory->getPointer());
+    pIMemory->update();
+    memset(pSharedMemoryData, 0, sharedMemBytesSize);
+    pIMemory->commit();
+
+    std::vector<OverlayMemoryDesc> overlaysDesc = {overlayMemDesc1,
+            overlayMemDesc2};
+
+    // Set indexes in shared memory.
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 0, overlayMemDesc1.id);
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, overlayMemDesc2.id);
+
+    overlaysData.overlaysMemoryDesc = overlaysDesc;
+    overlaysData.overlaysMemory = sharedMem.first;
+
+    return std::make_pair(overlaysData, pIMemory);
+}
+
+TEST_P(SurroundViewHidlTest, updateOverlaysSuccess) {
+    ALOGD("SurroundViewHidlTest, updateOverlaysSuccess");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::pair<OverlaysData, sp<IMemory>> overlaysData = GetSampleOverlaysData();
+    ASSERT_NE(overlaysData.second, nullptr);
+
+    SvResult result = surroundView3dSession->updateOverlays(overlaysData.first);
+    EXPECT_EQ(result, SvResult::OK);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataMismatchIdFail) {
+    ALOGD("SurroundViewHidlTest, overlaysDataMismatchIdFail");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::pair<OverlaysData, sp<IMemory>> overlaysDataMismatchId
+            = GetSampleOverlaysData();
+    ASSERT_NE(overlaysDataMismatchId.second, nullptr);
+
+    // Set id of second overlay in shared memory to 2 (expected is 1).
+    auto& overlaysDesc = overlaysDataMismatchId.first.overlaysMemoryDesc;
+    auto& pIMemory = overlaysDataMismatchId.second;
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, 2);
+
+    SvResult result = surroundView3dSession->updateOverlays(
+            overlaysDataMismatchId.first);
+    EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataNullMemoryFail) {
+    ALOGD("SurroundViewHidlTest, overlaysDataNullMemoryFail");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::pair<OverlaysData, sp<IMemory>> overlaysDataNullMemory
+            = GetSampleOverlaysData();
+
+    // Set shared memory to null.
+    overlaysDataNullMemory.first.overlaysMemory = hidl_memory();
+
+    SvResult result = surroundView3dSession->updateOverlays(
+            overlaysDataNullMemory.first);
+    EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataLessThan3VerticesFail) {
+    ALOGD("SurroundViewHidlTest, overlaysDataLessThan3VerticesFail");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::pair<OverlaysData, sp<IMemory>> overlaysData2Vertices
+            = GetSampleOverlaysData();
+
+    // Set vertices count of second overlay to 2.
+    overlaysData2Vertices.first.overlaysMemoryDesc[1].verticesCount = 2;
+
+    SvResult result = surroundView3dSession->updateOverlays(
+            overlaysData2Vertices.first);
+    EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataVerticesCountFail) {
+    ALOGD("SurroundViewHidlTest, overlaysDataVerticesNotMultipleOf3Fail");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    OverlaysData overlaysData;
+    overlaysData.overlaysMemoryDesc.resize(1);
+
+    OverlayMemoryDesc overlayMemDesc1;
+    overlayMemDesc1.id = 0;
+    overlayMemDesc1.verticesCount = 4; // Invalid count for TRIANGLES primitive.
+    overlayMemDesc1.overlayPrimitive = OverlayPrimitive::TRIANGLES;
+    overlaysData.overlaysMemoryDesc[0] = overlayMemDesc1;
+
+    const int sharedMemBytesSize =
+            2 + sizeof(float) * overlayMemDesc1.verticesCount;
+    auto sharedMem = GetMappedSharedMemory(sharedMemBytesSize);
+
+    // Set index in shared memory.
+    auto& overlaysDesc = overlaysData.overlaysMemoryDesc;
+    auto& pIMemory = sharedMem.second;
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 0, overlayMemDesc1.id);
+
+    SvResult result = surroundView3dSession->updateOverlays(overlaysData);
+    EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, overlaysDataSameIdFail) {
+    ALOGD("SurroundViewHidlTest, overlaysDataSameIdFail");
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    std::pair<OverlaysData, sp<IMemory>> overlaysDataSameId
+            = GetSampleOverlaysData();
+    ASSERT_NE(overlaysDataSameId.second, nullptr);
+
+    // Set id of second overlay as id of first.
+    auto& overlaysDesc = overlaysDataSameId.first.overlaysMemoryDesc;
+        auto& pIMemory = overlaysDataSameId.second;
+    SetIndexOfOverlaysMemory(overlaysDesc, pIMemory, 1, overlaysDesc[0].id);
+
+    SvResult result = surroundView3dSession->updateOverlays(
+            overlaysDataSameId.first);
+    EXPECT_EQ(result, SvResult::INVALID_ARG);
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectPointsIncorrectCameraIdFail) {
+    ALOGD("SurroundViewHidlTest, projectPointsIncorrectCameraIdFail");
+
+    hidl_vec<hidl_string> cameraIds;
+    mSurroundViewService->getCameraIds([&cameraIds](
+            const hidl_vec<hidl_string>& camIds) {
+        cameraIds = camIds;
+    });
+    EXPECT_GT(cameraIds.size(), 0);
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    Point2dInt cameraPoint;
+    cameraPoint.x = 0;
+    cameraPoint.y = 0;
+    std::vector<Point2dInt> cameraPoints = {cameraPoint};
+
+    hidl_string invalidCameraId = "INVALID_CAMERA_ID";
+
+    std::vector<Point3dFloat> points3d;
+    surroundView3dSession->projectCameraPointsTo3dSurface(
+        cameraPoints, invalidCameraId,
+        [&points3d](const hidl_vec<Point3dFloat>& points3dproj) {
+                points3d = points3dproj;
+            });
+
+    EXPECT_TRUE(points3d.empty());
+
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+TEST_P(SurroundViewHidlTest, projectPointsInvalidPointsFail) {
+    ALOGD("SurroundViewHidlTest, projectPointsInvalidPointsFail");
+
+    hidl_vec<hidl_string> cameraIds;
+    mSurroundViewService->getCameraIds([&cameraIds](
+            const hidl_vec<hidl_string>& camIds) {
+        cameraIds = camIds;
+    });
+
+    EXPECT_GT(cameraIds.size(), 0);
+
+    sp<ISurroundView3dSession> surroundView3dSession;
+    mSurroundViewService->start3dSession(
+        [&surroundView3dSession](
+            const sp<ISurroundView3dSession>& session, SvResult result) {
+        ASSERT_EQ(result, SvResult::OK);
+        surroundView3dSession = session;
+    });
+
+    sp<SurroundViewServiceHandler> handler =
+        new SurroundViewServiceHandler(surroundView3dSession);
+
+    std::vector<View3d> views(1);
+    views[0].viewId = 0;
+    SvResult setViewResult = surroundView3dSession->setViews(views);
+    EXPECT_EQ(setViewResult, SvResult::OK);
+    SvResult result = surroundView3dSession->startStream(handler);
+    EXPECT_EQ(result, SvResult::OK);
+
+    sleep(1);
+
+    // Get the width and height of the frame
+    int width, height;
+    SvFramesDesc frames = handler->getLastReceivedFrames();
+    EXPECT_EQ(frames.svBuffers.size(), 1);
+    SvBuffer svBuffer2d = frames.svBuffers[0];
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&svBuffer2d.hardwareBuffer.description);
+    width = pDesc->width;
+    height = pDesc->height;
+
+    Point2dInt cameraPoint;
+    cameraPoint.x = width * 2;
+    cameraPoint.y = height * 2;
+    std::vector<Point2dInt> cameraPoints = {cameraPoint};
+
+    std::vector<Point3dFloat> points3d;
+    surroundView3dSession->projectCameraPointsTo3dSurface(
+              cameraPoints, cameraIds[0],
+        [&points3d](const hidl_vec<Point3dFloat>& points3dproj) {
+                points3d = points3dproj;
+            });
+
+    EXPECT_FALSE(points3d[0].isValid);
+
+    surroundView3dSession->stopStream();
+    mSurroundViewService->stop3dSession(surroundView3dSession);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance,
+    SurroundViewHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(ISurroundViewService::descriptor)
+    ),
+    android::hardware::PrintInstanceNameToString
+);
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index ed09859..e529675 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -47,6 +47,9 @@
         "common/src/VehicleUtils.cpp",
         "common/src/VmsUtils.cpp",
     ],
+    shared_libs: [
+        "libbase",
+    ],
     local_include_dirs: ["common/include/vhal_v2_0"],
     export_include_dirs: ["common/include"],
 }
@@ -58,9 +61,13 @@
     defaults: ["vhal_v2_0_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",
@@ -93,10 +100,28 @@
         "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_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"],
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
index d1fd555..127eb98 100644
--- a/automotive/vehicle/2.0/default/VehicleService.cpp
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -20,8 +20,9 @@
 
 #include <iostream>
 
-#include <vhal_v2_0/VehicleHalManager.h>
+#include <vhal_v2_0/EmulatedVehicleConnector.h>
 #include <vhal_v2_0/EmulatedVehicleHal.h>
+#include <vhal_v2_0/VehicleHalManager.h>
 
 using namespace android;
 using namespace android::hardware;
@@ -29,9 +30,11 @@
 
 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 hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get());
     auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
     auto service = std::make_unique<VehicleHalManager>(hal.get());
+    connector->setValuePool(hal->getValuePool());
 
     configureRpcThreadpool(4, true /* callerWillJoin */);
 
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..e3cbf2e 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>
 
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/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index 393d3ec..5bebd1e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -21,11 +21,20 @@
 #include <cmath>
 #include <fstream>
 
-#include <android/log.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
 #include <android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h>
+#include <android/log.h>
+
+#include <hwbinder/IPCThreadState.h>
+
+#include <utils/SystemClock.h>
 
 #include "VehicleUtils.h"
 
+// TODO: figure out how to include private/android_filesystem_config.h instead...
+#define AID_ROOT 0 /* traditional unix root user */
+
 namespace android {
 namespace hardware {
 namespace automotive {
@@ -34,6 +43,10 @@
 
 using namespace std::placeholders;
 
+using ::android::base::EqualsIgnoreCase;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+
 constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10);
 
 const VehiclePropValue kEmptyValue{};
@@ -172,6 +185,251 @@
     return Void();
 }
 
+Return<void> VehicleHalManager::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds == 0) {
+        ALOGE("Invalid parameters passed to debug()");
+        return Void();
+    }
+
+    bool shouldContinue = mHal->dump(fd, options);
+    if (!shouldContinue) {
+        ALOGI("Dumped HAL only");
+        return Void();
+    }
+
+    // Do our dump
+    cmdDump(fd->data[0], options);
+    return Void();
+}
+
+void VehicleHalManager::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
+    if (options.size() == 0) {
+        cmdDumpAllProperties(fd);
+        return;
+    }
+    std::string option = options[0];
+    if (EqualsIgnoreCase(option, "--help")) {
+        cmdHelp(fd);
+    } else if (EqualsIgnoreCase(option, "--list")) {
+        cmdListAllProperties(fd);
+    } else if (EqualsIgnoreCase(option, "--get")) {
+        cmdDumpSpecificProperties(fd, options);
+    } else if (EqualsIgnoreCase(option, "--set")) {
+        cmdSetOneProperty(fd, options);
+    } else {
+        dprintf(fd, "Invalid option: %s\n", option.c_str());
+    }
+}
+
+bool VehicleHalManager::checkCallerHasWritePermissions(int fd) {
+    // Double check that's only called by root - it should be be blocked at the HIDL debug() level,
+    // but it doesn't hurt to make sure...
+    if (hardware::IPCThreadState::self()->getCallingUid() != AID_ROOT) {
+        dprintf(fd, "Must be root\n");
+        return false;
+    }
+    return true;
+}
+
+bool VehicleHalManager::checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options,
+                                           size_t minSize) {
+    size_t size = options.size();
+    if (size >= minSize) {
+        return true;
+    }
+    dprintf(fd, "Invalid number of arguments: required at least %zu, got %zu\n", minSize, size);
+    return false;
+}
+
+bool VehicleHalManager::safelyParseInt(int fd, int index, std::string s, int* out) {
+    if (!android::base::ParseInt(s, out)) {
+        dprintf(fd, "non-integer argument at index %d: %s\n", index, s.c_str());
+        return false;
+    }
+    return true;
+}
+
+void VehicleHalManager::cmdHelp(int fd) const {
+    dprintf(fd, "Usage: \n\n");
+    dprintf(fd, "[no args]: dumps (id and value) all supported properties \n");
+    dprintf(fd, "--help: shows this help\n");
+    dprintf(fd, "--list: lists the ids of all supported properties\n");
+    dprintf(fd, "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n");
+    // TODO: support other formats (int64, float, bytes)
+    dprintf(fd,
+            "--set <PROP> <i|s> <VALUE_1> [<i|s> <VALUE_N>] [a AREA_ID] : sets the value of "
+            "property PROP, using arbitrary number of key/value parameters (i for int32, "
+            "s for string) and an optional area.\n"
+            "Notice that the string value can be set just once, while the other can have multiple "
+            "values (so they're used in the respective array)\n");
+}
+
+void VehicleHalManager::cmdListAllProperties(int fd) const {
+    auto& halConfig = mConfigIndex->getAllConfigs();
+    size_t size = halConfig.size();
+    if (size == 0) {
+        dprintf(fd, "no properties to list\n");
+        return;
+    }
+    int i = 0;
+    dprintf(fd, "listing %zu properties\n", size);
+    for (const auto& config : halConfig) {
+        dprintf(fd, "%d: %d\n", ++i, config.prop);
+    }
+}
+
+void VehicleHalManager::cmdDumpAllProperties(int fd) {
+    auto& halConfig = mConfigIndex->getAllConfigs();
+    size_t size = halConfig.size();
+    if (size == 0) {
+        dprintf(fd, "no properties to dump\n");
+        return;
+    }
+    int rowNumber = 0;
+    dprintf(fd, "dumping %zu properties\n", size);
+    for (auto& config : halConfig) {
+        cmdDumpOneProperty(fd, ++rowNumber, config);
+    }
+}
+
+void VehicleHalManager::cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config) {
+    size_t numberAreas = config.areaConfigs.size();
+    if (numberAreas == 0) {
+        if (rowNumber > 0) {
+            dprintf(fd, "%d: ", rowNumber);
+        }
+        cmdDumpOneProperty(fd, config.prop, /* areaId= */ 0);
+        return;
+    }
+    for (size_t j = 0; j < numberAreas; ++j) {
+        if (rowNumber > 0) {
+            if (numberAreas > 1) {
+                dprintf(fd, "%d/%zu: ", rowNumber, j);
+            } else {
+                dprintf(fd, "%d: ", rowNumber);
+            }
+        }
+        cmdDumpOneProperty(fd, config.prop, config.areaConfigs[j].areaId);
+    }
+}
+
+void VehicleHalManager::cmdDumpSpecificProperties(int fd, const hidl_vec<hidl_string>& options) {
+    if (!checkArgumentsSize(fd, options, 2)) return;
+
+    // options[0] is the command itself...
+    int rowNumber = 0;
+    size_t size = options.size();
+    for (size_t i = 1; i < size; ++i) {
+        int prop;
+        if (!safelyParseInt(fd, i, options[i], &prop)) return;
+        const auto* config = getPropConfigOrNull(prop);
+        if (config == nullptr) {
+            dprintf(fd, "No property %d\n", prop);
+            continue;
+        }
+        if (size > 2) {
+            // Only show row number if there's more than 1
+            rowNumber++;
+        }
+        cmdDumpOneProperty(fd, rowNumber, *config);
+    }
+}
+
+void VehicleHalManager::cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId) {
+    VehiclePropValue input;
+    input.prop = prop;
+    input.areaId = areaId;
+    auto callback = [&](StatusCode status, const VehiclePropValue& output) {
+        if (status == StatusCode::OK) {
+            dprintf(fd, "%s\n", toString(output).c_str());
+        } else {
+            dprintf(fd, "Could not get property %d. Error: %s\n", prop, toString(status).c_str());
+        }
+    };
+    get(input, callback);
+}
+
+void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) {
+    if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return;
+
+    size_t size = options.size();
+
+    // Syntax is --set PROP Type1 Value1 TypeN ValueN, so number of arguments must be even
+    if (size % 2 != 0) {
+        dprintf(fd, "must pass even number of arguments (passed %zu)\n", size);
+        return;
+    }
+    int numberValues = (size - 2) / 2;
+
+    VehiclePropValue prop;
+    if (!safelyParseInt(fd, 1, options[1], &prop.prop)) return;
+    prop.timestamp = elapsedRealtimeNano();
+    prop.status = VehiclePropertyStatus::AVAILABLE;
+
+    // First pass: calculate sizes
+    int sizeInt32 = 0;
+    int stringIndex = 0;
+    int areaIndex = 0;
+    for (int i = 2, kv = 1; kv <= numberValues; kv++) {
+        // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step
+        std::string type = options[i];
+        std::string value = options[i + 1];
+        if (EqualsIgnoreCase(type, "i")) {
+            sizeInt32++;
+        } else if (EqualsIgnoreCase(type, "s")) {
+            if (stringIndex != 0) {
+                dprintf(fd,
+                        "defining string value (%s) again at index %d (already defined at %d=%s"
+                        ")\n",
+                        value.c_str(), i, stringIndex, options[stringIndex + 1].c_str());
+                return;
+            }
+            stringIndex = i;
+        } else if (EqualsIgnoreCase(type, "a")) {
+            if (areaIndex != 0) {
+                dprintf(fd,
+                        "defining area value (%s) again at index %d (already defined at %d=%s"
+                        ")\n",
+                        value.c_str(), i, areaIndex, options[areaIndex + 1].c_str());
+                return;
+            }
+            areaIndex = i;
+        } else {
+            dprintf(fd, "invalid (%s) type at index %d\n", type.c_str(), i);
+            return;
+        }
+        i += 2;
+    }
+    prop.value.int32Values.resize(sizeInt32);
+
+    // Second pass: populate it
+    int indexInt32 = 0;
+    for (int i = 2, kv = 1; kv <= numberValues; kv++) {
+        // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step
+        int valueIndex = i + 1;
+        std::string type = options[i];
+        std::string value = options[valueIndex];
+        if (EqualsIgnoreCase(type, "i")) {
+            int safeInt;
+            if (!safelyParseInt(fd, valueIndex, value, &safeInt)) return;
+            prop.value.int32Values[indexInt32++] = safeInt;
+        } else if (EqualsIgnoreCase(type, "s")) {
+            prop.value.stringValue = value;
+        } else if (EqualsIgnoreCase(type, "a")) {
+            if (!safelyParseInt(fd, valueIndex, value, &prop.areaId)) return;
+        }
+        i += 2;
+    }
+    ALOGD("Setting prop %s", toString(prop).c_str());
+    auto status = set(prop);
+    if (status == StatusCode::OK) {
+        dprintf(fd, "Set property %s\n", toString(prop).c_str());
+    } else {
+        dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(),
+                toString(status).c_str());
+    }
+}
+
 void VehicleHalManager::init() {
     ALOGI("VehicleHalManager::init");
 
diff --git a/automotive/vehicle/2.0/default/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..24b777c 100644
--- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -50,12 +50,18 @@
     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.
+    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/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..53c9ffb 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,12 +72,14 @@
     (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;
 constexpr int WHEEL_FRONT_RIGHT = (int)VehicleAreaWheel::RIGHT_FRONT;
 constexpr int WHEEL_REAR_LEFT = (int)VehicleAreaWheel::LEFT_REAR;
 constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR;
+constexpr int INITIAL_USER_INFO = (int)VehicleProperty::INITIAL_USER_INFO;
 
 /**
  * This property is used for test purpose to generate fake events. Here is the test package that
@@ -85,6 +89,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 +199,6 @@
                          .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.floatValues = {15000.0f}}},
 
@@ -177,14 +208,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 +224,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 +239,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 +247,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 +267,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 +307,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 +346,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 +357,6 @@
                          .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
                          .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {0}}},
 
@@ -303,8 +364,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 +375,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 +383,6 @@
                          .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {0}}},
 
@@ -330,17 +390,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 +434,7 @@
                          .minSampleRate = 1.0f,
                          .maxSampleRate = 2.0f,
                  },
-         .initialValue = {.floatValues = {200}}},  // units in kPa
+         .initialValue = {.floatValues = {200.0f}}},  // units in kPa
 
         {.config =
                  {
@@ -397,7 +457,6 @@
                          .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {0}}},
 
@@ -409,6 +468,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 +497,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 +636,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 +647,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 +670,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 +708,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 +883,6 @@
                          .prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
 
@@ -766,7 +891,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 +899,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 +907,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 +915,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 +923,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 +931,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 +939,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 +992,33 @@
                     .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,
+                        },
+        },
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
new file mode 100644
index 0000000..9c3c95f
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+  private:
+    void dumpUserHal(int fd, std::string indent);
+};
+
+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");
+            dprintf(fd, "--user-hal: dumps state used for user management \n");
+            dprintf(fd, "\n");
+            // Include caller's help options
+            return true;
+        } else if (options[0] == "--user-hal") {
+            dumpUserHal(fd, "");
+            return false;
+
+        } else {
+            // Let caller handle the options...
+            return true;
+        }
+    }
+
+    dprintf(fd, "Emulator-specific state:\n");
+    dumpUserHal(fd, "  ");
+    dprintf(fd, "\n");
+
+    return true;
+}
+
+void EmulatedPassthroughConnector::dumpUserHal(int fd, std::string indent) {
+    if (mInitialUserResponseFromCmd != nullptr) {
+        dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(),
+                toString(*mInitialUserResponseFromCmd).c_str());
+    } else {
+        dprintf(fd, "%sNo Initial User Info\n", indent.c_str());
+    }
+}
+
+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 e1da030..6d5f23f 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
@@ -87,17 +87,19 @@
     return sensorStore;
 }
 
-EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
+EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client)
     : 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) {
     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));
 }
 
 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
@@ -128,11 +130,20 @@
     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);
+        // 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);
         if (status != StatusCode::OK) {
             return status;
         }
@@ -156,29 +167,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;
         }
     }
 
@@ -198,12 +186,16 @@
         return StatusCode::NOT_AVAILABLE;
     }
 
-    if (!mPropStore->writeValue(propValue, shouldUpdateStatus)) {
-        return StatusCode::INVALID_ARG;
-    }
+    /**
+     * After checking all conditions, such as the property is available, a real vhal will
+     * sent the events to Car ECU to take actions.
+     */
 
-    getEmulatorOrDie()->doSetValueFromClient(propValue);
-    doHalEvent(getValuePool()->obtain(propValue));
+    // 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;
 }
@@ -291,7 +283,6 @@
         }
 
         if (v.get()) {
-            v->timestamp = elapsedRealtimeNano();
             doHalEvent(std::move(v));
         }
     }
@@ -324,144 +315,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 78895e3..ebf1995 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,7 @@
 #include "vhal_v2_0/VehiclePropertyStore.h"
 
 #include "DefaultConfig.h"
+#include "EmulatedVehicleConnector.h"
 #include "GeneratorHub.h"
 #include "VehicleEmulator.h"
 
@@ -44,7 +45,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);
     ~EmulatedVehicleHal() = default;
 
     //  Methods from VehicleHal
@@ -55,6 +57,7 @@
     StatusCode set(const VehiclePropValue& propValue) override;
     StatusCode subscribe(int32_t property, float sampleRate) override;
     StatusCode unsubscribe(int32_t property) override;
+    bool dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
     //  Methods from EmulatedVehicleHalIface
     bool setPropertyFromVehicle(const VehiclePropValue& propValue) override;
@@ -66,10 +69,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,7 +85,7 @@
     VehiclePropertyStore* mPropStore;
     std::unordered_set<int32_t> mHvacPowerProps;
     RecurrentTimer mRecurrentTimer;
-    GeneratorHub mGeneratorHub;
+    VehicleHalClient* mVehicleClient;
 };
 
 }  // 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/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..a91ca8e
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
@@ -0,0 +1,353 @@
+/*
+ * 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 "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;
+}
+
+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) {
+    // 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;
+        case INITIAL_USER_INFO:
+            return onSetInitialUserInfo(value, updateStatus);
+        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;
+}
+
+/**
+ * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change
+ * indicating what the initial user should be.
+ *
+ * During normal circumstances, the emulator will reply right away, passing a response if
+ * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user
+ * to boot).
+ *
+ * But during development / testing, the behavior can be changed using lshal dump, which must use
+ * the areaId to indicate what should happen next.
+ *
+ * So, the behavior of set(INITIAL_USER_INFO) is:
+ *
+ * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by
+ *   lshal).
+ * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and
+ *   InitialUserInfoResponseAction::DEFAULT
+ * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd:
+ * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id
+ * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test
+ *   this error scenario)
+ * - if it's 3, then don't send a property change (so Android can emulate a timeout)
+ *
+ */
+StatusCode VehicleHalServer::onSetInitialUserInfo(const VehiclePropValue& value,
+                                                  bool updateStatus) {
+    // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged
+    // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of
+    // LOG, it's not worth investigating why...
+
+    if (value.value.int32Values.size() == 0) {
+        LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value);
+        return StatusCode::INVALID_ARG;
+    }
+
+    if (value.areaId != 0) {
+        LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value);
+        mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
+        return StatusCode::OK;
+    }
+    LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value);
+
+    int32_t requestId = value.value.int32Values[0];
+
+    // Create the update property and set common values
+    auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
+    updatedValue->prop = INITIAL_USER_INFO;
+    updatedValue->timestamp = elapsedRealtimeNano();
+
+    if (mInitialUserResponseFromCmd == nullptr) {
+        updatedValue->value.int32Values.resize(2);
+        updatedValue->value.int32Values[0] = requestId;
+        updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;
+        LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: "
+                  << toString(*updatedValue);
+        onPropertyValueFromCar(*updatedValue, updateStatus);
+        return StatusCode::OK;
+    }
+
+    // mInitialUserResponseFromCmd is used for just one request
+    std::unique_ptr<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd);
+
+    // TODO(b/138709788): rather than populate the raw values directly, it should use the
+    // libraries that convert a InitialUserInfoResponse into a VehiclePropValue)
+
+    switch (response->areaId) {
+        case 1:
+            LOG(INFO) << "returning response with right request id";
+            *updatedValue = *response;
+            updatedValue->areaId = 0;
+            updatedValue->value.int32Values[0] = requestId;
+            break;
+        case 2:
+            LOG(INFO) << "returning response with wrong request id";
+            *updatedValue = *response;
+            updatedValue->areaId = 0;
+            updatedValue->value.int32Values[0] = -requestId;
+            break;
+        case 3:
+            LOG(INFO) << "not generating a property change event because of lshal prop: "
+                      << toString(*response);
+            return StatusCode::OK;
+        default:
+            LOG(ERROR) << "invalid action on lshal response: " << toString(*response);
+            return StatusCode::INTERNAL_ERROR;
+    }
+
+    LOG(INFO) << "updating property to: " << toString(*updatedValue);
+    onPropertyValueFromCar(*updatedValue, updateStatus);
+    return StatusCode::OK;
+}
+
+}  // 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..b1ae106
--- /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 "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);
+
+  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);
+
+    StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus);
+
+  // data members
+
+  protected:
+    // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class
+    std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
+
+  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..2eedecd 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
@@ -29,3 +29,64 @@
     ],
     srcs: ["VehicleHalProto.proto"]
 }
+
+cc_library_static {
+    name: "android.hardware.automotive.vehicle@2.0-grpc",
+    vendor: true,
+    include_dirs: [
+        "external/protobuf/src",
+    ],
+    generated_headers: [
+        "DefaultVehicleHalProtoStub_h",
+    ],
+    export_generated_headers: [
+        "DefaultVehicleHalProtoStub_h",
+    ],
+    generated_sources: [
+        "DefaultVehicleHalProtoStub_cc",
+    ],
+    shared_libs: [
+        "libgrpc++_unsecure",
+    ],
+    cflags: [
+        "-Wno-unused-parameter"
+    ],
+}
+
+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",
+        "VehicleServer.proto",
+    ],
+    out: [
+        "VehicleHalProto.pb.h",
+        "VehicleHalProto.grpc.pb.h",
+        "VehicleServer.pb.h",
+        "VehicleServer.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",
+        "VehicleServer.proto",
+    ],
+    out: [
+        "VehicleHalProto.pb.cc",
+        "VehicleHalProto.grpc.pb.cc",
+        "VehicleServer.pb.cc",
+        "VehicleServer.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/proto/VehicleServer.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
new file mode 100644
index 0000000..6f71d65
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
@@ -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.
+ */
+
+syntax = "proto3";
+
+package vhal_proto;
+
+import "google/protobuf/empty.proto";
+import "VehicleHalProto.proto";
+
+// correspond to StatusCode defined in types.hal
+enum VehicleHalStatusCode {
+    OK                                  = 0;
+    TRY_AGAIN                           = 1;
+    INVALID_ARG                         = 2;
+    NOT_AVAILABLE                       = 3;
+    ACCESS_DENIED                       = 4;
+    INTERNAL_ERROR                      = 5;
+}
+
+message VehicleHalCallStatus {
+    VehicleHalStatusCode status_code    = 1;
+}
+
+message WrappedVehiclePropValue {
+    VehiclePropValue value              = 1;
+    // An indicator on whether we should update the status of the property
+    //   - true: if the value is generated by (emulated/real) car, or;
+    //           if the value is injected to 'fake' a on car event (for debugging purpose)
+    //   - false: if the value is set by VHal (public interface), since Android
+    //            cannot change status of property on a real car
+    bool update_status                  = 2;
+}
+
+service VehicleServer {
+    rpc GetAllPropertyConfig(google.protobuf.Empty) returns (stream VehiclePropConfig) {}
+
+    // Change the property value of the vehicle
+    rpc SetProperty(WrappedVehiclePropValue) returns (VehicleHalCallStatus) {}
+
+    // Start a vehicle property value stream
+    rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream WrappedVehiclePropValue) {}
+}
+
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/types.hal b/automotive/vehicle/2.0/types.hal
index 0f20dd1..23f9135 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
@@ -799,7 +870,7 @@
         | VehicleArea:SEAT),
 
     /**
-     * On/off defrost for designated window
+     * Fan-based defrost for designated window.
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ_WRITE
@@ -1076,6 +1147,7 @@
      *
      * @change_mode VehiclePropertyChangeMode:STATIC
      * @access VehiclePropertyAccess:READ
+     * @data_enum VehicleHvacFanDirection
      */
     HVAC_FAN_DIRECTION_AVAILABLE = (
         0x0511
@@ -1118,6 +1190,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 +1432,33 @@
         | VehiclePropertyType:INT32_VEC
         | VehicleArea:GLOBAL),
 
+    /**
+     * Property to feed H/W rotary events to android
+     *
+     * int32Values[0] : RotaryInputType identifying which rotary knob rotated
+     * int32Values[1] : number of detents (clicks), positive for clockwise,
+     *                  negative for counterclockwise
+     * int32Values[2] : target display defined in VehicleDisplay. Events not
+     *                  tied to specific display must be sent to
+     *                  VehicleDisplay#MAIN.
+     * int32values[3 .. 3 + abs(number of detents) - 2]:
+     *                  nanosecond deltas between pairs of consecutive detents,
+     *                  if the number of detents is > 1 or < -1
+     *
+     * VehiclePropValue.timestamp: when the rotation occurred. If the number of
+     *                             detents is > 1 or < -1, this is when the
+     *                             first detent of rotation occurred.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @data_enum RotaryInputType
+     * @access VehiclePropertyAccess:READ
+     */
+    HW_ROTARY_INPUT = (
+        0x0A20
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:INT32_VEC
+        | VehicleArea:GLOBAL),
+
     /***************************************************************************
      * Most Car Cabin properties have both a POSition and MOVE parameter.  These
      * are used to control the various movements for seats, doors, and windows
@@ -2321,6 +2432,483 @@
         | 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 "Admin", the
+     * response would be:
+     *
+     * int32[0]: 42    // must match the request id from the request
+     * int32[1]:  2    // action = InitialUserInfoResponseAction::CREATE
+     * int32[2]: -1    // userToSwitchOrCreate.userId (not used as user will be created)
+     * int32[3]:  8    // userToSwitchOrCreate.flags = ADMIN
+     * string: "Admin" // userNameToCreate
+     *
+     * NOTE: if the HAL doesn't support user management, then it should not define this property,
+     * which in turn would disable the other user-related properties (for example, the Android
+     * system would never issue them and user-related requests from the HAL layer would be ignored
+     * by the Android System). But if it supports user management, then it must support all
+     * user-related properties (INITIAL_USER_INFO, SWITCH_USER, CREATE_USER, REMOVE_USER,
+     *       and USER_IDENTIFICATION_ASSOCIATION).
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    INITIAL_USER_INFO = (
+        0x0F07
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Defines a request to switch the foreground Android user.
+     *
+     * This property is used primarily by the Android System to inform the HAL that the
+     * current foreground Android user is switching, but it could also be used by the HAL to request
+     * the Android system to switch users - the
+     *
+     * When the request is made by Android, it sets a VehiclePropValue and the HAL must responde
+     * with a property change event; when the HAL is making the request, it must also do it through
+     * a property change event (the main difference is that the request id will be positive in the
+     * former case, and negative in the latter; the SwitchUserMessageType will also be different).
+     *
+     * The format of both request is defined by SwitchUserRequest and the format of the response
+     * (when needed) is defined by SwitchUserResponse. How the HAL (or Android System) should
+     * proceed depends on the message type (which is defined by the SwitchUserMessageType
+     * parameter), as defined below.
+     *
+     * 1.LEGACY_ANDROID_SWITCH
+     * -----------------------
+     *
+     * Called by the Android System to indicate the Android user is about to change, when the change
+     * request was made in a way that is not integrated with the HAL (for example, through
+     * adb shell am switch-user).
+     *
+     * The HAL can switch its internal user once it receives this request, but it doesn't need to
+     * reply back to the Android System. If its internal user cannot be changed for some reason,
+     * then it must wait for the SWITCH_USER(type=ANDROID_POST_SWITCH) call to recover
+     * (for example, it could issue a SWITCH_USER(type=VEHICLE_REQUEST) to switch back to
+     * the previous user), but ideally it should never fail (as switching back could result in a
+     * confusing experience for the end user).
+     *
+     * For example, if the system have users (0, 10, 11) and it's switching from 0 to 11 (where none
+     * of them have any special flag), the request would be:
+     *
+     * int32[0]:  42  // request id
+     * int32[1]:  1   // SwitchUserMessageType::LEGACY_ANDROID_SWITCH
+     * int32[2]:  11  // target user id
+     * int32[3]:  0   // target user flags (none)
+     * int32[4]:  10  // current user
+     * int32[5]:  0   // current user flags (none)
+     * int32[6]:  3   // number of users
+     * int32[7]:  0   // user #0 (Android user id 0)
+     * int32[8]:  0   // flags of user #0 (none)
+     * int32[9]:  10  // user #1 (Android user id 10)
+     * int32[10]: 0   // flags of user #1 (none)
+     * int32[11]: 11  // user #2 (Android user id 11)
+     * int32[12]: 0   // flags of user #2 (none)
+     *
+     * 2.ANDROID_SWITCH
+     * ----------------
+     * Called by the Android System to indicate the Android user is about to change, but Android
+     * will wait for the HAL's response (up to some time) before proceeding.
+     *
+     * The HAL must switch its internal user once it receives this request, then respond back to
+     * Android with a SWITCH_USER(type=VEHICLE_RESPONSE) indicating whether its internal
+     * user was switched or not (through the SwitchUserStatus enum).
+     *
+     * For example, if Android has users (0, 10, 11) and it's switching from 10 to 11 (where
+     * none of them have any special flag), the request would be:
+     *
+     * int32[0]:  42  // request id
+     * int32[1]:  2   // SwitchUserMessageType::ANDROID_SWITCH
+     * int32[2]:  11  // target user id
+     * int32[3]:  0   // target user flags (none)
+     * int32[4]:  10  // current user
+     * int32[5]:  0   // current user flags (none)
+     * int32[6]:  3   // number of users
+     * int32[7]:  0   // 1st user (user 0)
+     * int32[8]:  0   // 1st user flags (none)
+     * int32[9]:  10  // 2nd user (user 10)
+     * int32[10]: 0   // 2nd user flags (none)
+     * int32[11]: 11  // 3rd user (user 11)
+     * int32[12]: 0   // 3rd user flags (none)
+     *
+     * If the request succeeded, the HAL must update the propery with:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 3   // messageType = SwitchUserMessageType::VEHICLE_RESPONSE
+     * int32[2]: 1   // status = SwitchUserStatus::SUCCESS
+     *
+     * But if it failed, the response would be something like:
+     *
+     * int32[0]: 42   // request id
+     * int32[1]: 3    // messageType = SwitchUserMessageType::VEHICLE_RESPONSE
+     * int32[2]: 2    // status = SwitchUserStatus::FAILURE
+     * string: "108-D'OH!" // OEM-spefic error message
+     *
+     * 3.VEHICLE_RESPONSE
+     * ------------------
+     * Called by the HAL to indicate whether a request of type ANDROID_SWITCH should proceed or
+     * abort - see the ANDROID_SWITCH section above for more info.
+     *
+     * 4.VEHICLE_REQUEST
+     * ------------------
+     * Called by the HAL to request that the current foreground Android user is switched.
+     *
+     * This is useful in situations where Android started as one user, but the vehicle identified
+     * the driver as another user. For example, user A unlocked the car using the key fob of user B;
+     * the INITIAL_USER_INFO request returned user B, but then a face recognition subsubsystem
+     * identified the user as A.
+     *
+     * The HAL makes this request by a property change event (passing a negative request id), and
+     * the Android system will response by issuye an ANDROID_POST_SWITCH call which the same
+     * request id.
+     *
+     * For example, if the current foreground Android user is 10 and the HAL asked it to switch to
+     * 11, the request would be:
+     *
+     * int32[0]: -108  // request id
+     * int32[1]: 4     // messageType = SwitchUserMessageType::VEHICLE_REQUEST
+     * int32[2]: 11    // Android user id
+     *
+     * If the request succeeded and Android has 3 users (0, 10, 11), the response would be:
+     *
+     * int32[0]: -108 // request id
+     * int32[1]:  5   // messageType = SwitchUserMessageType::ANDROID_SWITCH
+     * int32[2]:  11  // target user id
+     * int32[3]:  11  // target user id flags (none)
+     * int32[4]:  11  // current user
+     * int32[5]:  0   // current user flags (none)
+     * int32[6]:  3   // number of users
+     * int32[7]:  0   // 1st user (user 0)
+     * int32[8]:  0   // 1st user flags (none)
+     * int32[9]:  10  // 2nd user (user 10)
+     * int32[10]: 4   // 2nd user flags (none)
+     * int32[11]: 11  // 3rd user (user 11)
+     * int32[12]: 3   // 3rd user flags (none)
+     *
+     * Notice that both the current and target user ids are the same - if the request failed, then
+     * they would be different (i.e, target user would be 11, but current user would still be 10).
+     *
+     * 5.ANDROID_POST_SWITCH
+     * ---------------------
+     * Called by the Android System after a request to switch a user was made
+     *
+     * This property is called after switch requests of any type (i.e., LEGACY_ANDROID_SWITCH,
+     * ANDROID_SWITCH, or VEHICLE_REQUEST) and can be used to determine if the request succeeded or
+     * failed:
+     *
+     * 1. When it succeeded, it's called when the Android user is in the boot locked state and the
+     *    value of the current and target users ids in the response are different. This would be
+     *    equivalent to receiving an Intent.ACTION_LOCKED_BOOT_COMPLETED in an Android app.
+     * 2. When it failed it's called right away and the value of the current and target users ids
+     *    in the response are the same.
+     *
+     * The HAL can update its internal state once it receives this request, but it doesn't need to
+     * reply back to the Android System.
+     *
+     * Request: the first N values as defined by INITIAL_USER_INFO (where the request-specific
+     * value at index 1 is SwitchUserMessageType::ANDROID_POST_SWITCH), then 2 more values for the
+     * target user id (i.e., the Android user id that was requested to be switched to) and its flags
+     * (as defined by  UserFlags).
+     *
+     * Response: none.
+     *
+     * Example: see VEHICLE_REQUEST section above.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    SWITCH_USER = (
+        0x0F08
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Called by the Android System after an Android user was created.
+     *
+     * The HAL can use this property to create its equivalent user.
+     *
+     * This is an async request: Android makes the request by setting a VehiclePropValue, and HAL
+     * must respond with a property change indicating whether the request succeeded or failed. If
+     * it failed, the Android system will remove the user.
+     *
+     * The format of the request is defined by CreateUserRequest and the format of the response by
+     * CreateUserResponse.
+     *
+     * For example, if system had 2 users (0 and 10) and a 3rd one (which is an ephemeral guest) was
+     * created, the request would be:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 11  // Android id of the created user
+     * int32[2]: 3   // Android flags (ephemeral guest) of the created user
+     * int32[3]: 10  // current user
+     * int32[4]: 0   // current user flags (none)
+     * int32[5]: 3   // number of users
+     * int32[6]: 0   // 1st user (user 0)
+     * int32[7]: 0   // 1st user flags (none)
+     * int32[8]: 10  // 2nd user (user 10)
+     * int32[9]: 0   // 2nd user flags (none)
+     * int32[19]: 11 // 3rd user (user 11)
+     * int32[11]: 3  // 3rd user flags (ephemeral guest)
+     * string: "ElGuesto" // name of the new user
+     *
+     * Then if the request succeeded, the HAL would return:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 1   // CreateUserStatus::SUCCESS
+     *
+     * But if it failed:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 2   // CreateUserStatus::FAILURE
+     * string: "D'OH!" // The meaning is a blackbox - it's passed to the caller (like Settings UI),
+     *                 // which in turn can take the proper action.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    CREATE_USER = (
+        0x0F09
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Called by the Android System after an Android user was removed.
+     *
+     * The HAL can use this property to remove its equivalent user.
+     *
+     * This is write-only call - the Android System is not expecting a reply from the HAL. Hence,
+     * this request should not fail - if the equivalent HAL user cannot be removed, then HAL should
+     * mark it as inactive or recover in some other way.
+     *
+     * The request is made by setting the VehiclePropValue with the contents defined by
+     * RemoveUserRequest.
+     *
+     * For example, if system had 3 users (0, 10, and 11) and user 11 was removed, the request
+     * would be:
+     *
+     * int32[0]: 42  // request id
+     * int32[1]: 11  // (Android user id of the removed user)
+     * int32[2]: 0   // (Android user flags of the removed user)
+     * int32[3]: 10  // current user
+     * int32[4]: 0   // current user flags (none)
+     * int32[5]: 2   // number of users
+     * int32[6]: 0   // 1st user (user 0)
+     * int32[7]: 0   // 1st user flags (none)
+     * int32[8]: 10  // 2nd user (user 10)
+     * int32[9]: 0   // 2nd user flags (none)
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:WRITE
+     */
+    REMOVE_USER = (
+        0x0F0A
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Property used to associate (or query the association) the current user with vehicle-specific
+     * identification mechanisms (such as key FOB).
+     *
+     * To query the association, the Android system gets the property, passing a VehiclePropValue
+     * containing the types of associations are being queried, as defined by
+     * UserIdentificationGetRequest. The HAL must return right away, updating the VehiclePropValue
+     * with a UserIdentificationResponse. Notice that user identification should have already
+     * happened while system is booting up and the VHAL implementation should only return the
+     * already identified association (like the key FOB used to unlock the car), instead of starting
+     * a new association from the get call.
+     *
+     * To associate types, the Android system sets the property, passing a VehiclePropValue
+     * containing the types and values of associations being set, as defined by the
+     * UserIdentificationSetRequest. The HAL will then use a property change event (whose
+     * VehiclePropValue is defined by UserIdentificationResponse) indicating the current status of
+     * the types after the request.
+     *
+     * For example, to query if the current user (10) is associated with the FOB that unlocked the
+     * car and a custom mechanism provided by the OEM, the request would be:
+     *
+     * int32[0]: 10  (Android user id)
+     * int32[1]: 0   (Android user flags)
+     * int32[2]: 2   (number of types queried)
+     * int32[3]: 1   (1st type queried, UserIdentificationAssociationType::KEY_FOB)
+     * int32[4]: 101 (2nd type queried, UserIdentificationAssociationType::CUSTOM_1)
+     *
+     * If the user is associated with the FOB but not with the custom mechanism, the response would
+     * be:
+     *
+     * int32[9]: 2   (number of associations in the response)
+     * int32[1]: 1   (1st type: UserIdentificationAssociationType::KEY_FOB)
+     * int32[2]: 2   (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER)
+     * int32[3]: 101 (2st type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[4]: 4   (2nd value: UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER)
+     *
+     * Then to associate the user with the custom mechanism, a set request would be made:
+     *
+     * int32[0]: 10  (Android user id)
+     * int32[0]: 0   (Android user flags)
+     * int32[1]: 1   (number of associations being set)
+     * int32[2]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[3]: 1   (1st value: UserIdentificationAssociationSETValue::ASSOCIATE_CURRENT_USER)
+     *
+     * If the request succeeded, the response would be simply:
+     *
+     * int32[0]: 2   (number of associations in the response)
+     * int32[1]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[2]: 1   (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER)
+     *
+     * Notice that the set request adds associations, but doesn't remove the existing ones. In the
+     * example above, the end state would be 2 associations (FOB and CUSTOM_1). If we wanted to
+     * associate the user with just CUSTOM_1 but not FOB, then the request should have been:
+     *
+     * int32[0]: 10  (Android user id)
+     * int32[1]: 2   (number of types set)
+     * int32[2]: 1   (1st type: UserIdentificationAssociationType::KEY_FOB)
+     * int32[3]: 2   (1st value: UserIdentificationAssociationValue::DISASSOCIATE_CURRENT_USER)
+     * int32[3]: 101 (2nd type: UserIdentificationAssociationType::CUSTOM_1)
+     * int32[5]: 1   (2nd value: UserIdentificationAssociationValue::ASSOCIATE_CURRENT_USER)
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    USER_IDENTIFICATION_ASSOCIATION = (
+        0x0F0B
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+};
+
+/**
+ * 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 +3046,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 +3087,52 @@
 };
 
 enum VehicleApPowerStateReq : int32_t {
-    /** Transition Android from WAIT_FOR_VHAL to ON state */
+    /**
+     * This requests Android to enter its normal operating state.
+     * This may be sent after the AP has reported
+     * VehicleApPowerStateReport#DEEP_SLEEP_EXIT,
+     * VehicleApPowerStateReport#SHUTDOWN_CANCELLED, or
+     * VehicleApPowerStateReport#WAIT_FOR_VHAL.
+     */
     ON = 0,
 
     /**
-     * The power controller has requested AP to shutdown. AP can either enter
-     * sleep state or start full shutdown. AP can also request postponing
-     * shutdown by sending VehicleApPowerSetState#SHUTDOWN_POSTPONE message. The
-     * power controller must change power state to this state to shutdown
-     * system.
+     * The power controller issues this request to shutdown the system.
+     * This may be sent after the AP has reported
+     * VehicleApPowerStateReport#DEEP_SLEEP_EXIT,
+     * VehicleApPowerStateReport#ON,
+     * VehicleApPowerStateReport#SHUTDOWN_CANCELLED,
+     * VehicleApPowerStateReport#SHUTDOWN_POSTPONE,
+     * VehicleApPowerStateReport#SHUTDOWN_PREPARE, or
+     * VehicleApPowerStateReport#WAIT_FOR_VHAL.
      *
-     * int32Values[1] : one of 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 +3155,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 +3371,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 +4192,523 @@
     PUBLISHER_ID = 1,
 };
 
+/**
+ * Information about a specific Android user.
+ */
+struct UserInfo {
+
+    UserId userId;
+
+    UserFlags flags;
+};
+
+/**
+ * Id of an Android user.
+ *
+ * Must be > 0 for valid ids, or -10000 (which is the same as Android.UserHandle.USER_NULL) when
+ * it's not used.
+ */
+typedef int32_t UserId;
+
+/**
+ * Flags used to define the characteristics of an Android user.
+ */
+enum UserFlags: int32_t {
+    /**
+     * No flags.
+     */
+    NONE = 0x0,
+
+    /**
+     * System user.
+     * On automotive, that user is always running, although never on foreground (except during
+     * boot or exceptional circumstances).
+     */
+    SYSTEM = 0x01,
+
+    /**
+     * Guest users have restrictions.
+     */
+    GUEST = 0x02,
+
+    /**
+     * Ephemeral users have non-persistent state.
+     */
+    EPHEMERAL = 0x04,
+
+    /**
+     * Admin users have additional privileges such as permission to create other users.
+     */
+    ADMIN = 0x08,
+};
+
+/**
+ * Information about all Android users.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it's part of other structs, which
+ * in turn are converted to a VehiclePropValue.RawValue through libraries provided by the default
+ * Vehicle HAL implementation.
+ */
+struct UsersInfo {
+
+    /** The current foreground user. */
+    UserInfo currentUser;
+
+    /** Number of existing users (includes the current user). */
+    int32_t numberUsers;
+
+    /** List of existing users (includes the current user). */
+    vec<UserInfo> existingUsers;
+ };
+
+/**
+ * Id of a request related to user management.
+ *
+ * This id can be used by the Android system to map responses sent by the HAL, and vice-versa.
+ *
+ * For requests originated by Android, the value is positive (> 0), while for requests originated by
+ * the HAL it must be negative (< 0).
+ */
+typedef int32_t UserRequestId;
+
+/**
+ * Defines the format of a INITIAL_USER_INFO request made by the Android system.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct InitialUserInfoRequest {
+    /**
+     * Arbitrary id used to map the HAL response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Type of request.
+     */
+    InitialUserInfoRequestType requestType;
+
+    /**
+     * Information about the current state of the Android system.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+ * Defines when a INITIAL_USER_INFO request was made.
+ */
+enum InitialUserInfoRequestType : int32_t {
+  /** At the first time Android was booted (or after a factory reset). */
+  FIRST_BOOT = 1,
+
+  /** At the first time Android was booted after the system was updated. */
+  FIRST_BOOT_AFTER_OTA = 2,
+
+  /** When Android was booted "from scratch". */
+  COLD_BOOT = 3,
+
+  /** When Android was resumed after the system was suspended to memory. */
+  RESUME = 4,
+};
+
+/**
+ * Defines the format of a HAL response to a INITIAL_USER_INFO request.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct InitialUserInfoResponse {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * which action the Android system should take.
+     */
+    InitialUserInfoResponseAction action;
+
+    /**
+     * Information about the user that should be switched to or created.
+     */
+    UserInfo userToSwitchOrCreate;
+
+    /**
+     * Name of the user that should be created.
+     */
+    string userNameToCreate;
+};
+
+/**
+ * Defines which action the Android system should take in an INITIAL_USER_INFO request.
+ */
+enum InitialUserInfoResponseAction : int32_t {
+   /**
+    * Let the Android System decide what to do.
+    *
+    * For example, it might create a new user on first boot, and switch to the last
+    * active user afterwards.
+    */
+   DEFAULT = 0,
+
+   /**
+    * Switch to an existing Android user.
+    */
+   SWITCH = 1,
+
+   /**
+    * Create a new Android user (and switch to it).
+    */
+   CREATE = 2,
+};
+
+/**
+ * Defines the format of a SWITCH_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct SwitchUserRequest {
+    /**
+     * Arbitrary id used to map the response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Type of message.
+     */
+    SwitchUserMessageType messageType;
+
+    /**
+     * Information about the Android user being switched to.
+     *
+     * Only the user id (but not the flags) should be set when the request is made by HAL.
+     */
+    UserInfo targetUser;
+
+    /**
+     * Information about the current state of the Android system.
+     *
+     * Should not be set when the request is made by HAL.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+ * Defines the reason a SWITCH_USER call was made.
+ *
+ * The meaning of each constant is explained in that property.
+ */
+enum SwitchUserMessageType: int32_t {
+   LEGACY_ANDROID_SWITCH = 1,
+   ANDROID_SWITCH = 2,
+   VEHICLE_RESPONSE = 3,
+   VEHICLE_REQUEST = 4,
+   ANDROID_POST_SWITCH = 5,
+};
+
+/**
+ * Defines the result of a SwitchUserRequest.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct SwitchUserResponse {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Type of message.
+     */
+    SwitchUserMessageType messageType;
+
+    /**
+     * Status of the request.
+     */
+    SwitchUserStatus status;
+
+    /**
+     * HAL-specific error message.
+     *
+     * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be
+     * used to show custom error messages to the end user.
+     */
+    string errorMessage;
+};
+
+/**
+ * Status of the response to a SwitchUserRequest.
+ */
+enum SwitchUserStatus : int32_t {
+   /** The request succeeded and the HAL user was switched. */
+   SUCCESS = 1,
+   /** The request failed and the HAL user remained the same. */
+   FAILURE = 2,
+};
+
+/**
+ * Defines the format of a CREATE_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct CreateUserRequest {
+    /**
+     * Arbitrary id used to map the response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Basic information about Android user that was created.
+     */
+    UserInfo newUserInfo;
+
+    /**
+     * Name of the new Android user.
+     */
+     string newUserName;
+
+    /**
+     * Information about the current state of the Android system.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+ * Defines the result of a CreateUserRequest.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct CreateUserResponse {
+    /**
+     * Id of the request being responded.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Status of the request.
+     */
+    CreateUserStatus status;
+
+    /**
+     * HAL-specific error message.
+     *
+     * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be
+     * used to show custom error messages to the end user.
+     */
+    string errorMessage;
+};
+
+/**
+ * Status of the response to a CreateUserRequest.
+ */
+enum CreateUserStatus : int32_t {
+   /**
+    * The request succeeded (for example, HAL created a new internal user, or associated the
+    * Android user to an existing internal user).
+    */
+   SUCCESS = 1,
+
+   /**
+     * The request failed (and Android will remove the Android user).
+     */
+   FAILURE = 2,
+};
+
+/**
+ * Defines the format of a REMOVE_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct RemoveUserRequest {
+    /**
+     * Arbitrary id used to map the response to the request.
+     */
+    UserRequestId requestId;
+
+    /**
+     * Information about the Android user that was removed.
+     */
+    UserInfo removedUserInfo;
+
+    /**
+     * Information about the current state of the Android system.
+     */
+    UsersInfo usersInfo;
+};
+
+/**
+  * Types of mechanisms used to identify an Android user.
+  *
+  * See USER_IDENTIFICATION_ASSOCIATION for more details and example.
+  */
+enum UserIdentificationAssociationType: int32_t {
+   /** Key used to unlock the car. */
+   KEY_FOB = 1,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_1 = 101,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_2 = 102,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_3 = 103,
+   /** Custom mechanism defined by the OEM. */
+   CUSTOM_4 = 104,
+};
+
+/**
+ * Whether a UserIdentificationAssociationType is associate with an Android user.
+ */
+enum UserIdentificationAssociationValue : int32_t {
+   /**
+    * Used when the status of an association could not be determined.
+    *
+    * For example, in a set() request, it would indicate a failure to set the given type.
+    */
+   UNKNOWN = 1,
+
+   /**
+    * The identification type is associated with the current foreground Android user.
+    */
+   ASSOCIATED_CURRENT_USER = 2,
+
+   /**
+    * The identification type is associated with another Android user.
+    */
+   ASSOCIATED_ANOTHER_USER = 3,
+
+   /**
+    * The identification type is not associated with any Android user.
+    */
+   NOT_ASSOCIATED_ANY_USER = 4,
+};
+
+/**
+ * Used to set a UserIdentificationAssociationType with an Android user.
+ */
+enum UserIdentificationAssociationSetValue : int32_t {
+   /**
+    * Associate the identification type with the current foreground Android user.
+    */
+   ASSOCIATE_CURRENT_USER = 1,
+
+   /**
+    * Disassociate the identification type from the current foreground Android user.
+    */
+   DISASSOCIATE_CURRENT_USER = 2,
+
+   /**
+    * Disassociate the identification type from all Android users.
+    */
+   DISASSOCIATE_ALL_USERS = 3,
+};
+
+/**
+ * Defines the format of a get() call to USER_IDENTIFICATION_ASSOCIATION.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct UserIdentificationGetRequest {
+    /**
+     * Information about the current foreground Android user.
+     */
+    UserInfo userInfo;
+
+    /**
+     * Number of association being queried.
+     */
+    int32_t numberAssociationTypes;
+
+    /**
+     * Types of association being queried.
+     */
+    vec<UserIdentificationAssociationType> associationTypes;
+};
+
+/**
+ * Defines the format of a set() call to USER_IDENTIFICATION_ASSOCIATION.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct UserIdentificationSetRequest {
+    /**
+     * Information about the current foreground Android user.
+     */
+    UserInfo userInfo;
+
+    /**
+     * Number of association being set.
+     */
+    int32_t numberAssociations;
+
+    /**
+     * Associations being set.
+     */
+    vec<UserIdentificationAssociationSetValue> associations;
+};
+
+/**
+ * Defines the result of a USER_IDENTIFICATION_ASSOCIATION - both for get() and set().
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct UserIdentificationResponse {
+    /**
+     * Number of associations being returned.
+     */
+    int32_t numberAssociation;
+
+    /**
+     * Values associated with the user.
+     */
+    vec<UserIdentificationAssociation> associations;
+
+    /**
+     * HAL-specific error message.
+     *
+     * This argument is optional, and when defined, it's passed "as-is" to the caller. It could be
+     * used to show custom error messages to the end user.
+     */
+    string errorMessage;
+};
+
+/**
+ * Helper struct used when getting a user/identification association type.
+ */
+struct UserIdentificationAssociation {
+
+    UserIdentificationAssociationType type;
+
+    UserIdentificationAssociationValue value;
+};
+
+/**
+ * Helper struct used when setting a user/identification association type.
+ */
+struct UserIdentificationSetAssociation {
+
+    UserIdentificationAssociationType type;
+
+    UserIdentificationAssociationSetValue value;
+};
+
+/**
+ * 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.1/Android.bp b/biometrics/face/1.1/Android.bp
new file mode 100644
index 0000000..2206597
--- /dev/null
+++ b/biometrics/face/1.1/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.biometrics.face@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IBiometricsFace.hal",
+    ],
+    interfaces: [
+        "android.hardware.biometrics.face@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal
new file mode 100644
index 0000000..84e7443
--- /dev/null
+++ b/biometrics/face/1.1/IBiometricsFace.hal
@@ -0,0 +1,117 @@
+/*
+ * 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.biometrics.face@1.1;
+
+import @1.0::IBiometricsFace;
+import @1.0::Status;
+import @1.0::Feature;
+
+/**
+ * The HAL interface for biometric face authentication.
+ */
+interface IBiometricsFace extends @1.0::IBiometricsFace {
+    /**
+     * Enrolls a user's face for a remote client, for example Android Auto.
+     *
+     * The HAL implementation is responsible for creating a secure communication
+     * channel and receiving the enrollment images from a mobile device with
+     * face authentication hardware.
+     *
+     * Note that the Hardware Authentication Token must be valid for the
+     * duration of enrollment and thus should be explicitly invalidated by a
+     * call to revokeChallenge() when enrollment is complete, to reduce the
+     * window of opportunity to re-use the challenge and HAT. For example,
+     * Settings calls generateChallenge() once to allow the user to enroll one
+     * or more faces or toggle secure settings without having to re-enter the
+     * PIN/pattern/password. Once the user completes the operation, Settings
+     * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+     * the implementation must invoke onError with UNABLE_TO_PROCESS.
+     *
+     * Requirements for using this API:
+     * - Mobile devices MUST NOT delegate enrollment to another device by calling
+     * this API. This feature is intended only to allow enrollment on devices
+     * where it is impossible to enroll locally on the device.
+     * - The path MUST be protected by a secret key with rollback protection.
+     * - Synchronizing between devices MUST be accomplished by having both
+     * devices agree on a secret PIN entered by the user (similar to BT
+     * pairing procedure) and use a salted version of that PIN plus other secret
+     * to encrypt traffic.
+     * - All communication to/from the remote device MUST be encrypted and signed
+     * to prevent image injection and other man-in-the-middle type attacks.
+     * - generateChallenge() and revokeChallenge() MUST be implemented on both
+     * remote and local host (e.g. hash the result of the remote host with a
+     * local secret before responding to the API call) and any transmission of
+     * the challenge between hosts MUST be signed to prevent man-in-the-middle
+     * attacks.
+     * - In the event of a lost connection, the result of the last
+     * generateChallenge() MUST be invalidated and the process started over.
+     * - Both the remote and local host MUST honor the timeout and invalidate the
+     * challenge.
+     *
+     * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+     * method.
+     *
+     * @param hat A valid Hardware Authentication Token, generated as a result
+     *     of a generateChallenge() challenge being wrapped by the gatekeeper
+     *     after a successful strong authentication request.
+     * @param timeoutSec A timeout in seconds, after which this enroll
+     *     attempt is cancelled. Note that the framework can continue
+     *     enrollment by calling this again with a valid HAT. This timeout is
+     *     expected to be used to limit power usage if the device becomes idle
+     *     during enrollment. The implementation is expected to send
+     *     ERROR_TIMEOUT if this happens.
+     * @param disabledFeatures A list of features to be disabled during
+     *     enrollment. Note that all features are enabled by default.
+     * @return status The status of this method call.
+     */
+    enrollRemotely(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures)
+        generates (Status status);
+
+    /**
+     * Enrolls a user's face.
+     *
+     * Note that the Hardware Authentication Token must be valid for the
+     * duration of enrollment and thus should be explicitly invalidated by a
+     * call to revokeChallenge() when enrollment is complete, to reduce the
+     * window of opportunity to re-use the challenge and HAT. For example,
+     * Settings calls generateChallenge() once to allow the user to enroll one
+     * or more faces or toggle secure settings without having to re-enter the
+     * PIN/pattern/password. Once the user completes the operation, Settings
+     * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+     * the implementation must invoke onError with UNABLE_TO_PROCESS.
+     *
+     * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+     * method.
+     *
+     * @param hat A valid Hardware Authentication Token, generated as a result
+     *     of a generateChallenge() challenge being wrapped by the gatekeeper
+     *     after a successful strong authentication request.
+     * @param timeoutSec A timeout in seconds, after which this enroll
+     *     attempt is cancelled. Note that the framework can continue
+     *     enrollment by calling this again with a valid HAT. This timeout is
+     *     expected to be used to limit power usage if the device becomes idle
+     *     during enrollment. The implementation is expected to send
+     *     ERROR_TIMEOUT if this happens.
+     * @param disabledFeatures A list of features to be disabled during
+     *     enrollment. Note that all features are enabled by default.
+     * @param windowId optional ID of a camera preview window for a
+     *     single-camera device. Must be null if not used.
+     * @return status The status of this method call.
+     */
+    enroll_1_1(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures,
+        handle windowId) generates (Status status);
+};
diff --git a/biometrics/face/1.1/default/Android.bp b/biometrics/face/1.1/default/Android.bp
new file mode 100644
index 0000000..360071f
--- /dev/null
+++ b/biometrics/face/1.1/default/Android.bp
@@ -0,0 +1,36 @@
+/*
+ * 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.1-service.example",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    init_rc: ["android.hardware.biometrics.face@1.1-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",
+        "android.hardware.biometrics.face@1.1",
+    ],
+}
diff --git a/biometrics/face/1.1/default/BiometricsFace.cpp b/biometrics/face/1.1/default/BiometricsFace.cpp
new file mode 100644
index 0000000..2143880
--- /dev/null
+++ b/biometrics/face/1.1/default/BiometricsFace.cpp
@@ -0,0 +1,129 @@
+/*
+ * 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;
+}
+
+// Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
+Return<Status> BiometricsFace::enroll_1_1(const hidl_vec<uint8_t>& /* hat */,
+                                          uint32_t /* timeoutSec */,
+                                          const hidl_vec<Feature>& /* disabledFeatures */,
+                                          const hidl_handle& /* windowId */) {
+    mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+    return Status::OK;
+}
+
+Return<Status> BiometricsFace::enrollRemotely(const hidl_vec<uint8_t>& /* hat */,
+                                              uint32_t /* timeoutSec */,
+                                              const hidl_vec<Feature>& /* disabledFeatures */) {
+    mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+    return Status::OK;
+}
+
+}  // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.1/default/BiometricsFace.h b/biometrics/face/1.1/default/BiometricsFace.h
new file mode 100644
index 0000000..5ce5771
--- /dev/null
+++ b/biometrics/face/1.1/default/BiometricsFace.h
@@ -0,0 +1,88 @@
+/*
+ * 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.1/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_1::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;
+
+    // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
+    Return<Status> enroll_1_1(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+                              const hidl_vec<Feature>& disabledFeatures,
+                              const hidl_handle& windowId) override;
+
+    Return<Status> enrollRemotely(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+                                  const hidl_vec<Feature>& disabledFeatures) override;
+
+  private:
+    std::mt19937 mRandom;
+    int32_t mUserId;
+    sp<IBiometricsFaceClientCallback> mClientCallback;
+};
+
+}  // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
new file mode 100644
index 0000000..687e2d8
--- /dev/null
+++ b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
@@ -0,0 +1,10 @@
+service vendor.face-hal-1-1-default /vendor/bin/hw/android.hardware.biometrics.face@1.1-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.1/default/manifest_face_default.xml b/biometrics/face/1.1/default/manifest_face_default.xml
new file mode 100644
index 0000000..ec71d9c
--- /dev/null
+++ b/biometrics/face/1.1/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.1</version>
+        <interface>
+            <name>IBiometricsFace</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/biometrics/face/1.1/default/service.cpp b/biometrics/face/1.1/default/service.cpp
new file mode 100644
index 0000000..344bdb9
--- /dev/null
+++ b/biometrics/face/1.1/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.1-service"
+
+#include <android/hardware/biometrics/face/1.0/types.h>
+#include <android/hardware/biometrics/face/1.1/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_1::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.1/vts/functional/Android.bp b/biometrics/face/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..ccbb399
--- /dev/null
+++ b/biometrics/face/1.1/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: "VtsHalBiometricsFaceV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBiometricsFaceV1_1TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.biometrics.face@1.0",
+        "android.hardware.biometrics.face@1.1",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
new file mode 100644
index 0000000..6ada442
--- /dev/null
+++ b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
@@ -0,0 +1,205 @@
+/*
+ * 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 "biometrics_face_hidl_hal_test"
+
+#include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <chrono>
+#include <cstdint>
+#include <random>
+
+using android::sp;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo;
+using android::hardware::biometrics::face::V1_0::FaceError;
+using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
+using android::hardware::biometrics::face::V1_0::OptionalUint64;
+using android::hardware::biometrics::face::V1_0::Status;
+using android::hardware::biometrics::face::V1_1::IBiometricsFace;
+
+namespace {
+
+// Arbitrary, nonexistent userId
+constexpr uint32_t kUserId = 9;
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata";
+constexpr char kCallbackNameOnError[] = "onError";
+
+// Callback arguments that need to be captured for the tests.
+struct FaceCallbackArgs {
+    // The error passed to the last onError() callback.
+    FaceError error;
+
+    // The userId passed to the last callback.
+    int32_t userId;
+};
+
+// Test callback class for the BiometricsFace HAL.
+// The HAL will call these callback methods to notify about completed operations
+// or encountered errors.
+class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
+                     public IBiometricsFaceClientCallback {
+  public:
+    Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { return Void(); }
+
+    Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
+        return Void();
+    }
+
+    Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
+        return Void();
+    }
+
+    Return<void> onError(uint64_t, int32_t userId, FaceError error, int32_t) override {
+        FaceCallbackArgs args = {};
+        args.error = error;
+        args.userId = userId;
+        NotifyFromCallback(kCallbackNameOnError, args);
+        return Void();
+    }
+
+    Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t) override { return Void(); }
+
+    Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
+        return Void();
+    }
+
+    Return<void> onLockoutChanged(uint64_t) override { return Void(); }
+};
+
+// Test class for the BiometricsFace HAL.
+class FaceHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        mService = IBiometricsFace::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        mCallback = new FaceCallback();
+        mCallback->SetWaitTimeoutDefault(kTimeout);
+        Return<void> ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) {
+            ASSERT_EQ(Status::OK, res.status);
+            // Makes sure the "deviceId" represented by "res.value" is not 0.
+            // 0 would mean the HIDL is not available.
+            ASSERT_NE(0UL, res.value);
+        });
+        ASSERT_TRUE(ret1.isOk());
+        Return<Status> ret2 = mService->setActiveUser(kUserId, kFacedataDir);
+        ASSERT_EQ(Status::OK, static_cast<Status>(ret2));
+    }
+
+    void TearDown() override {}
+
+    sp<IBiometricsFace> mService;
+    sp<FaceCallback> mCallback;
+};
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, Enroll2_2ZeroHatTest) {
+    // Filling HAT with zeros
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; i++) {
+        token[i] = 0;
+    }
+
+    hidl_handle windowId = nullptr;
+    Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
+    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+    // onError should be called with a meaningful (nonzero) error.
+    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
+    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, Enroll2_2GarbageHatTest) {
+    // Filling HAT with pseudorandom invalid data.
+    // Using default seed to make the test reproducible.
+    std::mt19937 gen(std::mt19937::default_seed);
+    std::uniform_int_distribution<uint8_t> dist;
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; ++i) {
+        token[i] = dist(gen);
+    }
+
+    hidl_handle windowId = nullptr;
+    Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
+    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+    // onError should be called with a meaningful (nonzero) error.
+    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
+    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) {
+    // Filling HAT with zeros
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; i++) {
+        token[i] = 0;
+    }
+
+    Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+    // onError should be called with a meaningful (nonzero) error.
+    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
+    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyGarbageHatTest) {
+    // Filling HAT with pseudorandom invalid data.
+    // Using default seed to make the test reproducible.
+    std::mt19937 gen(std::mt19937::default_seed);
+    std::uniform_int_distribution<uint8_t> dist;
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; ++i) {
+        token[i] = dist(gen);
+    }
+
+    Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+    // onError should be called with a meaningful (nonzero) error.
+    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
+    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+}  // anonymous namespace
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, FaceHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/fingerprint/2.2/Android.bp b/biometrics/fingerprint/2.2/Android.bp
new file mode 100644
index 0000000..6c769ac
--- /dev/null
+++ b/biometrics/fingerprint/2.2/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.biometrics.fingerprint@2.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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..0651034
--- /dev/null
+++ b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal
@@ -0,0 +1,58 @@
+/*
+ * 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;
+import @2.1::RequestStatus;
+
+interface IBiometricsFingerprint extends @2.1::IBiometricsFingerprint {
+    /**
+     * Fingerprint enroll request:
+     * Switches the HAL state machine to collect and store a new fingerprint
+     * template. Switches back as soon as enroll is complete, signalled by
+     * (fingerprintMsg.type == FINGERPRINT_TEMPLATE_ENROLLING &&
+     *  fingerprintMsg.data.enroll.samplesRemaining == 0)
+     * or after timeoutSec seconds.
+     * The fingerprint template must be assigned to the group gid.
+     *
+     * @param hat a valid Hardware Authentication Token (HAT), generated
+     * as a result of a preEnroll() call.
+     * @param gid a framework defined fingerprint set (group) id.
+     * @param timeoutSec a timeout in seconds.
+     * @param windowId optional ID of an illumination window for optical under
+     * display fingerprint sensors. Must contain a null pointer if not used.
+     *
+     * @return debugErrno is a value the framework logs in case it is not 0.
+     *
+     * A notify() function may be called with a more detailed error structure.
+     */
+    enroll_2_2(vec<uint8_t> hat, uint32_t gid, uint32_t timeoutSec, handle windowId)
+        generates (RequestStatus debugErrno);
+
+    /**
+     * Authenticates an operation identified by operationId
+     *
+     * @param operationId operation id.
+     * @param gid fingerprint group id.
+     * @param windowId optional ID of an illumination window for optical under
+     * display fingerprint sensors. Must contain a null pointer if not used.
+     *
+     * @return debugErrno is a value the framework logs in case it is not 0.
+     */
+    authenticate_2_2(uint64_t operationId, uint32_t gid, handle windowId)
+        generates (RequestStatus debugErrno);
+};
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..50bd4ab
--- /dev/null
+++ b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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/IBiometricsFingerprintClientCallback.h>
+#include <android/hardware/biometrics/fingerprint/2.2/IBiometricsFingerprint.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+#include <cinttypes>
+#include <random>
+
+using android::sp;
+using android::base::GetUintProperty;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::biometrics::fingerprint::V2_1::FingerprintAcquiredInfo;
+using android::hardware::biometrics::fingerprint::V2_1::FingerprintError;
+using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
+using android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
+using android::hardware::biometrics::fingerprint::V2_2::IBiometricsFingerprint;
+
+namespace {
+
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr uint32_t kGroupId = 99;
+constexpr char kCallbackNameOnError[] = "onError";
+
+// Callback arguments that need to be captured for the tests.
+struct FingerprintCallbackArgs {
+    // The error passed to the last onError() callback.
+    FingerprintError error;
+
+    // The deviceId passed to the last callback.
+    uint64_t deviceId;
+};
+
+// 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 IBiometricsFingerprintClientCallback {
+  public:
+    Return<void> onEnrollResult(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+
+    Return<void> onAcquired(uint64_t, FingerprintAcquiredInfo, int32_t) override { return Void(); }
+
+    Return<void> onAuthenticated(uint64_t, uint32_t, uint32_t, const hidl_vec<uint8_t>&) override {
+        return Void();
+    }
+
+    Return<void> onError(uint64_t deviceId, FingerprintError error, int32_t) override {
+        FingerprintCallbackArgs args = {};
+        args.error = error;
+        args.deviceId = deviceId;
+        NotifyFromCallback(kCallbackNameOnError, args);
+        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;
+};
+
+// Enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FingerprintHidlTest, EnrollZeroHatTest) {
+    // Filling HAT with zeros
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; i++) {
+        token[i] = 0;
+    }
+
+    hidl_handle windowId = nullptr;
+    Return<RequestStatus> ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(ret));
+
+    // At least one call to onError should occur
+    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+    ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error);
+}
+
+// Enroll with an invalid (null) HAT should fail.
+TEST_P(FingerprintHidlTest, EnrollGarbageHatTest) {
+    // Filling HAT with pseudorandom invalid data.
+    // Using default seed to make the test reproducible.
+    std::mt19937 gen(std::mt19937::default_seed);
+    std::uniform_int_distribution<uint8_t> dist;
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; ++i) {
+        token[i] = dist(gen);
+    }
+
+    hidl_handle windowId = nullptr;
+    Return<RequestStatus> ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId);
+    ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(ret));
+
+    // At least one call to onError should occur
+    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+    ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error);
+}
+
+}  // anonymous namespace
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IBiometricsFingerprint::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
index 3e5c6d7..f4390b2 100644
--- a/camera/common/1.0/default/Android.bp
+++ b/camera/common/1.0/default/Android.bp
@@ -21,6 +21,7 @@
         "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"],
diff --git a/camera/common/1.0/default/Exif.cpp b/camera/common/1.0/default/Exif.cpp
index 4de05c5..413b6bb 100644
--- a/camera/common/1.0/default/Exif.cpp
+++ b/camera/common/1.0/default/Exif.cpp
@@ -632,13 +632,13 @@
 }
 
 bool ExifUtilsImpl::setImageHeight(uint32_t length) {
-    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
     SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, length);
     return true;
 }
 
 bool ExifUtilsImpl::setImageWidth(uint32_t width) {
-    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
     SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width);
     return true;
 }
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index b8c40e9..7792b31 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -27,7 +27,9 @@
 
 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 +38,12 @@
         return;
     }
 
+    mMapperV4 = IMapperV4::getService();
+    if (mMapperV4 != nullptr) {
+        mInitialized = true;
+        return;
+    }
+
     mMapperV3 = IMapperV3::getService();
     if (mMapperV3 != nullptr) {
         mInitialized = true;
@@ -53,6 +61,7 @@
 }
 
 void HandleImporter::cleanup() {
+    mMapperV4.clear();
     mMapperV3.clear();
     mMapperV2.clear();
     mInitialized = false;
@@ -151,6 +160,10 @@
         initializeLocked();
     }
 
+    if (mMapperV4 != nullptr) {
+        return importBufferInternal<IMapperV4, MapperErrorV4>(mMapperV4, handle);
+    }
+
     if (mMapperV3 != nullptr) {
         return importBufferInternal<IMapperV3, MapperErrorV3>(mMapperV3, handle);
     }
@@ -159,7 +172,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 +182,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",
@@ -222,14 +239,26 @@
         initializeLocked();
     }
 
-    if (mMapperV3 == nullptr && mMapperV2 == nullptr) {
-        ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+    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) {
+    if (mMapperV4 != nullptr) {
+        IMapperV4::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.
+        mMapperV4->lock(buffer, cpuUsage, accessRegion, 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 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.
@@ -269,6 +298,16 @@
         initializeLocked();
     }
 
+    if (mMapperV4 != nullptr) {
+        // No device currently supports IMapper 4.0 so it is safe to just return an error code here.
+        //
+        // This will be supported by a combination of lock and BufferMetadata getters. We are going
+        // to refactor all the IAllocator/IMapper versioning code into a shared library. We will
+        // then add the IMapper 4.0 lockYCbCr support then.
+        ALOGE("%s: MapperV4 doesn't support lockYCbCr directly!", __FUNCTION__);
+        return {};
+    }
+
     if (mMapperV3 != nullptr) {
         return lockYCbCrInternal<IMapperV3, MapperErrorV3>(
                 mMapperV3, buf, cpuUsage, accessRegion);
@@ -279,11 +318,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 +333,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..fc2bbd1 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;
@@ -70,6 +71,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..e6e6485 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -14,6 +14,7 @@
         "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",
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
index e4d9e85..878878d 100644
--- a/camera/device/3.2/default/Android.bp
+++ b/camera/device/3.2/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",
         "liblog",
         "libhardware",
         "libcamera_metadata",
diff --git a/camera/device/3.3/default/Android.bp b/camera/device/3.3/default/Android.bp
index d964f3d..7d51434 100644
--- a/camera/device/3.3/default/Android.bp
+++ b/camera/device/3.3/default/Android.bp
@@ -15,6 +15,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",
         "liblog",
         "libhardware",
         "libcamera_metadata",
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index 71a9e77..59e8329 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -48,6 +48,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",
         "liblog",
         "libhardware",
         "libcamera_metadata",
@@ -84,6 +85,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",
         "liblog",
         "libhardware",
         "libcamera_metadata",
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 9ff0d74..5f86742 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -81,8 +81,6 @@
     return locked;
 }
 
-buffer_handle_t sEmptyBuffer = nullptr;
-
 } // Anonymous namespace
 
 // Static instances
@@ -119,8 +117,8 @@
     std::string make, model;
     if (ret < 0) {
         ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__);
-        make = "Generic UVC webcam";
-        model = "Generic UVC webcam";
+        mExifMake = "Generic UVC webcam";
+        mExifModel = "Generic UVC webcam";
     } else {
         // capability.card is UTF-8 encoded
         char card[32];
@@ -134,11 +132,11 @@
             }
         }
         if (j == 0 || card[j - 1] != '\0') {
-            make = "Generic UVC webcam";
-            model = "Generic UVC webcam";
+            mExifMake = "Generic UVC webcam";
+            mExifModel = "Generic UVC webcam";
         } else {
-            make = card;
-            model = card;
+            mExifMake = card;
+            mExifModel = card;
         }
     }
 
@@ -147,7 +145,7 @@
         ALOGE("%s: init OutputThread failed!", __FUNCTION__);
         return true;
     }
-    mOutputThread->setExifMakeModel(make, model);
+    mOutputThread->setExifMakeModel(mExifMake, mExifModel);
 
     status_t status = initDefaultRequests();
     if (status != OK) {
@@ -161,7 +159,7 @@
         ALOGE("%s: invalid request fmq", __FUNCTION__);
         return true;
     }
-    mResultMetadataQueue = std::make_shared<RequestMetadataQueue>(
+    mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
             kMetadataMsgQueueSize, false /* non blocking */);
     if (!mResultMetadataQueue->isValid()) {
         ALOGE("%s: invalid result fmq", __FUNCTION__);
@@ -183,7 +181,7 @@
 }
 
 void ExternalCameraDeviceSession::initOutputThread() {
-    mOutputThread = new OutputThread(this, mCroppingType);
+    mOutputThread = new OutputThread(this, mCroppingType, mCameraCharacteristics);
 }
 
 void ExternalCameraDeviceSession::closeOutputThread() {
@@ -518,35 +516,9 @@
         uint64_t bufId, buffer_handle_t buf,
         /*out*/buffer_handle_t** outBufPtr,
         bool allowEmptyBuf) {
-
-    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
-        if (allowEmptyBuf) {
-            *outBufPtr = &sEmptyBuffer;
-            return Status::OK;
-        } else {
-            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
-            return Status::ILLEGAL_ARGUMENT;
-        }
-    }
-
-    CirculatingBuffers& cbs = mCirculatingBuffers[streamId];
-    if (cbs.count(bufId) == 0) {
-        if (buf == nullptr) {
-            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
-            return Status::ILLEGAL_ARGUMENT;
-        }
-        // Register a newly seen buffer
-        buffer_handle_t importedBuf = buf;
-        sHandleImporter.importBuffer(importedBuf);
-        if (importedBuf == nullptr) {
-            ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
-            return Status::INTERNAL_ERROR;
-        } else {
-            cbs[bufId] = importedBuf;
-        }
-    }
-    *outBufPtr = &cbs[bufId];
-    return Status::OK;
+    return importBufferImpl(
+            mCirculatingBuffers, sHandleImporter, streamId,
+            bufId, buf, outBufPtr, allowEmptyBuf);
 }
 
 Status ExternalCameraDeviceSession::importRequestLockedImpl(
@@ -791,15 +763,32 @@
 
 //TODO: refactor with processCaptureResult
 Status ExternalCameraDeviceSession::processCaptureRequestError(
-        const std::shared_ptr<HalRequest>& req) {
+        const std::shared_ptr<HalRequest>& req,
+        /*out*/std::vector<NotifyMsg>* outMsgs,
+        /*out*/std::vector<CaptureResult>* outResults) {
     ATRACE_CALL();
     // Return V4L2 buffer to V4L2 buffer queue
-    enqueueV4l2Frame(req->frameIn);
+    sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+            static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+    enqueueV4l2Frame(v4l2Frame);
 
-    // NotifyShutter
-    notifyShutter(req->frameNumber, req->shutterTs);
+    if (outMsgs == nullptr) {
+        notifyShutter(req->frameNumber, req->shutterTs);
+        notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+    } else {
+        NotifyMsg shutter;
+        shutter.type = MsgType::SHUTTER;
+        shutter.msg.shutter.frameNumber = req->frameNumber;
+        shutter.msg.shutter.timestamp = req->shutterTs;
 
-    notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+        NotifyMsg error;
+        error.type = MsgType::ERROR;
+        error.msg.error.frameNumber = req->frameNumber;
+        error.msg.error.errorStreamId = -1;
+        error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+        outMsgs->push_back(shutter);
+        outMsgs->push_back(error);
+    }
 
     // Fill output buffers
     hidl_vec<CaptureResult> results;
@@ -826,16 +815,22 @@
         mInflightFrames.erase(req->frameNumber);
     }
 
-    // Callback into framework
-    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
-    freeReleaseFences(results);
+    if (outResults == nullptr) {
+        // Callback into framework
+        invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+        freeReleaseFences(results);
+    } else {
+        outResults->push_back(result);
+    }
     return Status::OK;
 }
 
 Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
     ATRACE_CALL();
     // Return V4L2 buffer to V4L2 buffer queue
-    enqueueV4l2Frame(req->frameIn);
+    sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+            static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+    enqueueV4l2Frame(v4l2Frame);
 
     // NotifyShutter
     notifyShutter(req->frameNumber, req->shutterTs);
@@ -923,29 +918,10 @@
     mProcessCaptureResultLock.unlock();
 }
 
-void ExternalCameraDeviceSession::freeReleaseFences(hidl_vec<CaptureResult>& results) {
-    for (auto& result : results) {
-        if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
-            native_handle_t* handle = const_cast<native_handle_t*>(
-                    result.inputBuffer.releaseFence.getNativeHandle());
-            native_handle_close(handle);
-            native_handle_delete(handle);
-        }
-        for (auto& buf : result.outputBuffers) {
-            if (buf.releaseFence.getNativeHandle() != nullptr) {
-                native_handle_t* handle = const_cast<native_handle_t*>(
-                        buf.releaseFence.getNativeHandle());
-                native_handle_close(handle);
-                native_handle_delete(handle);
-            }
-        }
-    }
-    return;
-}
-
 ExternalCameraDeviceSession::OutputThread::OutputThread(
-        wp<ExternalCameraDeviceSession> parent,
-        CroppingType ct) : mParent(parent), mCroppingType(ct) {}
+        wp<OutputThreadInterface> parent, CroppingType ct,
+        const common::V1_0::helper::CameraMetadata& chars) :
+        mParent(parent), mCroppingType(ct), mCameraCharacteristics(chars) {}
 
 ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
 
@@ -955,88 +931,6 @@
     mExifModel = model;
 }
 
-uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout(
-        const YCbCrLayout& layout) {
-    intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
-    intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
-    if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
-        // Interleaved format
-        if (layout.cb > layout.cr) {
-            return V4L2_PIX_FMT_NV21;
-        } else {
-            return V4L2_PIX_FMT_NV12;
-        }
-    } else if (layout.chromaStep == 1) {
-        // Planar format
-        if (layout.cb > layout.cr) {
-            return V4L2_PIX_FMT_YVU420; // YV12
-        } else {
-            return V4L2_PIX_FMT_YUV420; // YU12
-        }
-    } else {
-        return FLEX_YUV_GENERIC;
-    }
-}
-
-int ExternalCameraDeviceSession::OutputThread::getCropRect(
-        CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
-    if (out == nullptr) {
-        ALOGE("%s: out is null", __FUNCTION__);
-        return -1;
-    }
-
-    uint32_t inW = inSize.width;
-    uint32_t inH = inSize.height;
-    uint32_t outW = outSize.width;
-    uint32_t outH = outSize.height;
-
-    // Handle special case where aspect ratio is close to input but scaled
-    // dimension is slightly larger than input
-    float arIn = ASPECT_RATIO(inSize);
-    float arOut = ASPECT_RATIO(outSize);
-    if (isAspectRatioClose(arIn, arOut)) {
-        out->left = 0;
-        out->top = 0;
-        out->width = inW;
-        out->height = inH;
-        return 0;
-    }
-
-    if (ct == VERTICAL) {
-        uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
-        if (scaledOutH > inH) {
-            ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
-                    __FUNCTION__, outW, outH, inW, inH);
-            return -1;
-        }
-        scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
-
-        out->left = 0;
-        out->top = ((inH - scaledOutH) / 2) & ~0x1;
-        out->width = inW;
-        out->height = static_cast<int32_t>(scaledOutH);
-        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
-                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
-    } else {
-        uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
-        if (scaledOutW > inW) {
-            ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
-                    __FUNCTION__, outW, outH, inW, inH);
-            return -1;
-        }
-        scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
-
-        out->left = ((inW - scaledOutW) / 2) & ~0x1;
-        out->top = 0;
-        out->width = static_cast<int32_t>(scaledOutW);
-        out->height = inH;
-        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
-                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
-    }
-
-    return 0;
-}
-
 int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
         sp<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
     Size inSz = {in->mWidth, in->mHeight};
@@ -1274,265 +1168,6 @@
     return 0;
 }
 
-int ExternalCameraDeviceSession::OutputThread::formatConvertLocked(
-        const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
-    int ret = 0;
-    switch (format) {
-        case V4L2_PIX_FMT_NV21:
-            ret = libyuv::I420ToNV21(
-                    static_cast<uint8_t*>(in.y),
-                    in.yStride,
-                    static_cast<uint8_t*>(in.cb),
-                    in.cStride,
-                    static_cast<uint8_t*>(in.cr),
-                    in.cStride,
-                    static_cast<uint8_t*>(out.y),
-                    out.yStride,
-                    static_cast<uint8_t*>(out.cr),
-                    out.cStride,
-                    sz.width,
-                    sz.height);
-            if (ret != 0) {
-                ALOGE("%s: convert to NV21 buffer failed! ret %d",
-                            __FUNCTION__, ret);
-                return ret;
-            }
-            break;
-        case V4L2_PIX_FMT_NV12:
-            ret = libyuv::I420ToNV12(
-                    static_cast<uint8_t*>(in.y),
-                    in.yStride,
-                    static_cast<uint8_t*>(in.cb),
-                    in.cStride,
-                    static_cast<uint8_t*>(in.cr),
-                    in.cStride,
-                    static_cast<uint8_t*>(out.y),
-                    out.yStride,
-                    static_cast<uint8_t*>(out.cb),
-                    out.cStride,
-                    sz.width,
-                    sz.height);
-            if (ret != 0) {
-                ALOGE("%s: convert to NV12 buffer failed! ret %d",
-                            __FUNCTION__, ret);
-                return ret;
-            }
-            break;
-        case V4L2_PIX_FMT_YVU420: // YV12
-        case V4L2_PIX_FMT_YUV420: // YU12
-            // TODO: maybe we can speed up here by somehow save this copy?
-            ret = libyuv::I420Copy(
-                    static_cast<uint8_t*>(in.y),
-                    in.yStride,
-                    static_cast<uint8_t*>(in.cb),
-                    in.cStride,
-                    static_cast<uint8_t*>(in.cr),
-                    in.cStride,
-                    static_cast<uint8_t*>(out.y),
-                    out.yStride,
-                    static_cast<uint8_t*>(out.cb),
-                    out.cStride,
-                    static_cast<uint8_t*>(out.cr),
-                    out.cStride,
-                    sz.width,
-                    sz.height);
-            if (ret != 0) {
-                ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
-                            __FUNCTION__, ret);
-                return ret;
-            }
-            break;
-        case FLEX_YUV_GENERIC:
-            // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
-            ALOGE("%s: unsupported flexible yuv layout"
-                    " y %p cb %p cr %p y_str %d c_str %d c_step %d",
-                    __FUNCTION__, out.y, out.cb, out.cr,
-                    out.yStride, out.cStride, out.chromaStep);
-            return -1;
-        default:
-            ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
-            return -1;
-    }
-    return 0;
-}
-
-int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12(
-        const Size & inSz, const YCbCrLayout& inLayout,
-        int jpegQuality, const void *app1Buffer, size_t app1Size,
-        void *out, const size_t maxOutSize, size_t &actualCodeSize)
-{
-    /* libjpeg is a C library so we use C-style "inheritance" by
-     * putting libjpeg's jpeg_destination_mgr first in our custom
-     * struct. This allows us to cast jpeg_destination_mgr* to
-     * CustomJpegDestMgr* when we get it passed to us in a callback */
-    struct CustomJpegDestMgr {
-        struct jpeg_destination_mgr mgr;
-        JOCTET *mBuffer;
-        size_t mBufferSize;
-        size_t mEncodedSize;
-        bool mSuccess;
-    } dmgr;
-
-    jpeg_compress_struct cinfo = {};
-    jpeg_error_mgr jerr;
-
-    /* Initialize error handling with standard callbacks, but
-     * then override output_message (to print to ALOG) and
-     * error_exit to set a flag and print a message instead
-     * of killing the whole process */
-    cinfo.err = jpeg_std_error(&jerr);
-
-    cinfo.err->output_message = [](j_common_ptr cinfo) {
-        char buffer[JMSG_LENGTH_MAX];
-
-        /* Create the message */
-        (*cinfo->err->format_message)(cinfo, buffer);
-        ALOGE("libjpeg error: %s", buffer);
-    };
-    cinfo.err->error_exit = [](j_common_ptr cinfo) {
-        (*cinfo->err->output_message)(cinfo);
-        if(cinfo->client_data) {
-            auto & dmgr =
-                *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
-            dmgr.mSuccess = false;
-        }
-    };
-    /* Now that we initialized some callbacks, let's create our compressor */
-    jpeg_create_compress(&cinfo);
-
-    /* Initialize our destination manager */
-    dmgr.mBuffer = static_cast<JOCTET*>(out);
-    dmgr.mBufferSize = maxOutSize;
-    dmgr.mEncodedSize = 0;
-    dmgr.mSuccess = true;
-    cinfo.client_data = static_cast<void*>(&dmgr);
-
-    /* These lambdas become C-style function pointers and as per C++11 spec
-     * may not capture anything */
-    dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
-        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
-        dmgr.mgr.next_output_byte = dmgr.mBuffer;
-        dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
-        ALOGV("%s:%d jpeg start: %p [%zu]",
-              __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
-    };
-
-    dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
-        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
-        return 0;
-    };
-
-    dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
-        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
-        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
-        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
-    };
-    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
-
-    /* We are going to be using JPEG in raw data mode, so we are passing
-     * straight subsampled planar YCbCr and it will not touch our pixel
-     * data or do any scaling or anything */
-    cinfo.image_width = inSz.width;
-    cinfo.image_height = inSz.height;
-    cinfo.input_components = 3;
-    cinfo.in_color_space = JCS_YCbCr;
-
-    /* Initialize defaults and then override what we want */
-    jpeg_set_defaults(&cinfo);
-
-    jpeg_set_quality(&cinfo, jpegQuality, 1);
-    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
-    cinfo.raw_data_in = 1;
-    cinfo.dct_method = JDCT_IFAST;
-
-    /* Configure sampling factors. The sampling factor is JPEG subsampling 420
-     * because the source format is YUV420. Note that libjpeg sampling factors
-     * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
-     * 1 V value for each 2 Y values */
-    cinfo.comp_info[0].h_samp_factor = 2;
-    cinfo.comp_info[0].v_samp_factor = 2;
-    cinfo.comp_info[1].h_samp_factor = 1;
-    cinfo.comp_info[1].v_samp_factor = 1;
-    cinfo.comp_info[2].h_samp_factor = 1;
-    cinfo.comp_info[2].v_samp_factor = 1;
-
-    /* Let's not hardcode YUV420 in 6 places... 5 was enough */
-    int maxVSampFactor = std::max( {
-        cinfo.comp_info[0].v_samp_factor,
-        cinfo.comp_info[1].v_samp_factor,
-        cinfo.comp_info[2].v_samp_factor
-    });
-    int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
-                        cinfo.comp_info[1].v_samp_factor;
-
-    /* Start the compressor */
-    jpeg_start_compress(&cinfo, TRUE);
-
-    /* Compute our macroblock height, so we can pad our input to be vertically
-     * macroblock aligned.
-     * TODO: Does it need to be horizontally MCU aligned too? */
-
-    size_t mcuV = DCTSIZE*maxVSampFactor;
-    size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
-
-    /* libjpeg uses arrays of row pointers, which makes it really easy to pad
-     * data vertically (unfortunately doesn't help horizontally) */
-    std::vector<JSAMPROW> yLines (paddedHeight);
-    std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
-    std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
-
-    uint8_t *py = static_cast<uint8_t*>(inLayout.y);
-    uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
-    uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
-
-    for(uint32_t i = 0; i < paddedHeight; i++)
-    {
-        /* Once we are in the padding territory we still point to the last line
-         * effectively replicating it several times ~ CLAMP_TO_EDGE */
-        int li = std::min(i, inSz.height - 1);
-        yLines[i]  = static_cast<JSAMPROW>(py + li * inLayout.yStride);
-        if(i < paddedHeight / cVSubSampling)
-        {
-            crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
-            cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
-        }
-    }
-
-    /* If APP1 data was passed in, use it */
-    if(app1Buffer && app1Size)
-    {
-        jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
-             static_cast<const JOCTET*>(app1Buffer), app1Size);
-    }
-
-    /* While we still have padded height left to go, keep giving it one
-     * macroblock at a time. */
-    while (cinfo.next_scanline < cinfo.image_height) {
-        const uint32_t batchSize = DCTSIZE * maxVSampFactor;
-        const uint32_t nl = cinfo.next_scanline;
-        JSAMPARRAY planes[3]{ &yLines[nl],
-                              &cbLines[nl/cVSubSampling],
-                              &crLines[nl/cVSubSampling] };
-
-        uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
-
-        if (done != batchSize) {
-            ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
-              __FUNCTION__, done, batchSize, cinfo.next_scanline,
-              cinfo.image_height);
-            return -1;
-        }
-    }
-
-    /* This will flush everything */
-    jpeg_finish_compress(&cinfo);
-
-    /* Grab the actual code size and set it */
-    actualCodeSize = dmgr.mEncodedSize;
-
-    return 0;
-}
-
 /*
  * TODO: There needs to be a mechanism to discover allocated buffer size
  * in the HAL.
@@ -1555,25 +1190,9 @@
 }
 
 Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
-    Size thumbSize { 0, 0 };
-    camera_metadata_ro_entry entry =
-        mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
-    for(uint32_t i = 0; i < entry.count; i += 2) {
-        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
-                  static_cast<uint32_t>(entry.data.i32[i+1]) };
-        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
-            thumbSize = sz;
-        }
-    }
-
-    if (thumbSize.width * thumbSize.height == 0) {
-        ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
-    }
-
-    return thumbSize;
+    return getMaxThumbnailResolution(mCameraCharacteristics);
 }
 
-
 ssize_t ExternalCameraDeviceSession::getJpegBufferSize(
         uint32_t width, uint32_t height) const {
     // Constant from camera3.h
@@ -1616,7 +1235,7 @@
 
 int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
         HalStreamBuffer &halBuf,
-        const std::shared_ptr<HalRequest>& req)
+        const common::V1_0::helper::CameraMetadata& setting)
 {
     ATRACE_CALL();
     int ret;
@@ -1645,17 +1264,17 @@
     Size thumbSize;
     bool outputThumbnail = true;
 
-    if (req->setting.exists(ANDROID_JPEG_QUALITY)) {
-        camera_metadata_entry entry =
-            req->setting.find(ANDROID_JPEG_QUALITY);
+    if (setting.exists(ANDROID_JPEG_QUALITY)) {
+        camera_metadata_ro_entry entry =
+            setting.find(ANDROID_JPEG_QUALITY);
         jpegQuality = entry.data.u8[0];
     } else {
         return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__);
     }
 
-    if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
-        camera_metadata_entry entry =
-            req->setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+    if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+        camera_metadata_ro_entry entry =
+            setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
         thumbQuality = entry.data.u8[0];
     } else {
         return lfail(
@@ -1663,9 +1282,9 @@
             __FUNCTION__);
     }
 
-    if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
-        camera_metadata_entry entry =
-            req->setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+    if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+        camera_metadata_ro_entry entry =
+            setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
         thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
                            static_cast<uint32_t>(entry.data.i32[1])
         };
@@ -1732,8 +1351,8 @@
 
     /* Combine camera characteristics with request settings to form EXIF
      * metadata */
-    common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics);
-    meta.append(req->setting);
+    common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics);
+    meta.append(setting);
 
     /* Generate EXIF object */
     std::unique_ptr<ExifUtils> utils(ExifUtils::create());
@@ -1838,7 +1457,7 @@
     // TODO: see if we can save some computation by converting to YV12 here
     uint8_t* inData;
     size_t inDataSize;
-    if (req->frameIn->map(&inData, &inDataSize) != 0) {
+    if (req->frameIn->getData(&inData, &inDataSize) != 0) {
         lk.unlock();
         return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
     }
@@ -1899,7 +1518,7 @@
         // Gralloc lockYCbCr the buffer
         switch (halBuf.format) {
             case PixelFormat::BLOB: {
-                int ret = createJpegLocked(halBuf, req);
+                int ret = createJpegLocked(halBuf, req->setting);
 
                 if(ret != 0) {
                     lk.unlock();
@@ -1949,8 +1568,8 @@
                 }
 
                 Size sz {halBuf.width, halBuf.height};
-                ATRACE_BEGIN("formatConvertLocked");
-                ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc);
+                ATRACE_BEGIN("formatConvert");
+                ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
                 ATRACE_END();
                 if (ret != 0) {
                     lk.unlock();
@@ -2055,6 +1674,14 @@
     return Status::OK;
 }
 
+void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() {
+    std::lock_guard<std::mutex> lk(mBufferLock);
+    mYu12Frame.clear();
+    mYu12ThumbFrame.clear();
+    mIntermediateBuffers.clear();
+    mBlobBufferSize = 0;
+}
+
 Status ExternalCameraDeviceSession::OutputThread::submitRequest(
         const std::shared_ptr<HalRequest>& req) {
     std::unique_lock<std::mutex> lk(mRequestListLock);
@@ -2090,6 +1717,32 @@
     }
 }
 
+std::list<std::shared_ptr<HalRequest>>
+ExternalCameraDeviceSession::OutputThread::switchToOffline() {
+    ATRACE_CALL();
+    std::list<std::shared_ptr<HalRequest>> emptyList;
+    auto parent = mParent.promote();
+    if (parent == nullptr) {
+       ALOGE("%s: session has been disconnected!", __FUNCTION__);
+       return emptyList;
+    }
+
+    std::unique_lock<std::mutex> lk(mRequestListLock);
+    std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
+    mRequestList.clear();
+    if (mProcessingRequest) {
+        std::chrono::seconds timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+        auto st = mRequestDoneCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+        }
+    }
+    lk.unlock();
+    clearIntermediateBuffers();
+    ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size());
+    return reqs;
+}
+
 void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(
         std::shared_ptr<HalRequest>* out) {
     ATRACE_CALL();
@@ -2733,6 +2386,7 @@
         return Status::INTERNAL_ERROR;
     }
 
+    mBlobBufferSize = blobBufferSize;
     status = mOutputThread->allocateIntermediateBuffers(v4lSize,
                 mMaxThumbResolution, config.streams, blobBufferSize);
     if (status != Status::OK) {
@@ -2916,16 +2570,6 @@
 
 status_t ExternalCameraDeviceSession::fillCaptureResult(
         common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
-    // android.control
-    // For USB camera, we don't know the AE state. Set the state to converged to
-    // indicate the frame should be good to use. Then apps don't have to wait the
-    // AE state.
-    const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
-    UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
-
-    const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
-    UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
-
     bool afTrigger = false;
     {
         std::lock_guard<std::mutex> lk(mAfTriggerLock);
@@ -2951,46 +2595,10 @@
     }
     UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
 
-    // Set AWB state to converged to indicate the frame should be good to use.
-    const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
-    UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+    camera_metadata_ro_entry activeArraySize =
+            mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
 
-    const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
-    UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
-
-    camera_metadata_ro_entry active_array_size =
-        mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
-
-    if (active_array_size.count == 0) {
-        ALOGE("%s: cannot find active array size!", __FUNCTION__);
-        return -EINVAL;
-    }
-
-    const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
-    UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
-
-    // This means pipeline latency of X frame intervals. The maximum number is 4.
-    const uint8_t requestPipelineMaxDepth = 4;
-    UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
-
-    // android.scaler
-    const int32_t crop_region[] = {
-          active_array_size.data.i32[0], active_array_size.data.i32[1],
-          active_array_size.data.i32[2], active_array_size.data.i32[3],
-    };
-    UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
-
-    // android.sensor
-    UPDATE(md, ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
-
-    // android.statistics
-    const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
-    UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
-
-    const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
-    UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
-
-    return OK;
+    return fillCaptureResultCommon(md, timestamp, activeArraySize);
 }
 
 #undef ARRAY_SIZE
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index e25deff..62a4c87 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -18,10 +18,23 @@
 #include <log/log.h>
 
 #include <cmath>
+#include <cstring>
 #include <sys/mman.h>
 #include <linux/videodev2.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <jpeglib.h>
+
 #include "ExternalCameraUtils.h"
 
+namespace {
+
+buffer_handle_t sEmptyBuffer = nullptr;
+
+} // Anonymous namespace
+
 namespace android {
 namespace hardware {
 namespace camera {
@@ -29,10 +42,13 @@
 namespace V3_4 {
 namespace implementation {
 
+Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc) :
+        mWidth(width), mHeight(height), mFourcc(fourcc) {}
+
 V4L2Frame::V4L2Frame(
         uint32_t w, uint32_t h, uint32_t fourcc,
         int bufIdx, int fd, uint32_t dataSize, uint64_t offset) :
-        mWidth(w), mHeight(h), mFourcc(fourcc),
+        Frame(w, h, fourcc),
         mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {}
 
 int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
@@ -75,9 +91,13 @@
     unmap();
 }
 
+int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+    return map(outData, dataSize);
+}
+
 AllocatedFrame::AllocatedFrame(
         uint32_t w, uint32_t h) :
-        mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {};
+        Frame(w, h, V4L2_PIX_FMT_YUV420) {};
 
 AllocatedFrame::~AllocatedFrame() {}
 
@@ -106,6 +126,17 @@
     return 0;
 }
 
+int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) {
+    YCbCrLayout layout;
+    int ret = allocate(&layout);
+    if (ret != 0) {
+        return ret;
+    }
+    *outData = mData.data();
+    *dataSize = mData.size();
+    return 0;
+}
+
 int AllocatedFrame::getLayout(YCbCrLayout* out) {
     IMapper::Rect noCrop = {0, 0,
             static_cast<int32_t>(mWidth),
@@ -150,8 +181,521 @@
     return durationDenominator / static_cast<double>(durationNumerator);
 }
 
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+        /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*inout*/HandleImporter& handleImporter,
+        int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf) {
+    using ::android::hardware::camera::common::V1_0::Status;
+    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+        if (allowEmptyBuf) {
+            *outBufPtr = &sEmptyBuffer;
+            return Status::OK;
+        } else {
+            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+            return Status::ILLEGAL_ARGUMENT;
+        }
+    }
+
+    CirculatingBuffers& cbs = circulatingBuffers[streamId];
+    if (cbs.count(bufId) == 0) {
+        if (buf == nullptr) {
+            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+            return Status::ILLEGAL_ARGUMENT;
+        }
+        // Register a newly seen buffer
+        buffer_handle_t importedBuf = buf;
+        handleImporter.importBuffer(importedBuf);
+        if (importedBuf == nullptr) {
+            ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
+            return Status::INTERNAL_ERROR;
+        } else {
+            cbs[bufId] = importedBuf;
+        }
+    }
+    *outBufPtr = &cbs[bufId];
+    return Status::OK;
+}
+
+uint32_t getFourCcFromLayout(const YCbCrLayout& layout) {
+    intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
+    intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
+    if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
+        // Interleaved format
+        if (layout.cb > layout.cr) {
+            return V4L2_PIX_FMT_NV21;
+        } else {
+            return V4L2_PIX_FMT_NV12;
+        }
+    } else if (layout.chromaStep == 1) {
+        // Planar format
+        if (layout.cb > layout.cr) {
+            return V4L2_PIX_FMT_YVU420; // YV12
+        } else {
+            return V4L2_PIX_FMT_YUV420; // YU12
+        }
+    } else {
+        return FLEX_YUV_GENERIC;
+    }
+}
+
+int getCropRect(
+        CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
+    if (out == nullptr) {
+        ALOGE("%s: out is null", __FUNCTION__);
+        return -1;
+    }
+
+    uint32_t inW = inSize.width;
+    uint32_t inH = inSize.height;
+    uint32_t outW = outSize.width;
+    uint32_t outH = outSize.height;
+
+    // Handle special case where aspect ratio is close to input but scaled
+    // dimension is slightly larger than input
+    float arIn = ASPECT_RATIO(inSize);
+    float arOut = ASPECT_RATIO(outSize);
+    if (isAspectRatioClose(arIn, arOut)) {
+        out->left = 0;
+        out->top = 0;
+        out->width = inW;
+        out->height = inH;
+        return 0;
+    }
+
+    if (ct == VERTICAL) {
+        uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
+        if (scaledOutH > inH) {
+            ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
+                    __FUNCTION__, outW, outH, inW, inH);
+            return -1;
+        }
+        scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
+
+        out->left = 0;
+        out->top = ((inH - scaledOutH) / 2) & ~0x1;
+        out->width = inW;
+        out->height = static_cast<int32_t>(scaledOutH);
+        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
+                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
+    } else {
+        uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
+        if (scaledOutW > inW) {
+            ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
+                    __FUNCTION__, outW, outH, inW, inH);
+            return -1;
+        }
+        scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
+
+        out->left = ((inW - scaledOutW) / 2) & ~0x1;
+        out->top = 0;
+        out->width = static_cast<int32_t>(scaledOutW);
+        out->height = inH;
+        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
+                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
+    }
+
+    return 0;
+}
+
+int formatConvert(
+        const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
+    int ret = 0;
+    switch (format) {
+        case V4L2_PIX_FMT_NV21:
+            ret = libyuv::I420ToNV21(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cr),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: convert to NV21 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case V4L2_PIX_FMT_NV12:
+            ret = libyuv::I420ToNV12(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cb),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: convert to NV12 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case V4L2_PIX_FMT_YVU420: // YV12
+        case V4L2_PIX_FMT_YUV420: // YU12
+            // TODO: maybe we can speed up here by somehow save this copy?
+            ret = libyuv::I420Copy(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cb),
+                    out.cStride,
+                    static_cast<uint8_t*>(out.cr),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case FLEX_YUV_GENERIC:
+            // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
+            ALOGE("%s: unsupported flexible yuv layout"
+                    " y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                    __FUNCTION__, out.y, out.cb, out.cr,
+                    out.yStride, out.cStride, out.chromaStep);
+            return -1;
+        default:
+            ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
+            return -1;
+    }
+    return 0;
+}
+
+int encodeJpegYU12(
+        const Size & inSz, const YCbCrLayout& inLayout,
+        int jpegQuality, const void *app1Buffer, size_t app1Size,
+        void *out, const size_t maxOutSize, size_t &actualCodeSize)
+{
+    /* libjpeg is a C library so we use C-style "inheritance" by
+     * putting libjpeg's jpeg_destination_mgr first in our custom
+     * struct. This allows us to cast jpeg_destination_mgr* to
+     * CustomJpegDestMgr* when we get it passed to us in a callback */
+    struct CustomJpegDestMgr {
+        struct jpeg_destination_mgr mgr;
+        JOCTET *mBuffer;
+        size_t mBufferSize;
+        size_t mEncodedSize;
+        bool mSuccess;
+    } dmgr;
+
+    jpeg_compress_struct cinfo = {};
+    jpeg_error_mgr jerr;
+
+    /* Initialize error handling with standard callbacks, but
+     * then override output_message (to print to ALOG) and
+     * error_exit to set a flag and print a message instead
+     * of killing the whole process */
+    cinfo.err = jpeg_std_error(&jerr);
+
+    cinfo.err->output_message = [](j_common_ptr cinfo) {
+        char buffer[JMSG_LENGTH_MAX];
+
+        /* Create the message */
+        (*cinfo->err->format_message)(cinfo, buffer);
+        ALOGE("libjpeg error: %s", buffer);
+    };
+    cinfo.err->error_exit = [](j_common_ptr cinfo) {
+        (*cinfo->err->output_message)(cinfo);
+        if(cinfo->client_data) {
+            auto & dmgr =
+                *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+            dmgr.mSuccess = false;
+        }
+    };
+    /* Now that we initialized some callbacks, let's create our compressor */
+    jpeg_create_compress(&cinfo);
+
+    /* Initialize our destination manager */
+    dmgr.mBuffer = static_cast<JOCTET*>(out);
+    dmgr.mBufferSize = maxOutSize;
+    dmgr.mEncodedSize = 0;
+    dmgr.mSuccess = true;
+    cinfo.client_data = static_cast<void*>(&dmgr);
+
+    /* These lambdas become C-style function pointers and as per C++11 spec
+     * may not capture anything */
+    dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mgr.next_output_byte = dmgr.mBuffer;
+        dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+        ALOGV("%s:%d jpeg start: %p [%zu]",
+              __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+    };
+
+    dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+        return 0;
+    };
+
+    dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+    };
+    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+    /* We are going to be using JPEG in raw data mode, so we are passing
+     * straight subsampled planar YCbCr and it will not touch our pixel
+     * data or do any scaling or anything */
+    cinfo.image_width = inSz.width;
+    cinfo.image_height = inSz.height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_YCbCr;
+
+    /* Initialize defaults and then override what we want */
+    jpeg_set_defaults(&cinfo);
+
+    jpeg_set_quality(&cinfo, jpegQuality, 1);
+    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+    cinfo.raw_data_in = 1;
+    cinfo.dct_method = JDCT_IFAST;
+
+    /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+     * because the source format is YUV420. Note that libjpeg sampling factors
+     * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+     * 1 V value for each 2 Y values */
+    cinfo.comp_info[0].h_samp_factor = 2;
+    cinfo.comp_info[0].v_samp_factor = 2;
+    cinfo.comp_info[1].h_samp_factor = 1;
+    cinfo.comp_info[1].v_samp_factor = 1;
+    cinfo.comp_info[2].h_samp_factor = 1;
+    cinfo.comp_info[2].v_samp_factor = 1;
+
+    /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+    int maxVSampFactor = std::max( {
+        cinfo.comp_info[0].v_samp_factor,
+        cinfo.comp_info[1].v_samp_factor,
+        cinfo.comp_info[2].v_samp_factor
+    });
+    int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
+                        cinfo.comp_info[1].v_samp_factor;
+
+    /* Start the compressor */
+    jpeg_start_compress(&cinfo, TRUE);
+
+    /* Compute our macroblock height, so we can pad our input to be vertically
+     * macroblock aligned.
+     * TODO: Does it need to be horizontally MCU aligned too? */
+
+    size_t mcuV = DCTSIZE*maxVSampFactor;
+    size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+    /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+     * data vertically (unfortunately doesn't help horizontally) */
+    std::vector<JSAMPROW> yLines (paddedHeight);
+    std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
+    std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
+
+    uint8_t *py = static_cast<uint8_t*>(inLayout.y);
+    uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
+    uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
+
+    for(uint32_t i = 0; i < paddedHeight; i++)
+    {
+        /* Once we are in the padding territory we still point to the last line
+         * effectively replicating it several times ~ CLAMP_TO_EDGE */
+        int li = std::min(i, inSz.height - 1);
+        yLines[i]  = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+        if(i < paddedHeight / cVSubSampling)
+        {
+            li = std::min(i, (inSz.height - 1) / cVSubSampling);
+            crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+            cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+        }
+    }
+
+    /* If APP1 data was passed in, use it */
+    if(app1Buffer && app1Size)
+    {
+        jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
+             static_cast<const JOCTET*>(app1Buffer), app1Size);
+    }
+
+    /* While we still have padded height left to go, keep giving it one
+     * macroblock at a time. */
+    while (cinfo.next_scanline < cinfo.image_height) {
+        const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+        const uint32_t nl = cinfo.next_scanline;
+        JSAMPARRAY planes[3]{ &yLines[nl],
+                              &cbLines[nl/cVSubSampling],
+                              &crLines[nl/cVSubSampling] };
+
+        uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+        if (done != batchSize) {
+            ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
+              __FUNCTION__, done, batchSize, cinfo.next_scanline,
+              cinfo.image_height);
+            return -1;
+        }
+    }
+
+    /* This will flush everything */
+    jpeg_finish_compress(&cinfo);
+
+    /* Grab the actual code size and set it */
+    actualCodeSize = dmgr.mEncodedSize;
+
+    return 0;
+}
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) {
+    Size thumbSize { 0, 0 };
+    camera_metadata_ro_entry entry =
+        chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for(uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+                  static_cast<uint32_t>(entry.data.i32[i+1]) };
+        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+    }
+
+    return thumbSize;
+}
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>& results) {
+    for (auto& result : results) {
+        if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+            native_handle_t* handle = const_cast<native_handle_t*>(
+                    result.inputBuffer.releaseFence.getNativeHandle());
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+        for (auto& buf : result.outputBuffers) {
+            if (buf.releaseFence.getNativeHandle() != nullptr) {
+                native_handle_t* handle = const_cast<native_handle_t*>(
+                        buf.releaseFence.getNativeHandle());
+                native_handle_close(handle);
+                native_handle_delete(handle);
+            }
+        }
+    }
+    return;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define UPDATE(md, tag, data, size)               \
+do {                                              \
+    if ((md).update((tag), (data), (size))) {     \
+        ALOGE("Update " #tag " failed!");         \
+        return BAD_VALUE;                         \
+    }                                             \
+} while (0)
+
+status_t fillCaptureResultCommon(
+        common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp,
+        camera_metadata_ro_entry& activeArraySize) {
+    if (activeArraySize.count < 4) {
+        ALOGE("%s: cannot find active array size!", __FUNCTION__);
+        return -EINVAL;
+    }
+    // android.control
+    // For USB camera, we don't know the AE state. Set the state to converged to
+    // indicate the frame should be good to use. Then apps don't have to wait the
+    // AE state.
+    const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
+    UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
+
+    const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+    UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
+
+    // Set AWB state to converged to indicate the frame should be good to use.
+    const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
+    UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+
+    const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+    UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
+
+    const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+    UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
+    // This means pipeline latency of X frame intervals. The maximum number is 4.
+    const uint8_t requestPipelineMaxDepth = 4;
+    UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
+
+    // android.scaler
+    const int32_t crop_region[] = {
+          activeArraySize.data.i32[0], activeArraySize.data.i32[1],
+          activeArraySize.data.i32[2], activeArraySize.data.i32[3],
+    };
+    UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
+
+    // android.sensor
+    UPDATE(md, ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
+
+    // android.statistics
+    const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+    UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
+
+    const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
+    UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
+
+    return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
 }  // namespace implementation
 }  // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+AllocatedV4L2Frame::AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn) :
+        Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) {
+    uint8_t* dataIn;
+    size_t dataSize;
+    if (frameIn->getData(&dataIn, &dataSize) != 0) {
+        ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__);
+        return;
+    }
+
+    mData.resize(dataSize);
+    std::memcpy(mData.data(), dataIn, dataSize);
+}
+
+int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+    if (outData == nullptr || dataSize == nullptr) {
+        ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize);
+        return -1;
+    }
+
+    *outData = mData.data();
+    *dataSize = mData.size();
+    return 0;
+}
+
+AllocatedV4L2Frame::~AllocatedV4L2Frame() {}
+
+}  // namespace implementation
+}  // namespace V3_6
 }  // namespace device
 
 
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index 71b7c17..180f0c1 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
@@ -84,7 +84,8 @@
 using ::android::Mutex;
 using ::android::base::unique_fd;
 
-struct ExternalCameraDeviceSession : public virtual RefBase {
+struct ExternalCameraDeviceSession : public virtual RefBase,
+        public virtual OutputThreadInterface {
 
     ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
             const ExternalCameraConfig& cfg,
@@ -110,6 +111,82 @@
     static const int kMaxStallStream = 1;
     static const uint32_t kMaxBytesPerPixel = 2;
 
+    class OutputThread : public android::Thread {
+    public:
+        OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+                const common::V1_0::helper::CameraMetadata&);
+        virtual ~OutputThread();
+
+        Status allocateIntermediateBuffers(
+                const Size& v4lSize, const Size& thumbSize,
+                const hidl_vec<Stream>& streams,
+                uint32_t blobBufferSize);
+        Status submitRequest(const std::shared_ptr<HalRequest>&);
+        void flush();
+        void dump(int fd);
+        virtual bool threadLoop() override;
+
+        void setExifMakeModel(const std::string& make, const std::string& model);
+
+        // The remaining request list is returned for offline processing
+        std::list<std::shared_ptr<HalRequest>> switchToOffline();
+
+    protected:
+        // Methods to request output buffer in parallel
+        // No-op for device@3.4. Implemented in device@3.5
+        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
+        virtual int waitForBufferRequestDone(
+                /*out*/std::vector<HalStreamBuffer>*) { return 0; }
+
+        static const int kFlushWaitTimeoutSec = 3; // 3 sec
+        static const int kReqWaitTimeoutMs = 33;   // 33ms
+        static const int kReqWaitTimesMax = 90;    // 33ms * 90 ~= 3 sec
+
+        void waitForNextRequest(std::shared_ptr<HalRequest>* out);
+        void signalRequestDone();
+
+        int cropAndScaleLocked(
+                sp<AllocatedFrame>& in, const Size& outSize,
+                YCbCrLayout* out);
+
+        int cropAndScaleThumbLocked(
+                sp<AllocatedFrame>& in, const Size& outSize,
+                YCbCrLayout* out);
+
+        int createJpegLocked(HalStreamBuffer &halBuf,
+                const common::V1_0::helper::CameraMetadata& settings);
+
+        void clearIntermediateBuffers();
+
+        const wp<OutputThreadInterface> mParent;
+        const CroppingType mCroppingType;
+        const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+        mutable std::mutex mRequestListLock;      // Protect acccess to mRequestList,
+                                                  // mProcessingRequest and mProcessingFrameNumer
+        std::condition_variable mRequestCond;     // signaled when a new request is submitted
+        std::condition_variable mRequestDoneCond; // signaled when a request is done processing
+        std::list<std::shared_ptr<HalRequest>> mRequestList;
+        bool mProcessingRequest = false;
+        uint32_t mProcessingFrameNumer = 0;
+
+        // V4L2 frameIn
+        // (MJPG decode)-> mYu12Frame
+        // (Scale)-> mScaledYu12Frames
+        // (Format convert) -> output gralloc frames
+        mutable std::mutex mBufferLock; // Protect access to intermediate buffers
+        sp<AllocatedFrame> mYu12Frame;
+        sp<AllocatedFrame> mYu12ThumbFrame;
+        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
+        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
+        YCbCrLayout mYu12FrameLayout;
+        YCbCrLayout mYu12ThumbFrameLayout;
+        uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
+
+        std::string mExifMake;
+        std::string mExifModel;
+    };
+
 protected:
 
     // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow
@@ -150,27 +227,22 @@
             ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb);
 
 protected:
-    struct HalStreamBuffer {
-        int32_t streamId;
-        uint64_t bufferId;
-        uint32_t width;
-        uint32_t height;
-        PixelFormat format;
-        V3_2::BufferUsageFlags usage;
-        buffer_handle_t* bufPtr;
-        int acquireFence;
-        bool fenceTimeout;
-    };
+    // Methods from OutputThreadInterface
+    virtual Status importBuffer(int32_t streamId,
+            uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr,
+            bool allowEmptyBuf) override;
 
-    struct HalRequest {
-        uint32_t frameNumber;
-        common::V1_0::helper::CameraMetadata setting;
-        sp<V4L2Frame> frameIn;
-        nsecs_t shutterTs;
-        std::vector<HalStreamBuffer> buffers;
-    };
+    virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
 
-    static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+    virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+        /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+        /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+    virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+    // End of OutputThreadInterface methods
 
     Status constructDefaultRequestSettingsRaw(RequestTemplate type,
             V3_2::CameraMetadata *outMetadata);
@@ -219,11 +291,6 @@
             // Optional argument for ICameraDeviceSession@3.5 impl
             bool allowEmptyBuf = false);
 
-    Status importBuffer(int32_t streamId,
-            uint64_t bufId, buffer_handle_t buf,
-            /*out*/buffer_handle_t** outBufPtr,
-            bool allowEmptyBuf);
-
     Status importBufferLocked(int32_t streamId,
             uint64_t bufId, buffer_handle_t buf,
             /*out*/buffer_handle_t** outBufPtr,
@@ -236,106 +303,15 @@
 
     Status processOneCaptureRequest(const CaptureRequest& request);
 
-    Status processCaptureResult(std::shared_ptr<HalRequest>&);
-    Status processCaptureRequestError(const std::shared_ptr<HalRequest>&);
     void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs);
-    void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec);
     void invokeProcessCaptureResultCallback(
             hidl_vec<CaptureResult> &results, bool tryWriteFmq);
-    static void freeReleaseFences(hidl_vec<CaptureResult>&);
 
     Size getMaxJpegResolution() const;
     Size getMaxThumbResolution() const;
 
-    ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
-
     int waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk);
 
-    class OutputThread : public android::Thread {
-    public:
-        OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
-        virtual ~OutputThread();
-
-        Status allocateIntermediateBuffers(
-                const Size& v4lSize, const Size& thumbSize,
-                const hidl_vec<Stream>& streams,
-                uint32_t blobBufferSize);
-        Status submitRequest(const std::shared_ptr<HalRequest>&);
-        void flush();
-        void dump(int fd);
-        virtual bool threadLoop() override;
-
-        void setExifMakeModel(const std::string& make, const std::string& model);
-
-    protected:
-        // Methods to request output buffer in parallel
-        // No-op for device@3.4. Implemented in device@3.5
-        virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
-        virtual int waitForBufferRequestDone(
-                /*out*/std::vector<HalStreamBuffer>*) { return 0; }
-
-        static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
-                static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
-                static_cast<uint32_t>('X') << 24;
-        // returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
-        static uint32_t getFourCcFromLayout(const YCbCrLayout&);
-        static int getCropRect(
-                CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
-
-        static const int kFlushWaitTimeoutSec = 3; // 3 sec
-        static const int kReqWaitTimeoutMs = 33;   // 33ms
-        static const int kReqWaitTimesMax = 90;    // 33ms * 90 ~= 3 sec
-
-        void waitForNextRequest(std::shared_ptr<HalRequest>* out);
-        void signalRequestDone();
-
-        int cropAndScaleLocked(
-                sp<AllocatedFrame>& in, const Size& outSize,
-                YCbCrLayout* out);
-
-        int cropAndScaleThumbLocked(
-                sp<AllocatedFrame>& in, const Size& outSize,
-                YCbCrLayout* out);
-
-        int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out,
-                Size sz, uint32_t format);
-
-        static int encodeJpegYU12(const Size &inSz,
-                const YCbCrLayout& inLayout, int jpegQuality,
-                const void *app1Buffer, size_t app1Size,
-                void *out, size_t maxOutSize,
-                size_t &actualCodeSize);
-
-        int createJpegLocked(HalStreamBuffer &halBuf, const std::shared_ptr<HalRequest>& req);
-
-        const wp<ExternalCameraDeviceSession> mParent;
-        const CroppingType mCroppingType;
-
-        mutable std::mutex mRequestListLock;      // Protect acccess to mRequestList,
-                                                  // mProcessingRequest and mProcessingFrameNumer
-        std::condition_variable mRequestCond;     // signaled when a new request is submitted
-        std::condition_variable mRequestDoneCond; // signaled when a request is done processing
-        std::list<std::shared_ptr<HalRequest>> mRequestList;
-        bool mProcessingRequest = false;
-        uint32_t mProcessingFrameNumer = 0;
-
-        // V4L2 frameIn
-        // (MJPG decode)-> mYu12Frame
-        // (Scale)-> mScaledYu12Frames
-        // (Format convert) -> output gralloc frames
-        mutable std::mutex mBufferLock; // Protect access to intermediate buffers
-        sp<AllocatedFrame> mYu12Frame;
-        sp<AllocatedFrame> mYu12ThumbFrame;
-        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
-        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
-        YCbCrLayout mYu12FrameLayout;
-        YCbCrLayout mYu12ThumbFrameLayout;
-        uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
-
-        std::string mExifMake;
-        std::string mExifModel;
-    };
-
     // Protect (most of) HIDL interface methods from synchronized-entering
     mutable Mutex mInterfaceLock;
 
@@ -345,7 +321,7 @@
     const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
     const std::vector<SupportedV4L2Format> mSupportedFormats;
     const CroppingType mCroppingType;
-    const std::string& mCameraId;
+    const std::string mCameraId;
 
     // Not protected by mLock, this is almost a const.
     // Setup in constructor, reset in close() after OutputThread is joined
@@ -381,12 +357,6 @@
     std::mutex mInflightFramesLock; // protect mInflightFrames
     std::unordered_set<uint32_t>  mInflightFrames;
 
-    // buffers currently circulating between HAL and camera service
-    // key: bufferId sent via HIDL interface
-    // value: imported buffer_handle_t
-    // Buffer will be imported during processCaptureRequest and will be freed
-    // when the its stream is deleted or camera device session is closed
-    typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
     // Stream ID -> circulating buffers map
     std::map<int, CirculatingBuffers> mCirculatingBuffers;
     // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
@@ -395,6 +365,8 @@
     std::mutex mAfTriggerLock; // protect mAfTrigger
     bool mAfTrigger = false;
 
+    uint32_t mBlobBufferSize = 0;
+
     static HandleImporter sHandleImporter;
 
     /* Beginning of members not changed after initialize() */
@@ -410,6 +382,9 @@
 
     const Size mMaxThumbResolution;
     const Size mMaxJpegResolution;
+
+    std::string mExifMake;
+    std::string mExifModel;
     /* End of members not changed after initialize() */
 
 private:
@@ -484,4 +459,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index bd79807..1958fcb 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -105,7 +105,7 @@
     // Calls into virtual member function. Do not use it in constructor
     status_t initCameraCharacteristics();
     // Init available capabilities keys
-    status_t initAvailableCapabilities(
+    virtual status_t initAvailableCapabilities(
             ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
     // Init non-device dependent keys
     virtual status_t initDefaultCharsKeys(
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 341c622..74f75eb 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -17,16 +17,27 @@
 #ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
 #define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
 
+#include <android/hardware/camera/common/1.0/types.h>
+#include <android/hardware/camera/device/3.2/types.h>
+#include <android/hardware/graphics/common/1.0/types.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <inttypes.h>
 #include <mutex>
+#include <unordered_map>
 #include <unordered_set>
 #include <vector>
 #include "tinyxml2.h"  // XML parsing
 #include "utils/LightRefBase.h"
+#include "utils/Timers.h"
+#include <CameraMetadata.h>
+#include <HandleImporter.h>
 
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
 
 namespace android {
 namespace hardware {
@@ -113,16 +124,28 @@
     std::vector<FrameRate> frameRates;
 };
 
+// A Base class with basic information about a frame
+struct Frame : public VirtualLightRefBase {
+public:
+    Frame(uint32_t width, uint32_t height, uint32_t fourcc);
+    const uint32_t mWidth;
+    const uint32_t mHeight;
+    const uint32_t mFourcc;
+
+    // getData might involve map/allocation
+    virtual int getData(uint8_t** outData, size_t* dataSize) = 0;
+};
+
 // A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
 // Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
-class V4L2Frame : public virtual VirtualLightRefBase {
+class V4L2Frame : public Frame {
 public:
     V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd,
               uint32_t dataSize, uint64_t offset);
     ~V4L2Frame() override;
-    const uint32_t mWidth;
-    const uint32_t mHeight;
-    const uint32_t mFourcc;
+
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
     const int mBufferIndex; // for later enqueue
     int map(uint8_t** data, size_t* dataSize);
     int unmap();
@@ -137,13 +160,13 @@
 
 // A RAII class representing a CPU allocated YUV frame used as intermeidate buffers
 // when generating output images.
-class AllocatedFrame : public virtual VirtualLightRefBase {
+class AllocatedFrame : public Frame {
 public:
-    AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size?
+    AllocatedFrame(uint32_t w, uint32_t h); // only support V4L2_PIX_FMT_YUV420 for now
     ~AllocatedFrame() override;
-    const uint32_t mWidth;
-    const uint32_t mHeight;
-    const uint32_t mFourcc; // Only support YU12 format for now
+
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
     int allocate(YCbCrLayout* out = nullptr);
     int getLayout(YCbCrLayout* out);
     int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
@@ -165,8 +188,110 @@
 
 bool isAspectRatioClose(float ar1, float ar2);
 
+struct HalStreamBuffer {
+    int32_t streamId;
+    uint64_t bufferId;
+    uint32_t width;
+    uint32_t height;
+    ::android::hardware::graphics::common::V1_0::PixelFormat format;
+    ::android::hardware::camera::device::V3_2::BufferUsageFlags usage;
+    buffer_handle_t* bufPtr;
+    int acquireFence;
+    bool fenceTimeout;
+};
+
+struct HalRequest {
+    uint32_t frameNumber;
+    common::V1_0::helper::CameraMetadata setting;
+    sp<Frame> frameIn;
+    nsecs_t shutterTs;
+    std::vector<HalStreamBuffer> buffers;
+};
+
+static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
+// buffers currently circulating between HAL and camera service
+// key: bufferId sent via HIDL interface
+// value: imported buffer_handle_t
+// Buffer will be imported during processCaptureRequest (or requestStreamBuffer
+// in the case of HAL buffer manager is enabled) and will be freed
+// when the stream is deleted or camera device session is closed
+typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
+
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+        /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*inout*/HandleImporter& handleImporter,
+        int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf);
+
+static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
+        static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
+        static_cast<uint32_t>('X') << 24;
+
+// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
+uint32_t getFourCcFromLayout(const YCbCrLayout&);
+
+using ::android::hardware::camera::external::common::Size;
+int getCropRect(CroppingType ct, const Size& inSize,
+        const Size& outSize, IMapper::Rect* out);
+
+int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format);
+
+int encodeJpegYU12(const Size &inSz,
+        const YCbCrLayout& inLayout, int jpegQuality,
+        const void *app1Buffer, size_t app1Size,
+        void *out, size_t maxOutSize,
+        size_t &actualCodeSize);
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&);
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>&);
+
+status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp,
+        camera_metadata_ro_entry& activeArraySize);
+
+// Interface for OutputThread calling back to parent
+struct OutputThreadInterface : public virtual RefBase {
+    virtual ::android::hardware::camera::common::V1_0::Status importBuffer(
+            int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) = 0;
+
+    virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) = 0;
+
+    // Callbacks are fired within the method if msgs/results are nullptr.
+    // Otherwise the callbacks will be returned and caller is responsible to
+    // fire the callback later
+    virtual ::android::hardware::camera::common::V1_0::Status processCaptureRequestError(
+            const std::shared_ptr<HalRequest>&,
+            /*out*/std::vector<V3_2::NotifyMsg>* msgs = nullptr,
+            /*out*/std::vector<V3_2::CaptureResult>* results = nullptr) = 0;
+
+    virtual ::android::hardware::camera::common::V1_0::Status processCaptureResult(
+            std::shared_ptr<HalRequest>&) = 0;
+
+    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0;
+};
+
 }  // namespace implementation
 }  // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame.
+class AllocatedV4L2Frame : public V3_4::implementation::Frame {
+public:
+    AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn);
+    ~AllocatedV4L2Frame() override;
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+private:
+    std::vector<uint8_t> mData;
+};
+
+} // namespace implementation
+} // namespace V3_6
 }  // namespace device
 }  // namespace camera
 }  // namespace hardware
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
index 43362fd..1c307ee 100644
--- a/camera/device/3.5/default/Android.bp
+++ b/camera/device/3.5/default/Android.bp
@@ -49,6 +49,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",
         "liblog",
         "libhardware",
         "libcamera_metadata",
@@ -81,7 +82,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@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "liblog",
         "libhardware",
         "libcamera_metadata",
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..19adb34
--- /dev/null
+++ b/camera/device/3.6/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.device@3.6",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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..a2ddebd
--- /dev/null
+++ b/camera/device/3.6/default/Android.bp
@@ -0,0 +1,67 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+    name: "camera.device@3.6-external-impl_headers",
+    vendor: true,
+    export_include_dirs: ["include/ext_device_v3_6_impl"]
+}
+
+cc_library_shared {
+    name: "camera.device@3.6-external-impl",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    vendor: true,
+    srcs: [
+        "ExternalCameraDevice.cpp",
+        "ExternalCameraDeviceSession.cpp",
+        "ExternalCameraOfflineSession.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libutils",
+        "libcutils",
+        "camera.device@3.2-impl",
+        "camera.device@3.3-impl",
+        "camera.device@3.4-external-impl",
+        "camera.device@3.5-external-impl",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.device@3.5",
+        "android.hardware.camera.device@3.6",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "liblog",
+        "libhardware",
+        "libcamera_metadata",
+        "libfmq",
+        "libsync",
+        "libyuv",
+        "libjpeg",
+        "libexif",
+        "libtinyxml2"
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    local_include_dirs: ["include/ext_device_v3_6_impl"],
+    export_shared_lib_headers: [
+        "libfmq",
+    ],
+}
diff --git a/camera/device/3.6/default/ExternalCameraDevice.cpp b/camera/device/3.6/default/ExternalCameraDevice.cpp
new file mode 100644
index 0000000..244c7dd
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDevice.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ExtCamDev@3.6"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include "ExternalCameraDevice_3_6.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDevice::ExternalCameraDevice(
+        const std::string& cameraId, const ExternalCameraConfig& cfg) :
+        V3_5::implementation::ExternalCameraDevice(cameraId, cfg) {}
+
+ExternalCameraDevice::~ExternalCameraDevice() {}
+
+sp<V3_4::implementation::ExternalCameraDeviceSession> ExternalCameraDevice::createSession(
+        const sp<V3_2::ICameraDeviceCallback>& cb,
+        const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats,
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        unique_fd v4l2Fd) {
+    return new ExternalCameraDeviceSession(
+            cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd));
+}
+
+#define UPDATE(tag, data, size)                    \
+do {                                               \
+  if (metadata->update((tag), (data), (size))) {   \
+    ALOGE("Update " #tag " failed!");              \
+    return -EINVAL;                                \
+  }                                                \
+} while (0)
+
+status_t ExternalCameraDevice::initAvailableCapabilities(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    status_t res =
+            V3_4::implementation::ExternalCameraDevice::initAvailableCapabilities(metadata);
+
+    if (res != OK) {
+        return res;
+    }
+
+    camera_metadata_entry caps = metadata->find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    std::vector<uint8_t> availableCapabilities;
+
+    for (size_t i = 0; i < caps.count; i++) {
+        uint8_t capability = caps.data.u8[i];
+        availableCapabilities.push_back(capability);
+    }
+
+    // Add OFFLINE_PROCESSING capability to device 3.6
+    availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING);
+
+    UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+           availableCapabilities.data(),
+           availableCapabilities.size());
+
+    return OK;
+}
+
+#undef UPDATE
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
new file mode 100644
index 0000000..60a1a10
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ExtCamDevSsn@3.6"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+ExternalCameraDeviceSession::ExternalCameraDeviceSession(
+        const sp<V3_2::ICameraDeviceCallback>& callback,
+        const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats,
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        unique_fd v4l2Fd) :
+        V3_5::implementation::ExternalCameraDeviceSession(
+                callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) {
+}
+
+ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {}
+
+
+Return<void> ExternalCameraDeviceSession::configureStreams_3_6(
+        const StreamConfiguration& requestedConfiguration,
+        ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb)  {
+    V3_2::StreamConfiguration config_v32;
+    V3_3::HalStreamConfiguration outStreams_v33;
+    V3_6::HalStreamConfiguration outStreams;
+    const V3_4::StreamConfiguration& requestedConfiguration_3_4 = requestedConfiguration.v3_4;
+    Mutex::Autolock _il(mInterfaceLock);
+
+    config_v32.operationMode = requestedConfiguration_3_4.operationMode;
+    config_v32.streams.resize(requestedConfiguration_3_4.streams.size());
+    uint32_t blobBufferSize = 0;
+    int numStallStream = 0;
+    for (size_t i = 0; i < config_v32.streams.size(); i++) {
+        config_v32.streams[i] = requestedConfiguration_3_4.streams[i].v3_2;
+        if (config_v32.streams[i].format == PixelFormat::BLOB) {
+            blobBufferSize = requestedConfiguration_3_4.streams[i].bufferSize;
+            numStallStream++;
+        }
+    }
+
+    // Fail early if there are multiple BLOB streams
+    if (numStallStream > kMaxStallStream) {
+        ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__,
+                kMaxStallStream, numStallStream);
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, outStreams);
+        return Void();
+    }
+
+    Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize);
+
+    fillOutputStream3_6(outStreams_v33, &outStreams);
+
+    _hidl_cb(status, outStreams);
+    return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::switchToOffline(
+        const hidl_vec<int32_t>& streamsToKeep,
+        ICameraDeviceSession::switchToOffline_cb _hidl_cb) {
+    std::vector<NotifyMsg> msgs;
+    std::vector<CaptureResult> results;
+    CameraOfflineSessionInfo info;
+    sp<ICameraOfflineSession> session;
+
+    Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session);
+
+    mCallback->notify(msgs);
+    hidl_vec<CaptureResult> hidlResults(std::move(results));
+    invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true);
+    V3_4::implementation::freeReleaseFences(hidlResults);
+
+    _hidl_cb(st, info, session);
+    return Void();
+}
+
+void ExternalCameraDeviceSession::fillOutputStream3_6(
+        const V3_3::HalStreamConfiguration& outStreams_v33,
+        /*out*/V3_6::HalStreamConfiguration* outStreams_v36) {
+    if (outStreams_v36 == nullptr) {
+        ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__);
+        return;
+    }
+    Mutex::Autolock _l(mLock);
+    outStreams_v36->streams.resize(outStreams_v33.streams.size());
+    for (size_t i = 0; i < outStreams_v36->streams.size(); i++) {
+        outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i];
+        outStreams_v36->streams[i].supportOffline =
+                supportOfflineLocked(outStreams_v33.streams[i].v3_2.id);
+    }
+}
+
+bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) {
+    const Stream& stream = mStreamMap[streamId];
+    if (stream.format == PixelFormat::BLOB &&
+            stream.dataSpace == static_cast<int32_t>(Dataspace::V0_JFIF)) {
+        return true;
+    }
+    // TODO: support YUV output stream?
+    return false;
+}
+
+bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+        std::shared_ptr<V3_4::implementation::HalRequest> halReq) {
+    for (const auto& buffer : halReq->buffers) {
+        for (auto offlineStreamId : offlineStreams) {
+            if (buffer.streamId == offlineStreamId) {
+                return false;
+            }
+        }
+    }
+    // Only drop a request completely if it has no offline output
+    return true;
+}
+
+void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+        std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+        const std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*out*/CameraOfflineSessionInfo* info) {
+    if (info == nullptr) {
+        ALOGE("%s: output info must not be null!", __FUNCTION__);
+        return;
+    }
+
+    info->offlineStreams.resize(offlineStreams.size());
+    info->offlineRequests.resize(offlineReqs.size());
+
+    // Fill in offline reqs and count outstanding buffers
+    for (size_t i = 0; i < offlineReqs.size(); i++) {
+        info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
+        info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
+        for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
+            int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
+            info->offlineRequests[i].pendingStreams[bIdx] = streamId;
+        }
+    }
+
+    for (size_t i = 0; i < offlineStreams.size(); i++) {
+        int32_t streamId = offlineStreams[i];
+        info->offlineStreams[i].id = streamId;
+        // outstanding buffers are 0 since we are doing hal buffer management and
+        // offline session will ask for those buffers later
+        info->offlineStreams[i].numOutstandingBuffers = 0;
+        const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
+        info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
+        size_t bIdx = 0;
+        for (const auto& pair : bufIdMap) {
+            // Fill in bufferId
+            info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
+        }
+
+    }
+}
+
+Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+        /*out*/std::vector<NotifyMsg>* msgs,
+        /*out*/std::vector<CaptureResult>* results,
+        /*out*/CameraOfflineSessionInfo* info,
+        /*out*/sp<ICameraOfflineSession>* session) {
+    ATRACE_CALL();
+    if (offlineStreams.size() > 1) {
+        ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
+        ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__,
+                msgs, results, info, session);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    msgs->clear();
+    results->clear();
+
+    Mutex::Autolock _il(mInterfaceLock);
+    Status status = initStatus();
+    if (status != Status::OK) {
+        return status;
+    }
+
+    Mutex::Autolock _l(mLock);
+    for (auto streamId : offlineStreams) {
+        if (!supportOfflineLocked(streamId)) {
+            return Status::ILLEGAL_ARGUMENT;
+        }
+    }
+
+    // pause output thread and get all remaining inflight requests
+    auto remainingReqs = mOutputThread->switchToOffline();
+    std::vector<std::shared_ptr<V3_4::implementation::HalRequest>> halReqs;
+
+    // Send out buffer/request error for remaining requests and filter requests
+    // to be handled in offline mode
+    for (auto& halReq : remainingReqs) {
+        bool dropReq = canDropRequest(offlineStreams, halReq);
+        if (dropReq) {
+            // Request is dropped completely. Just send request error and
+            // there is no need to send the request to offline session
+            processCaptureRequestError(halReq, msgs, results);
+            continue;
+        }
+
+        // All requests reach here must have at least one offline stream output
+        NotifyMsg shutter;
+        shutter.type = MsgType::SHUTTER;
+        shutter.msg.shutter.frameNumber = halReq->frameNumber;
+        shutter.msg.shutter.timestamp = halReq->shutterTs;
+        msgs->push_back(shutter);
+
+        std::vector<V3_4::implementation::HalStreamBuffer> offlineBuffers;
+        for (const auto& buffer : halReq->buffers) {
+            bool dropBuffer = true;
+            for (auto offlineStreamId : offlineStreams) {
+                if (buffer.streamId == offlineStreamId) {
+                    dropBuffer = false;
+                    break;
+                }
+            }
+            if (dropBuffer) {
+                NotifyMsg error;
+                error.type = MsgType::ERROR;
+                error.msg.error.frameNumber = halReq->frameNumber;
+                error.msg.error.errorStreamId = buffer.streamId;
+                error.msg.error.errorCode = ErrorCode::ERROR_BUFFER;
+                msgs->push_back(error);
+
+                CaptureResult result;
+                result.frameNumber = halReq->frameNumber;
+                result.partialResult = 0; // buffer only result
+                result.inputBuffer.streamId = -1;
+                result.outputBuffers.resize(1);
+                result.outputBuffers[0].streamId = buffer.streamId;
+                result.outputBuffers[0].bufferId = buffer.bufferId;
+                result.outputBuffers[0].status = BufferStatus::ERROR;
+                if (buffer.acquireFence >= 0) {
+                    native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                    handle->data[0] = buffer.acquireFence;
+                    result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false);
+                }
+                results->push_back(result);
+            } else {
+                offlineBuffers.push_back(buffer);
+            }
+        }
+        halReq->buffers = offlineBuffers;
+        halReqs.push_back(halReq);
+    }
+
+    // convert hal requests to offline request
+    std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+    for (auto& v4lReq : halReqs) {
+        std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
+        halReq->frameNumber = v4lReq->frameNumber;
+        halReq->setting = v4lReq->setting;
+        halReq->shutterTs = v4lReq->shutterTs;
+        halReq->buffers = v4lReq->buffers;
+        sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+                static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
+        halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame);
+        offlineReqs.push_back(halReq);
+        // enqueue V4L2 frame
+        enqueueV4l2Frame(v4l2Frame);
+    }
+
+    // Collect buffer caches/streams
+    hidl_vec<Stream> streamInfos;
+    streamInfos.resize(offlineStreams.size());
+    std::map<int, CirculatingBuffers> circulatingBuffers;
+    {
+        Mutex::Autolock _l(mCbsLock);
+        size_t idx = 0;
+        for(auto streamId : offlineStreams) {
+            circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
+            mCirculatingBuffers.erase(streamId);
+            streamInfos[idx++] = mStreamMap.at(streamId);
+            mStreamMap.erase(streamId);
+        }
+    }
+
+    fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
+
+    // create the offline session object
+    bool afTrigger;
+    {
+        std::lock_guard<std::mutex> lk(mAfTriggerLock);
+        afTrigger = mAfTrigger;
+    }
+    sp<ExternalCameraOfflineSession> sessionImpl = new ExternalCameraOfflineSession(
+            mCroppingType, mCameraCharacteristics, mCameraId,
+            mExifMake, mExifModel, mBlobBufferSize, afTrigger,
+            streamInfos, offlineReqs, circulatingBuffers);
+
+    bool initFailed = sessionImpl->initialize();
+    if (initFailed) {
+        ALOGE("%s: offline session initialize failed!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    // cleanup stream and buffer caches
+    {
+        Mutex::Autolock _l(mCbsLock);
+        for(auto pair : mStreamMap) {
+            cleanupBuffersLocked(/*Stream ID*/pair.first);
+        }
+        mCirculatingBuffers.clear();
+    }
+    mStreamMap.clear();
+
+    // update inflight records
+    {
+        std::lock_guard<std::mutex> lk(mInflightFramesLock);
+        mInflightFrames.clear();
+    }
+
+    // stop v4l2 streaming
+    if (v4l2StreamOffLocked() !=0) {
+        ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    // No need to return session if there is no offline requests left
+    if (offlineReqs.size() != 0) {
+        *session = sessionImpl->getInterface();
+    } else {
+        *session = nullptr;
+    }
+    return Status::OK;
+}
+
+} // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
new file mode 100644
index 0000000..e606fda
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ExtCamOfflnSsn@3.6"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+#include <android/log.h>
+
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace {
+
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+} // anonymous namespace
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+// static instance
+HandleImporter ExternalCameraOfflineSession::sHandleImporter;
+
+using V3_5::implementation::ExternalCameraDeviceSession;
+
+ExternalCameraOfflineSession::ExternalCameraOfflineSession(
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId,
+        const std::string& exifMake,
+        const std::string& exifModel,
+        const uint32_t blobBufferSize,
+        const bool afTrigger,
+        const hidl_vec<Stream>& offlineStreams,
+        std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+        const std::map<int, CirculatingBuffers>& circulatingBuffers) :
+        mCroppingType(croppingType), mChars(chars), mCameraId(cameraId),
+        mExifMake(exifMake), mExifModel(exifModel), mBlobBufferSize(blobBufferSize),
+        mAfTrigger(afTrigger), mOfflineStreams(offlineStreams), mOfflineReqs(offlineReqs),
+        mCirculatingBuffers(circulatingBuffers) {}
+
+ExternalCameraOfflineSession::~ExternalCameraOfflineSession() {
+    close();
+}
+
+bool ExternalCameraOfflineSession::initialize() {
+    mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
+            kMetadataMsgQueueSize, false /* non blocking */);
+    if (!mResultMetadataQueue->isValid()) {
+        ALOGE("%s: invalid result fmq", __FUNCTION__);
+        return true;
+    }
+    return false;
+}
+
+void ExternalCameraOfflineSession::initOutputThread() {
+    if (mOutputThread != nullptr) {
+        ALOGE("%s: OutputThread already exist!", __FUNCTION__);
+        return;
+    }
+
+    mBufferRequestThread = new ExternalCameraDeviceSession::BufferRequestThread(
+            this, mCallback);
+    mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
+
+    mOutputThread = new OutputThread(this, mCroppingType, mChars,
+            mBufferRequestThread, mOfflineReqs);
+
+    mOutputThread->setExifMakeModel(mExifMake, mExifModel);
+
+    Size inputSize = { mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight};
+    Size maxThumbSize = V3_4::implementation::getMaxThumbnailResolution(mChars);
+    mOutputThread->allocateIntermediateBuffers(
+            inputSize, maxThumbSize, mOfflineStreams, mBlobBufferSize);
+
+    mOutputThread->run("ExtCamOfflnOut", PRIORITY_DISPLAY);
+}
+
+bool ExternalCameraOfflineSession::OutputThread::threadLoop() {
+    auto parent = mParent.promote();
+    if (parent == nullptr) {
+       ALOGE("%s: session has been disconnected!", __FUNCTION__);
+       return false;
+    }
+
+    if (mOfflineReqs.empty()) {
+        ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__);
+        return false;
+    }
+
+    std::shared_ptr<HalRequest> req = mOfflineReqs.front();
+    mOfflineReqs.pop_front();
+
+    auto onDeviceError = [&](auto... args) {
+        ALOGE(args...);
+        parent->notifyError(
+                req->frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+        signalRequestDone();
+        return false;
+    };
+
+    if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
+        return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+                req->frameIn->mFourcc & 0xFF,
+                (req->frameIn->mFourcc >> 8) & 0xFF,
+                (req->frameIn->mFourcc >> 16) & 0xFF,
+                (req->frameIn->mFourcc >> 24) & 0xFF);
+    }
+
+    int res = requestBufferStart(req->buffers);
+    if (res != 0) {
+        ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+        return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+    }
+
+    std::unique_lock<std::mutex> lk(mBufferLock);
+    // Convert input V4L2 frame to YU12 of the same size
+    // TODO: see if we can save some computation by converting to YV12 here
+    uint8_t* inData;
+    size_t inDataSize;
+    if (req->frameIn->getData(&inData, &inDataSize) != 0) {
+        lk.unlock();
+        return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+    }
+
+    // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+    if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+        ATRACE_BEGIN("MJPGtoI420");
+        int res = libyuv::MJPGToI420(
+            inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y), mYu12FrameLayout.yStride,
+            static_cast<uint8_t*>(mYu12FrameLayout.cb), mYu12FrameLayout.cStride,
+            static_cast<uint8_t*>(mYu12FrameLayout.cr), mYu12FrameLayout.cStride,
+            mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth, mYu12Frame->mHeight);
+        ATRACE_END();
+
+        if (res != 0) {
+            // For some webcam, the first few V4L2 frames might be malformed...
+            ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
+            lk.unlock();
+            Status st = parent->processCaptureRequestError(req);
+            if (st != Status::OK) {
+                return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+            }
+            signalRequestDone();
+            return true;
+        }
+    }
+
+    ATRACE_BEGIN("Wait for BufferRequest done");
+    res = waitForBufferRequestDone(&req->buffers);
+    ATRACE_END();
+
+    if (res != 0) {
+        ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+        lk.unlock();
+        return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+    }
+
+    ALOGV("%s processing new request", __FUNCTION__);
+    const int kSyncWaitTimeoutMs = 500;
+    for (auto& halBuf : req->buffers) {
+        if (*(halBuf.bufPtr) == nullptr) {
+            ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+            halBuf.fenceTimeout = true;
+        } else if (halBuf.acquireFence >= 0) {
+            int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+            if (ret) {
+                halBuf.fenceTimeout = true;
+            } else {
+                ::close(halBuf.acquireFence);
+                halBuf.acquireFence = -1;
+            }
+        }
+
+        if (halBuf.fenceTimeout) {
+            continue;
+        }
+
+        // Gralloc lockYCbCr the buffer
+        switch (halBuf.format) {
+            case PixelFormat::BLOB: {
+                int ret = createJpegLocked(halBuf, req->setting);
+
+                if(ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: createJpegLocked failed with %d",
+                          __FUNCTION__, ret);
+                }
+            } break;
+            case PixelFormat::Y16: {
+                void* outLayout = sHandleImporter.lock(*(halBuf.bufPtr), halBuf.usage, inDataSize);
+
+                std::memcpy(outLayout, inData, inDataSize);
+
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            case PixelFormat::YCBCR_420_888:
+            case PixelFormat::YV12: {
+                IMapper::Rect outRect {0, 0,
+                        static_cast<int32_t>(halBuf.width),
+                        static_cast<int32_t>(halBuf.height)};
+                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+                        *(halBuf.bufPtr), halBuf.usage, outRect);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                        __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
+                        outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
+
+                // Convert to output buffer size/format
+                uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout);
+                ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__,
+                        outputFourcc & 0xFF,
+                        (outputFourcc >> 8) & 0xFF,
+                        (outputFourcc >> 16) & 0xFF,
+                        (outputFourcc >> 24) & 0xFF);
+
+                YCbCrLayout cropAndScaled;
+                ATRACE_BEGIN("cropAndScaleLocked");
+                int ret = cropAndScaleLocked(
+                        mYu12Frame,
+                        Size { halBuf.width, halBuf.height },
+                        &cropAndScaled);
+                ATRACE_END();
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
+                }
+
+                Size sz {halBuf.width, halBuf.height};
+                ATRACE_BEGIN("formatConvert");
+                ret = V3_4::implementation::formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
+                ATRACE_END();
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: format coversion failed!", __FUNCTION__);
+                }
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            default:
+                lk.unlock();
+                return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+        }
+    } // for each buffer
+    mScaledYu12Frames.clear();
+
+    // Don't hold the lock while calling back to parent
+    lk.unlock();
+    Status st = parent->processCaptureResult(req);
+    if (st != Status::OK) {
+        return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
+    }
+    signalRequestDone();
+    return true;
+}
+
+Status ExternalCameraOfflineSession::importBuffer(int32_t streamId,
+        uint64_t bufId, buffer_handle_t buf,
+        /*out*/buffer_handle_t** outBufPtr,
+        bool allowEmptyBuf) {
+    Mutex::Autolock _l(mCbsLock);
+    return V3_4::implementation::importBufferImpl(
+            mCirculatingBuffers, sHandleImporter, streamId,
+            bufId, buf, outBufPtr, allowEmptyBuf);
+    return Status::OK;
+};
+
+#define UPDATE(md, tag, data, size)               \
+do {                                              \
+    if ((md).update((tag), (data), (size))) {     \
+        ALOGE("Update " #tag " failed!");         \
+        return BAD_VALUE;                         \
+    }                                             \
+} while (0)
+
+status_t ExternalCameraOfflineSession::fillCaptureResult(
+        common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
+    bool afTrigger = false;
+    {
+        std::lock_guard<std::mutex> lk(mAfTriggerLock);
+        afTrigger = mAfTrigger;
+        if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+            camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+            if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+                mAfTrigger = afTrigger = true;
+            } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+                mAfTrigger = afTrigger = false;
+            }
+        }
+    }
+
+    // For USB camera, the USB camera handles everything and we don't have control
+    // over AF. We only simply fake the AF metadata based on the request
+    // received here.
+    uint8_t afState;
+    if (afTrigger) {
+        afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+    } else {
+        afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+    }
+    UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+    camera_metadata_ro_entry activeArraySize =
+            mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+    return V3_4::implementation::fillCaptureResultCommon(md, timestamp, activeArraySize);
+}
+
+#undef UPDATE
+
+Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
+    ATRACE_CALL();
+    // Fill output buffers
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    CaptureResult& result = results[0];
+    result.frameNumber = req->frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req->buffers.size());
+    for (size_t i = 0; i < req->buffers.size(); i++) {
+        result.outputBuffers[i].streamId = req->buffers[i].streamId;
+        result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+        if (req->buffers[i].fenceTimeout) {
+            result.outputBuffers[i].status = BufferStatus::ERROR;
+            if (req->buffers[i].acquireFence >= 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+            }
+            notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+        } else {
+            result.outputBuffers[i].status = BufferStatus::OK;
+            // TODO: refactor
+            if (req->buffers[i].acquireFence >= 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+            }
+        }
+    }
+
+    // Fill capture result metadata
+    fillCaptureResult(req->setting, req->shutterTs);
+    const camera_metadata_t *rawResult = req->setting.getAndLock();
+    V3_2::implementation::convertToHidl(rawResult, &result.result);
+    req->setting.unlock(rawResult);
+
+    // Callback into framework
+    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+    V3_4::implementation::freeReleaseFences(results);
+    return Status::OK;
+};
+
+void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback(
+        hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        const nsecs_t NS_TO_SECOND = 1000000000;
+        ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(/* 1s */NS_TO_SECOND) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+                    __FUNCTION__);
+            return;
+        }
+    }
+    if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+        for (CaptureResult &result : results) {
+            if (result.result.size() > 0) {
+                if (mResultMetadataQueue->write(result.result.data(), result.result.size())) {
+                    result.fmqResultSize = result.result.size();
+                    result.result.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    result.fmqResultSize = 0;
+                }
+            } else {
+                result.fmqResultSize = 0;
+            }
+        }
+    }
+    auto status = mCallback->processCaptureResult(results);
+    if (!status.isOk()) {
+        ALOGE("%s: processCaptureResult ERROR : %s", __FUNCTION__,
+              status.description().c_str());
+    }
+
+    mProcessCaptureResultLock.unlock();
+}
+
+Status ExternalCameraOfflineSession::processCaptureRequestError(
+        const std::shared_ptr<HalRequest>& req,
+        /*out*/std::vector<NotifyMsg>* outMsgs,
+        /*out*/std::vector<CaptureResult>* outResults) {
+    ATRACE_CALL();
+
+    if (outMsgs == nullptr) {
+        notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+    } else {
+        NotifyMsg shutter;
+        shutter.type = MsgType::SHUTTER;
+        shutter.msg.shutter.frameNumber = req->frameNumber;
+        shutter.msg.shutter.timestamp = req->shutterTs;
+
+        NotifyMsg error;
+        error.type = MsgType::ERROR;
+        error.msg.error.frameNumber = req->frameNumber;
+        error.msg.error.errorStreamId = -1;
+        error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+        outMsgs->push_back(shutter);
+        outMsgs->push_back(error);
+    }
+
+    // Fill output buffers
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    CaptureResult& result = results[0];
+    result.frameNumber = req->frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req->buffers.size());
+    for (size_t i = 0; i < req->buffers.size(); i++) {
+        result.outputBuffers[i].streamId = req->buffers[i].streamId;
+        result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+        result.outputBuffers[i].status = BufferStatus::ERROR;
+        if (req->buffers[i].acquireFence >= 0) {
+            native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+            handle->data[0] = req->buffers[i].acquireFence;
+            result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+        }
+    }
+
+    if (outResults == nullptr) {
+        // Callback into framework
+        invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+        V3_4::implementation::freeReleaseFences(results);
+    } else {
+        outResults->push_back(result);
+    }
+    return Status::OK;
+};
+
+ssize_t ExternalCameraOfflineSession::getJpegBufferSize(
+        uint32_t /*width*/, uint32_t /*height*/) const {
+    // Empty implementation here as the jpeg buffer size is passed in by ctor
+    return 0;
+};
+
+void ExternalCameraOfflineSession::notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) {
+    NotifyMsg msg;
+    msg.type = MsgType::ERROR;
+    msg.msg.error.frameNumber = frameNumber;
+    msg.msg.error.errorStreamId = streamId;
+    msg.msg.error.errorCode = ec;
+    mCallback->notify({msg});
+};
+
+Return<void> ExternalCameraOfflineSession::setCallback(const sp<ICameraDeviceCallback>& cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    if (mCallback != nullptr && cb != nullptr) {
+        ALOGE("%s: callback must not be set twice!", __FUNCTION__);
+        return Void();
+    }
+    mCallback = cb;
+
+    initOutputThread();
+
+    if (mOutputThread == nullptr) {
+        ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+    }
+    return Void();
+}
+
+Return<void> ExternalCameraOfflineSession::getCaptureResultMetadataQueue(
+        V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    _hidl_cb(*mResultMetadataQueue->getDesc());
+    return Void();
+}
+
+void ExternalCameraOfflineSession::cleanupBuffersLocked(int id) {
+    for (auto& pair : mCirculatingBuffers.at(id)) {
+        sHandleImporter.freeBuffer(pair.second);
+    }
+    mCirculatingBuffers[id].clear();
+    mCirculatingBuffers.erase(id);
+}
+
+Return<void> ExternalCameraOfflineSession::close() {
+    Mutex::Autolock _il(mInterfaceLock);
+    {
+        Mutex::Autolock _l(mLock);
+        if (mClosed) {
+            ALOGW("%s: offline session already closed!", __FUNCTION__);
+            return Void();
+        }
+    }
+    if (mBufferRequestThread) {
+        mBufferRequestThread->requestExit();
+        mBufferRequestThread->join();
+        mBufferRequestThread.clear();
+    }
+    if (mOutputThread) {
+        mOutputThread->flush();
+        mOutputThread->requestExit();
+        mOutputThread->join();
+        mOutputThread.clear();
+    }
+
+    Mutex::Autolock _l(mLock);
+    // free all buffers
+    {
+        Mutex::Autolock _cbl(mCbsLock);
+        for(auto stream : mOfflineStreams) {
+            cleanupBuffersLocked(stream.id);
+        }
+    }
+    mCallback.clear();
+    mClosed = true;
+    return Void();
+}
+
+} // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.6/default/OWNERS b/camera/device/3.6/default/OWNERS
new file mode 100644
index 0000000..f48a95c
--- /dev/null
+++ b/camera/device/3.6/default/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
new file mode 100644
index 0000000..db0d9a5
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+
+struct ExternalCameraDeviceSession : public V3_5::implementation::ExternalCameraDeviceSession {
+
+    ExternalCameraDeviceSession(const sp<V3_2::ICameraDeviceCallback>&,
+            const ExternalCameraConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats,
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            unique_fd v4l2Fd);
+    virtual ~ExternalCameraDeviceSession();
+
+    // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+    // dealing with minor version revs and simultaneous implementation and interface inheritance
+    virtual sp<V3_4::ICameraDeviceSession> getInterface() override {
+        return new TrampolineSessionInterface_3_6(this);
+    }
+
+protected:
+    // Methods from v3.5 and earlier will trampoline to inherited implementation
+    Return<void> configureStreams_3_6(
+            const StreamConfiguration& requestedConfiguration,
+            ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb);
+
+    Return<void> switchToOffline(
+            const hidl_vec<int32_t>& streamsToKeep,
+            ICameraDeviceSession::switchToOffline_cb _hidl_cb);
+
+    void fillOutputStream3_6(const V3_3::HalStreamConfiguration& outStreams_v33,
+            /*out*/V3_6::HalStreamConfiguration* outStreams_v36);
+    bool supportOfflineLocked(int32_t streamId);
+
+    // Main body of switchToOffline. This method does not invoke any callbacks
+    // but instead returns the necessary callbacks in output arguments so callers
+    // can callback later without holding any locks
+    Status switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+            /*out*/std::vector<NotifyMsg>* msgs,
+            /*out*/std::vector<CaptureResult>* results,
+            /*out*/CameraOfflineSessionInfo* info,
+            /*out*/sp<ICameraOfflineSession>* session);
+
+    // Whether a request can be completely dropped when switching to offline
+    bool canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+            std::shared_ptr<V3_4::implementation::HalRequest> halReq);
+
+    void fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+            std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+            const std::map<int, CirculatingBuffers>& circulatingBuffers,
+            /*out*/CameraOfflineSessionInfo* info);
+
+private:
+
+    struct TrampolineSessionInterface_3_6 : public ICameraDeviceSession {
+        TrampolineSessionInterface_3_6(sp<ExternalCameraDeviceSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> constructDefaultRequestSettings(
+                RequestTemplate type,
+                V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+            return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+            return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+            return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> getCaptureRequestMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<Status> flush() override {
+            return mParent->flush();
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+        virtual Return<void> configureStreams_3_3(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_3_cb _hidl_cb) override {
+            return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_4(
+                const V3_4::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_4_cb _hidl_cb) override {
+            return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
+            return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_5(
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_5_cb _hidl_cb) override {
+            return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> signalStreamFlush(
+                const hidl_vec<int32_t>& requests,
+                uint32_t streamConfigCounter) override {
+            return mParent->signalStreamFlush(requests, streamConfigCounter);
+        }
+
+        virtual Return<void> isReconfigurationRequired(const V3_2::CameraMetadata& oldSessionParams,
+                const V3_2::CameraMetadata& newSessionParams,
+                ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) override {
+            return mParent->isReconfigurationRequired(oldSessionParams, newSessionParams, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_6(
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_6_cb _hidl_cb) override {
+            return mParent->configureStreams_3_6(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> switchToOffline(
+                const hidl_vec<int32_t>& streamsToKeep,
+                switchToOffline_cb _hidl_cb) override {
+            return mParent->switchToOffline(streamsToKeep, _hidl_cb);
+        }
+
+    private:
+        sp<ExternalCameraDeviceSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h
new file mode 100644
index 0000000..020bec4
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDevice_3_6.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
+
+#include <android/hardware/camera/device/3.6/ICameraDevice.h>
+
+#include "ExternalCameraDeviceSession.h"
+#include <../../../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDevice_3_5.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_6::ICameraDevice;
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct ExternalCameraDevice : public V3_5::implementation::ExternalCameraDevice {
+
+    // Called by external camera provider HAL.
+    // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+    // be multiple CameraDevice trying to access the same physical camera.  Also, provider will have
+    // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+    // camera is detached.
+    ExternalCameraDevice(const std::string& cameraId, const ExternalCameraConfig& cfg);
+    virtual ~ExternalCameraDevice();
+
+    virtual sp<V3_2::ICameraDevice> getInterface() override {
+        return new TrampolineDeviceInterface_3_6(this);
+    }
+
+protected:
+    virtual sp<V3_4::implementation::ExternalCameraDeviceSession> createSession(
+            const sp<V3_2::ICameraDeviceCallback>&,
+            const ExternalCameraConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats,
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            unique_fd v4l2Fd) override;
+
+    virtual status_t initAvailableCapabilities(
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*) override;
+
+private:
+    struct TrampolineDeviceInterface_3_6 : public ICameraDevice {
+        TrampolineDeviceInterface_3_6(sp<ExternalCameraDevice> parent) :
+            mParent(parent) {}
+
+        virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb)
+                override {
+            return mParent->getResourceCost(_hidl_cb);
+        }
+
+        virtual Return<void> getCameraCharacteristics(
+                V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getCameraCharacteristics(_hidl_cb);
+        }
+
+        virtual Return<Status> setTorchMode(TorchMode mode) override {
+            return mParent->setTorchMode(mode);
+        }
+
+        virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback,
+                V3_2::ICameraDevice::open_cb _hidl_cb) override {
+            return mParent->open(callback, _hidl_cb);
+        }
+
+        virtual Return<void> dumpState(const hidl_handle& fd) override {
+            return mParent->dumpState(fd);
+        }
+
+        virtual Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+                V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb);
+        }
+
+        virtual Return<void> isStreamCombinationSupported(
+                const V3_4::StreamConfiguration& streams,
+                V3_5::ICameraDevice::isStreamCombinationSupported_cb _hidl_cb) override {
+            return mParent->isStreamCombinationSupported(streams, _hidl_cb);
+        }
+
+    private:
+        sp<ExternalCameraDevice> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
new file mode 100644
index 0000000..230b67c
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+#include <android/hardware/camera/common/1.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <deque>
+#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include <HandleImporter.h>
+#include <Exif.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_5::BufferRequest;
+using ::android::hardware::camera::device::V3_5::BufferRequestStatus;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_2::DataspaceFlags;
+using ::android::hardware::camera::device::V3_2::CameraBlob;
+using ::android::hardware::camera::device::V3_2::CameraBlobId;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::camera::external::common::SizeHasher;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::CirculatingBuffers;
+using ::android::hardware::camera::device::V3_4::implementation::HalRequest;
+using ::android::hardware::camera::device::V3_4::implementation::OutputThreadInterface;
+
+struct ExternalCameraOfflineSession : public virtual RefBase,
+        public virtual OutputThreadInterface {
+
+    ExternalCameraOfflineSession(
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            const std::string& cameraId,
+            const std::string& exifMake,
+            const std::string& exifModel,
+            uint32_t blobBufferSize,
+            bool afTrigger,
+            const hidl_vec<Stream>& offlineStreams,
+            std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+            const std::map<int, CirculatingBuffers>& circulatingBuffers);
+
+    bool initialize();
+
+    virtual ~ExternalCameraOfflineSession();
+
+    // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+    // dealing with minor version revs and simultaneous implementation and interface inheritance
+    virtual sp<V3_6::ICameraOfflineSession> getInterface() {
+        return new TrampolineSessionInterface_3_6(this);
+    }
+
+protected:
+
+    // Methods from OutputThreadInterface
+    virtual Status importBuffer(int32_t streamId,
+            uint64_t bufId, buffer_handle_t buf,
+            /*out*/buffer_handle_t** outBufPtr,
+            bool allowEmptyBuf) override;
+
+    virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
+
+    virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+            /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+            /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+    virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+    // End of OutputThreadInterface methods
+
+    class OutputThread : public V3_5::implementation::ExternalCameraDeviceSession::OutputThread {
+    public:
+        OutputThread(
+                wp<OutputThreadInterface> parent, CroppingType ct,
+                const common::V1_0::helper::CameraMetadata& chars,
+                sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> bufReqThread,
+                std::deque<std::shared_ptr<HalRequest>>& offlineReqs) :
+                V3_5::implementation::ExternalCameraDeviceSession::OutputThread(
+                        parent, ct, chars, bufReqThread),
+                mOfflineReqs(offlineReqs) {}
+
+        virtual bool threadLoop() override;
+
+    protected:
+        std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+    }; // OutputThread
+
+
+    Return<void> setCallback(const sp<ICameraDeviceCallback>& cb);
+
+    Return<void> getCaptureResultMetadataQueue(
+            V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb);
+
+    Return<void> close();
+
+    void initOutputThread();
+
+    void invokeProcessCaptureResultCallback(
+            hidl_vec<CaptureResult> &results, bool tryWriteFmq);
+
+    status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
+
+    void cleanupBuffersLocked(int id);
+
+    // Protect (most of) HIDL interface methods from synchronized-entering
+    mutable Mutex mInterfaceLock;
+
+    mutable Mutex mLock; // Protect all data members except otherwise noted
+
+    bool mClosed = false;
+    const CroppingType mCroppingType;
+    const common::V1_0::helper::CameraMetadata mChars;
+    const std::string mCameraId;
+    const std::string mExifMake;
+    const std::string mExifModel;
+    const uint32_t mBlobBufferSize;
+
+    std::mutex mAfTriggerLock; // protect mAfTrigger
+    bool mAfTrigger;
+
+    const hidl_vec<Stream> mOfflineStreams;
+    std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+
+    // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+    mutable Mutex mCbsLock;
+    std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+    static HandleImporter sHandleImporter;
+
+    using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+    std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+    // Protect against invokeProcessCaptureResultCallback()
+    Mutex mProcessCaptureResultLock;
+
+    sp<ICameraDeviceCallback> mCallback;
+
+    sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> mBufferRequestThread;
+    sp<OutputThread> mOutputThread;
+private:
+
+    struct TrampolineSessionInterface_3_6 : public ICameraOfflineSession {
+        TrampolineSessionInterface_3_6(sp<ExternalCameraOfflineSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> setCallback(const sp<ICameraDeviceCallback>& cb) override {
+            return mParent->setCallback(cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+    private:
+        sp<ExternalCameraOfflineSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_6
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
diff --git a/camera/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..f5034cc 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>
      *
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..224c369
--- /dev/null
+++ b/camera/metadata/3.5/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.metadata@3.5",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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..4e2252c
--- /dev/null
+++ b/camera/metadata/3.5/types.hal
@@ -0,0 +1,133 @@
+/*
+ * 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.availableBokehMaxSizes [static, int32[], ndk_public]
+     *
+     * <p>The list of bokeh modes for ANDROID_CONTROL_BOKEH_MODE that are supported by this camera
+     * device, and each bokeh mode's maximum streaming (non-stall) size with bokeh effect.</p>
+     *
+     * @see ANDROID_CONTROL_BOKEH_MODE
+     */
+    ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+
+    /** android.control.availableBokehZoomRatioRanges [static, float[], ndk_public]
+     *
+     * <p>The ranges of supported zoom ratio for non-OFF ANDROID_CONTROL_BOKEH_MODE.</p>
+     *
+     * @see ANDROID_CONTROL_BOKEH_MODE
+     */
+    ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES,
+
+    /** android.control.bokehMode [dynamic, enum, public]
+     *
+     * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+     */
+    ANDROID_CONTROL_BOKEH_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[], public]
+     *
+     * <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, public]
+     *
+     * <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.bokehMode enumeration values
+ * @see ANDROID_CONTROL_BOKEH_MODE
+ */
+enum CameraMetadataEnumAndroidControlBokehMode : uint32_t {
+    ANDROID_CONTROL_BOKEH_MODE_OFF,
+    ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE,
+    ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS,
+};
+
+/** 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..2bfced2 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -26,6 +26,7 @@
 #include "ExternalCameraProviderImpl_2_4.h"
 #include "ExternalCameraDevice_3_4.h"
 #include "ExternalCameraDevice_3_5.h"
+#include "ExternalCameraDevice_3_6.h"
 
 namespace android {
 namespace hardware {
@@ -73,6 +74,7 @@
     switch(mPreferredHal3MinorVersion) {
         case 4:
         case 5:
+        case 6:
             // OK
             break;
         default:
@@ -171,6 +173,12 @@
                     cameraId, mCfg);
             break;
         }
+        case 6: {
+            ALOGV("Constructing v3.6 external camera device");
+            deviceImpl = new device::V3_6::implementation::ExternalCameraDevice(
+                    cameraId, mCfg);
+            break;
+        }
         default:
             ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion);
             _hidl_cb(Status::INTERNAL_ERROR, nullptr);
@@ -202,7 +210,9 @@
     ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
     Mutex::Autolock _l(mLock);
     std::string deviceName;
-    if (mPreferredHal3MinorVersion == 5) {
+    if (mPreferredHal3MinorVersion == 6) {
+        deviceName = std::string("device@3.6/external/") + devName;
+    } else if (mPreferredHal3MinorVersion == 5) {
         deviceName = std::string("device@3.5/external/") + devName;
     } else {
         deviceName = std::string("device@3.4/external/") + devName;
@@ -249,7 +259,9 @@
 void ExternalCameraProviderImpl_2_4::deviceRemoved(const char* devName) {
     Mutex::Autolock _l(mLock);
     std::string deviceName;
-    if (mPreferredHal3MinorVersion == 5) {
+    if (mPreferredHal3MinorVersion == 6) {
+        deviceName = std::string("device@3.6/external/") + devName;
+    } else if (mPreferredHal3MinorVersion == 5) {
         deviceName = std::string("device@3.5/external/") + devName;
     } else {
         deviceName = std::string("device@3.4/external/") + devName;
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 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/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index a5369e7..c9d76da 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -20,111 +20,116 @@
 #include <chrono>
 #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 +137,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;
@@ -161,11 +168,13 @@
 namespace {
     // "device@<version>/legacy/<id>"
     const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
+    const int CAMERA_DEVICE_API_VERSION_3_6 = 0x306;
     const int CAMERA_DEVICE_API_VERSION_3_5 = 0x305;
     const int CAMERA_DEVICE_API_VERSION_3_4 = 0x304;
     const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303;
     const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
     const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
+    const char *kHAL3_6 = "3.6";
     const char *kHAL3_5 = "3.5";
     const char *kHAL3_4 = "3.4";
     const char *kHAL3_3 = "3.3";
@@ -201,7 +210,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 +297,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 +537,31 @@
 }
 
 // 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);
 
-    struct EmptyDeviceCb : public V3_5::ICameraDeviceCallback {
+ 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 +598,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 +617,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 +634,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 +725,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 +742,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,
@@ -776,6 +784,8 @@
             const CameraMetadata& chars, int deviceVersion,
             const hidl_vec<hidl_string>& deviceNames);
     void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
+    void verifyBokehCharacteristics(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 +807,25 @@
     void verifySessionReconfigurationQuery(sp<device::V3_5::ICameraDeviceSession> session3_5,
             camera_metadata* oldSessionParams, camera_metadata* newSessionParams);
 
+    void verifyRequestTemplate(const camera_metadata_t* metadata, RequestTemplate requestTemplate);
+
     bool isDepthOnly(camera_metadata_t* staticMeta);
 
-    static Status getAvailableOutputStreams(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,
@@ -832,6 +852,9 @@
             CameraParameters &cameraParams, const char *mode) ;
     static Status isMonochromeCamera(const camera_metadata_t *staticMeta);
 
+    // Used by switchToOffline where a new result queue is created for offline reqs
+    void updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue);
+
 protected:
 
     // In-flight queue for tracking completion of capture requests.
@@ -865,6 +888,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 +903,8 @@
         // return from HAL but framework.
         ::android::Vector<StreamBuffer> resultOutputBuffers;
 
+        std::unordered_set<std::string> expectedPhysicalResults;
+
         InFlightRequest() :
                 shutterTimestamp(0),
                 errorCodeValid(false),
@@ -907,6 +934,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 +977,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 +1170,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 +1304,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 +1346,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 +1353,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 +1446,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 +1470,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 +1479,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 +1521,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,9 +1541,27 @@
         ALOGE("%s: unknown buffer ID %" PRIu64, __FUNCTION__, buf.bufferId);
         ADD_FAILURE();
     }
+    if (!hasOutstandingBuffersLocked()) {
+        l.unlock();
+        mFlushedCondition.notify_one();
+    }
     return Void();
 }
 
+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) {
     std::vector<std::string> cameraDeviceNames;
     Return<void> ret;
@@ -1505,8 +1618,23 @@
     return retList;
 }
 
+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 +1659,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 +1676,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 +1689,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 +1707,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 +1725,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 +1759,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:
@@ -1649,12 +1815,13 @@
 
 // Verify that the device resource cost can be retrieved and the values are
 // sane.
-TEST_F(CameraHidlTest, getResourceCost) {
+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 +1886,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 +1934,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 +1954,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 +1979,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 +2004,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 +2034,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 +2083,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 +2103,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 +2130,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 +2153,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 +2231,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 +2255,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 +2316,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 +2362,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 +2417,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) {
@@ -2298,7 +2465,7 @@
 }
 
 // Basic sanity tests related to camera parameters.
-TEST_F(CameraHidlTest, getSetParameters) {
+TEST_P(CameraHidlTest, getSetParameters) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
 
     for (const auto& name : cameraDeviceNames) {
@@ -2390,12 +2557,13 @@
 
 // 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 +2624,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 +2643,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 +2763,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 +2829,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 +2866,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 +2927,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 +2985,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 +3012,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 +3032,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 +3120,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 +3292,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 +3469,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 +3490,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 +3636,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 +3658,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 +3756,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 +3781,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 +3880,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 +3899,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 +4086,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 +4111,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,7 +4208,7 @@
 }
 
 // Generate and verify a camera capture request
-TEST_F(CameraHidlTest, processCaptureRequestPreview) {
+TEST_P(CameraHidlTest, processCaptureRequestPreview) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
                                         static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
@@ -4048,7 +4376,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 +4445,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 +4485,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 +4564,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 +4623,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 +4781,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 +4854,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 +5122,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 +5265,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 +5310,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 +5318,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 +5351,65 @@
     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) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+    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 +5473,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) {
@@ -5243,7 +5855,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 +5928,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,6 +5949,144 @@
     ASSERT_TRUE(ret.isOk());
 }
 
+// Configure preview stream with possible offline session support
+void CameraHidlTest::configureOfflineStillStream(const std::string &name,
+        int32_t deviceVersion,
+        sp<ICameraProvider> provider,
+        const AvailableStream *threshold,
+        sp<device::V3_6::ICameraDeviceSession> *session/*out*/,
+        V3_2::Stream *stream /*out*/,
+        device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/,
+        bool *supportsPartialResults /*out*/,
+        uint32_t *partialResultCount /*out*/,
+        sp<DeviceCb> *outCb /*out*/,
+        uint32_t *jpegBufferSize /*out*/,
+        bool *useHalBufManager /*out*/) {
+    ASSERT_NE(nullptr, session);
+    ASSERT_NE(nullptr, halStreamConfig);
+    ASSERT_NE(nullptr, stream);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_NE(nullptr, outCb);
+    ASSERT_NE(nullptr, jpegBufferSize);
+    ASSERT_NE(nullptr, useHalBufManager);
+
+    std::vector<AvailableStream> outputStreams;
+    ::android::sp<device::V3_6::ICameraDevice> cameraDevice;
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+    Return<void> ret;
+    ret = provider->getCameraDeviceInterface_V3_x(
+        name,
+        [&cameraDevice](auto status, const auto& device) {
+            ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                  (int)status);
+            ASSERT_EQ(Status::OK, status);
+            ASSERT_NE(device, nullptr);
+            auto castResult = device::V3_6::ICameraDevice::castFrom(device);
+            ASSERT_TRUE(castResult.isOk());
+            cameraDevice = castResult;
+        });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_t *staticMeta;
+    ret = cameraDevice->getCameraCharacteristics([&] (Status s,
+            CameraMetadata metadata) {
+        ASSERT_EQ(Status::OK, s);
+        staticMeta = clone_camera_metadata(
+                reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+        ASSERT_NE(nullptr, staticMeta);
+    });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_ro_entry entry;
+    auto status = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+    if ((0 == status) && (entry.count > 0)) {
+        *partialResultCount = entry.data.i32[0];
+        *supportsPartialResults = (*partialResultCount > 1);
+    }
+
+    *useHalBufManager = false;
+    status = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+    if ((0 == status) && (entry.count == 1)) {
+        *useHalBufManager = (entry.data.u8[0] ==
+            ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    }
+
+    auto st = getJpegBufferSize(staticMeta, jpegBufferSize);
+    ASSERT_EQ(st, Status::OK);
+
+    sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta);
+    ret = cameraDevice->open(cb, [&session](auto status, const auto& newSession) {
+            ALOGI("device::open returns status:%d", (int)status);
+            ASSERT_EQ(Status::OK, status);
+            ASSERT_NE(newSession, nullptr);
+            auto castResult = device::V3_6::ICameraDeviceSession::castFrom(newSession);
+            ASSERT_TRUE(castResult.isOk());
+            *session = castResult;
+        });
+    ASSERT_TRUE(ret.isOk());
+    *outCb = cb;
+
+    outputStreams.clear();
+    auto rc = getAvailableOutputStreams(staticMeta,
+            outputStreams, threshold);
+    size_t idx = 0;
+    int currLargest = outputStreams[0].width * outputStreams[0].height;
+    for (size_t i = 0; i < outputStreams.size(); i++) {
+        int area = outputStreams[i].width * outputStreams[i].height;
+        if (area > currLargest) {
+            idx = i;
+            currLargest = area;
+        }
+    }
+    free_camera_metadata(staticMeta);
+    ASSERT_EQ(Status::OK, rc);
+    ASSERT_FALSE(outputStreams.empty());
+
+    V3_2::DataspaceFlags dataspaceFlag = 0;
+    switch (static_cast<PixelFormat>(outputStreams[idx].format)) {
+        case PixelFormat::BLOB:
+            dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::V0_JFIF);
+            break;
+        case PixelFormat::Y16:
+            dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::DEPTH);
+            break;
+        default:
+            dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::UNKNOWN);
+    }
+
+    ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(/*size*/1);
+    V3_4::Stream stream3_4 = {{ 0 /*streamId*/, StreamType::OUTPUT,
+        static_cast<uint32_t> (outputStreams[idx].width),
+        static_cast<uint32_t> (outputStreams[idx].height),
+        static_cast<PixelFormat> (outputStreams[idx].format),
+        GRALLOC1_CONSUMER_USAGE_CPU_READ, dataspaceFlag, StreamRotation::ROTATION_0},
+        nullptr /*physicalId*/, /*bufferSize*/ *jpegBufferSize};
+    streams3_4[0] = stream3_4;
+
+    ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+    ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
+    config3_4 = {streams3_4, StreamConfigurationMode::NORMAL_MODE, {}};
+
+    config3_5.v3_4 = config3_4;
+    config3_5.streamConfigCounter = 0;
+    ret = (*session)->configureStreams_3_6(config3_5,
+            [&] (Status s, device::V3_6::HalStreamConfiguration halConfig) {
+                ASSERT_EQ(Status::OK, s);
+                *halStreamConfig = halConfig;
+
+                if (*useHalBufManager) {
+                    hidl_vec<V3_2::HalStream> halStreams3_2(1);
+                    halStreams3_2[0] = halConfig.streams[0].v3_4.v3_3.v3_2;
+                    cb->setCurrentStreamConfig(streams3_4, halStreams3_2);
+                }
+            });
+    *stream = streams3_4[0].v3_2;
+    ASSERT_TRUE(ret.isOk());
+}
+
 bool CameraHidlTest::isDepthOnly(camera_metadata_t* staticMeta) {
     camera_metadata_ro_entry scalarEntry;
     camera_metadata_ro_entry depthEntry;
@@ -5367,6 +6118,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,
@@ -5435,7 +6194,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,
@@ -5493,9 +6253,9 @@
                     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);
                     }
@@ -5550,12 +6310,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 +6330,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());
@@ -5623,6 +6398,11 @@
         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 +6410,37 @@
     for (auto physicalId : physicalIds) {
         ASSERT_NE(physicalId, cameraId);
         bool isPublicId = false;
+        std::string fullPublicId;
         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);
+                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());
             continue;
         }
 
@@ -5654,6 +6456,12 @@
                 [&](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());
 
@@ -5673,8 +6481,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 +6579,216 @@
             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);
+    }
+
+    verifyBokehCharacteristics(metadata);
+    verifyZoomCharacteristics(metadata);
+}
+
+void CameraHidlTest::verifyBokehCharacteristics(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_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+    bool hasBokehRequestKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasBokehRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_BOKEH_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 hasBokehResultKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasBokehResultKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_BOKEH_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 hasBokehMaxSizesKey = false;
+    bool hasBokehZoomRatioRangesKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasBokehMaxSizesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES) != entry.data.i32+entry.count;
+        hasBokehZoomRatioRangesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_AVAILABLE_BOKEH_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_BOKEH_MAX_SIZES, &maxSizesEntry);
+    bool hasBokehMaxSizes = (0 == retcode && maxSizesEntry.count > 0);
+
+    camera_metadata_ro_entry zoomRatioRangesEntry;
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES, &zoomRatioRangesEntry);
+    bool hasBokehZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0);
+
+    // Bokeh keys must all be available, or all be unavailable.
+    bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehMaxSizesKey &&
+            !hasBokehZoomRatioRangesKey && !hasBokehMaxSizes && !hasBokehZoomRatioRanges;
+    if (noBokeh) {
+        return;
+    }
+    bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehMaxSizesKey &&
+            hasBokehZoomRatioRangesKey && hasBokehMaxSizes && hasBokehZoomRatioRanges;
+    ASSERT_TRUE(hasBokeh);
+
+    // Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS.
+    // Only valid combinations: {OFF, CONTINUOUS}, {OFF, STILL_CAPTURE}, and
+    // {OFF, CONTINUOUS, STILL_CAPTURE}.
+    ASSERT_TRUE((maxSizesEntry.count == 6 && zoomRatioRangesEntry.count == 2) ||
+            (maxSizesEntry.count == 9 && zoomRatioRangesEntry.count == 4));
+    bool hasOffMode = false;
+    bool hasStillCaptureMode = false;
+    bool hasContinuousMode = 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_BOKEH_MODE_OFF:
+                hasOffMode = true;
+                ASSERT_TRUE(maxWidth == 0 && maxHeight == 0);
+                break;
+            case ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE:
+                hasStillCaptureMode = true;
+                j += 2;
+                break;
+            case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS:
+                hasContinuousMode = true;
+                j += 2;
+                break;
+            default:
+                ADD_FAILURE() << "Invalid bokehMode advertised: " << mode;
+                break;
+        }
+
+        if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) {
+            // 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(hasOffMode);
+    ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode);
+}
+
+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];
+    if (maxDigitalZoom != maxZoomRatio) {
+        ADD_FAILURE() << "Maximum zoom ratio is different than maximum digital zoom!";
+    }
+    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 +6942,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 +7162,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 +7290,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..e69819c
--- /dev/null
+++ b/camera/provider/2.6/Android.bp
@@ -0,0 +1,26 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.provider@2.6",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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..5651550
--- /dev/null
+++ b/camera/provider/2.6/ICameraProvider.hal
@@ -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.
+ */
+
+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.
+     *
+     * 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.
+     *
+     * @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/common/aidl/Android.bp b/common/aidl/Android.bp
new file mode 100644
index 0000000..f55e799
--- /dev/null
+++ b/common/aidl/Android.bp
@@ -0,0 +1,21 @@
+aidl_interface {
+    name: "android.hardware.common",
+    host_supported: true,
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "android/hardware/common/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/common/aidl/android/hardware/common/NativeHandle.aidl b/common/aidl/android/hardware/common/NativeHandle.aidl
new file mode 100644
index 0000000..2c250a2
--- /dev/null
+++ b/common/aidl/android/hardware/common/NativeHandle.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.common;
+
+/**
+ * Representation of a native handle.
+ */
+@VintfStability
+parcelable NativeHandle {
+    ParcelFileDescriptor[] fds;
+    int[] ints;
+}
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 21459b7..de1ee84 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -45,6 +45,22 @@
         <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 +73,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>
@@ -113,7 +129,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 +137,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>
@@ -145,7 +161,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.contexthub</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IContexthub</name>
             <instance>default</instance>
@@ -153,7 +169,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>
@@ -187,7 +203,7 @@
          - test DeviceManifestTest#GnssHalVersionCompatibility.
         -->
         <version>1.1</version>
-        <version>2.0</version>
+        <version>2.0-1</version>
         <interface>
             <name>IGnss</name>
             <instance>default</instance>
@@ -195,8 +211,10 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.allocator</name>
+        <!-- TODO(b/136016160): deprecating 2.0. New devices should not use this -->
         <version>2.0</version>
         <version>3.0</version>
+        <version>4.0</version>
         <interface>
             <name>IAllocator</name>
             <instance>default</instance>
@@ -204,7 +222,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>
@@ -212,8 +230,10 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.mapper</name>
+        <!-- TODO(b/136016160): deprecating 2.1. New devices should not use this -->
         <version>2.1</version>
         <version>3.0</version>
+        <version>4.0</version>
         <interface>
             <name>IMapper</name>
             <instance>default</instance>
@@ -268,14 +288,6 @@
             <instance>strongbox</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.light</name>
-        <version>2.0</version>
-        <interface>
-            <name>ILight</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.light</name>
         <interface>
@@ -285,7 +297,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>
@@ -388,6 +400,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>
@@ -400,7 +419,7 @@
     <hal format="hidl" optional="true">
         <name>android.hardware.sensors</name>
         <version>1.0</version>
-        <version>2.0</version>
+        <version>2.0-1</version>
         <interface>
             <name>ISensors</name>
             <instance>default</instance>
@@ -408,7 +427,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>
@@ -465,7 +484,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 +515,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 +523,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 +531,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 9e99c33..d51c966 100644
--- a/contexthub/1.0/vts/functional/Android.bp
+++ b/contexthub/1.0/vts/functional/Android.bp
@@ -18,7 +18,10 @@
     name: "VtsHalContexthubV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalContexthubV1_0TargetTest.cpp"],
-    static_libs: ["android.hardware.contexthub@1.0"],
+    static_libs: [
+        "android.hardware.contexthub@1.0",
+        "VtsHalContexthubUtils",
+    ],
     test_suites: [
         "general-tests",
         "vts-core",
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index a1d173b..ada232b 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -16,6 +16,10 @@
 
 #define LOG_TAG "contexthub_hidl_hal_test"
 
+#include "ContexthubCallbackBase.h"
+#include "ContexthubHidlTestBase.h"
+#include "VtsHalContexthubUtils.h"
+
 #include <android-base/logging.h>
 #include <android/hardware/contexthub/1.0/IContexthub.h>
 #include <android/hardware/contexthub/1.0/IContexthubCallback.h>
@@ -23,17 +27,17 @@
 #include <android/log.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 #include <cinttypes>
 #include <future>
 #include <utility>
 
-using ::android::hardware::Return;
-using ::android::hardware::Void;
+using ::android::sp;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
 using ::android::hardware::contexthub::V1_0::AsyncEventType;
 using ::android::hardware::contexthub::V1_0::ContextHub;
 using ::android::hardware::contexthub::V1_0::ContextHubMsg;
@@ -43,10 +47,11 @@
 using ::android::hardware::contexthub::V1_0::NanoAppBinary;
 using ::android::hardware::contexthub::V1_0::Result;
 using ::android::hardware::contexthub::V1_0::TransactionResult;
-using ::android::sp;
-
-#define ASSERT_OK(result) ASSERT_EQ(result, Result::OK)
-#define EXPECT_OK(result) EXPECT_EQ(result, Result::OK)
+using ::android::hardware::contexthub::vts_utils::asBaseType;
+using ::android::hardware::contexthub::vts_utils::ContexthubCallbackBase;
+using ::android::hardware::contexthub::vts_utils::ContexthubHidlTestBase;
+using ::android::hardware::contexthub::vts_utils::getHalAndHubIdList;
+using ::android::hardware::contexthub::vts_utils::getHubsSync;
 
 namespace {
 
@@ -54,132 +59,37 @@
 // app ID is reserved and must never appear in the list of loaded apps.
 constexpr uint64_t kNonExistentAppId = 0x476f6f6754555555;
 
-// Helper that does explicit conversion of an enum class to its underlying/base
-// type. Useful for stream output of enum values.
-template<typename EnumType>
-constexpr typename std::underlying_type<EnumType>::type asBaseType(
-    EnumType value) {
-  return static_cast<typename std::underlying_type<EnumType>::type>(value);
-}
+const std::vector<std::tuple<std::string, std::string>> kTestParameters =
+        getHalAndHubIdList<IContexthub>();
 
-// Synchronously queries IContexthub::getHubs() and returns the result
-hidl_vec<ContextHub> getHubsSync(sp<IContexthub> hubApi) {
-  hidl_vec<ContextHub> hubList;
-  std::promise<void> barrier;
-
-  hubApi->getHubs([&hubList, &barrier](const hidl_vec<ContextHub>& hubs) {
-    hubList = hubs;
-    barrier.set_value();
-  });
-  barrier.get_future().wait_for(std::chrono::seconds(1));
-
-  return hubList;
-}
-
-// Gets a list of valid hub IDs in the system
-std::vector<std::string> getHubIds(const std::string& service_name) {
-    std::vector<std::string> hubIds;
-
-    sp<IContexthub> hubApi = IContexthub::getService(service_name);
-
-    if (hubApi != nullptr) {
-        for (const ContextHub& hub : getHubsSync(hubApi)) {
-            hubIds.push_back(std::to_string(hub.hubId));
-        }
-    }
-
-    ALOGD("Running tests against all %zu reported hubs for service %s", hubIds.size(),
-          service_name.c_str());
-    return hubIds;
-}
-
-// Test fixture parameterized by hub ID, initializes the HAL and makes the context hub API handle
-// available.
-class ContexthubHidlTest : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
-  public:
-    virtual void SetUp() override {
-        hubApi = IContexthub::getService(std::get<0>(GetParam()));
-        ASSERT_NE(hubApi, nullptr);
-
-        // getHubs() must be called at least once for proper initialization of the
-        // HAL implementation
-        getHubsSync(hubApi);
-    }
-
-    uint32_t getHubId() { return std::stoi(std::get<1>(GetParam())); }
-
-    Result registerCallback(sp<IContexthubCallback> cb) {
-        Result result = hubApi->registerCallback(getHubId(), cb);
-        ALOGD("Registered callback, result %" PRIu32, result);
-        return result;
-    }
-
-    sp<IContexthub> hubApi;
-};
-
-// Base callback implementation that just logs all callbacks by default
-class ContexthubCallbackBase : public IContexthubCallback {
- public:
-  virtual Return<void> handleClientMsg(const ContextHubMsg& /*msg*/) override {
-    ALOGD("Got client message callback");
-    return Void();
-  }
-
-  virtual Return<void> handleTxnResult(
-      uint32_t txnId, TransactionResult result) override {
-    ALOGD("Got transaction result callback for txnId %" PRIu32 " with result %"
-          PRId32, txnId, result);
-    return Void();
-  }
-
-  virtual Return<void> handleHubEvent(AsyncEventType evt) override {
-    ALOGD("Got hub event callback for event type %" PRIu32, evt);
-    return Void();
-  }
-
-  virtual Return<void> handleAppAbort(uint64_t appId, uint32_t abortCode)
-      override {
-    ALOGD("Got app abort notification for appId 0x%" PRIx64 " with abort code "
-          "0x%" PRIx32, appId, abortCode);
-    return Void();
-  }
-
-  virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& /*appInfo*/)
-      override {
-    ALOGD("Got app info callback");
-    return Void();
-  }
-};
+class ContexthubHidlTest : public ContexthubHidlTestBase<IContexthub> {};
 
 // Wait for a callback to occur (signaled by the given future) up to the
 // provided timeout. If the future is invalid or the callback does not come
 // within the given time, returns false.
-template<class ReturnType>
-bool waitForCallback(
-    std::future<ReturnType> future,
-    ReturnType *result,
-    std::chrono::milliseconds timeout = std::chrono::seconds(5)) {
-  auto expiration = std::chrono::system_clock::now() + timeout;
+template <class ReturnType>
+bool waitForCallback(std::future<ReturnType> future, ReturnType* result,
+                     std::chrono::milliseconds timeout = std::chrono::seconds(5)) {
+    auto expiration = std::chrono::system_clock::now() + timeout;
 
-  EXPECT_NE(result, nullptr);
-  EXPECT_TRUE(future.valid());
-  if (result != nullptr && future.valid()) {
-    std::future_status status = future.wait_until(expiration);
-    EXPECT_NE(status, std::future_status::timeout)
-        << "Timed out waiting for callback";
+    EXPECT_NE(result, nullptr);
+    EXPECT_TRUE(future.valid());
+    if (result != nullptr && future.valid()) {
+        std::future_status status = future.wait_until(expiration);
+        EXPECT_NE(status, std::future_status::timeout) << "Timed out waiting for callback";
 
-    if (status == std::future_status::ready) {
-      *result = future.get();
-      return true;
+        if (status == std::future_status::ready) {
+            *result = future.get();
+            return true;
+        }
     }
-  }
 
-  return false;
+    return false;
 }
 
 // Ensures that the metadata reported in getHubs() is sane
 TEST_P(ContexthubHidlTest, TestGetHubs) {
-    hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
+    hidl_vec<ContextHub> hubs = getHubsSync(hubApi.get());
     ALOGD("System reports %zu hubs", hubs.size());
 
     for (const ContextHub& hub : hubs) {
@@ -199,189 +109,158 @@
 }
 
 TEST_P(ContexthubHidlTest, TestRegisterCallback) {
-  ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId());
-  ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+    ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId());
+    ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
 }
 
 TEST_P(ContexthubHidlTest, TestRegisterNullCallback) {
-  ALOGD("TestRegisterNullCallback called, hubId %" PRIu32, getHubId());
-  ASSERT_OK(registerCallback(nullptr));
+    ALOGD("TestRegisterNullCallback called, hubId %" PRIu32, getHubId());
+    ASSERT_OK(registerCallback(nullptr));
 }
 
 // Helper callback that puts the async appInfo callback data into a promise
 class QueryAppsCallback : public ContexthubCallbackBase {
- public:
-  virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& appInfo)
-      override {
-    ALOGD("Got app info callback with %zu apps", appInfo.size());
-    promise.set_value(appInfo);
-    return Void();
-  }
+  public:
+    virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& appInfo) override {
+        ALOGD("Got app info callback with %zu apps", appInfo.size());
+        promise.set_value(appInfo);
+        return Void();
+    }
 
-  std::promise<hidl_vec<HubAppInfo>> promise;
+    std::promise<hidl_vec<HubAppInfo>> promise;
 };
 
 // Calls queryApps() and checks the returned metadata
 TEST_P(ContexthubHidlTest, TestQueryApps) {
-  ALOGD("TestQueryApps called, hubId %u", getHubId());
-  sp<QueryAppsCallback> cb = new QueryAppsCallback();
-  ASSERT_OK(registerCallback(cb));
+    ALOGD("TestQueryApps called, hubId %u", getHubId());
+    sp<QueryAppsCallback> cb = new QueryAppsCallback();
+    ASSERT_OK(registerCallback(cb));
 
-  Result result = hubApi->queryApps(getHubId());
-  ASSERT_OK(result);
+    Result result = hubApi->queryApps(getHubId());
+    ASSERT_OK(result);
 
-  ALOGD("Waiting for app info callback");
-  hidl_vec<HubAppInfo> appList;
-  ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appList));
-  for (const HubAppInfo &appInfo : appList) {
-    EXPECT_NE(appInfo.appId, UINT64_C(0));
-    EXPECT_NE(appInfo.appId, kNonExistentAppId);
-  }
+    ALOGD("Waiting for app info callback");
+    hidl_vec<HubAppInfo> appList;
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appList));
+    for (const HubAppInfo& appInfo : appList) {
+        EXPECT_NE(appInfo.appId, UINT64_C(0));
+        EXPECT_NE(appInfo.appId, kNonExistentAppId);
+    }
 }
 
 // Helper callback that puts the TransactionResult for the expectedTxnId into a
 // promise
 class TxnResultCallback : public ContexthubCallbackBase {
- public:
-  virtual Return<void> handleTxnResult(
-      uint32_t txnId, TransactionResult result) override {
-    ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %"
-          PRIu32 ") with result %" PRId32, txnId, expectedTxnId, result);
-    if (txnId == expectedTxnId) {
-      promise.set_value(result);
+  public:
+    virtual Return<void> handleTxnResult(uint32_t txnId, TransactionResult result) override {
+        ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %" PRIu32
+              ") with result %" PRId32,
+              txnId, expectedTxnId, result);
+        if (txnId == expectedTxnId) {
+            promise.set_value(result);
+        }
+        return Void();
     }
-    return Void();
-  }
 
-  uint32_t expectedTxnId = 0;
-  std::promise<TransactionResult> promise;
+    uint32_t expectedTxnId = 0;
+    std::promise<TransactionResult> promise;
 };
 
 // Parameterized fixture that sets the callback to TxnResultCallback
 class ContexthubTxnTest : public ContexthubHidlTest {
- public:
-  virtual void SetUp() override {
-    ContexthubHidlTest::SetUp();
-    ASSERT_OK(registerCallback(cb));
-  }
+  public:
+    virtual void SetUp() override {
+        ContexthubHidlTest::SetUp();
+        ASSERT_OK(registerCallback(cb));
+    }
 
-  sp<TxnResultCallback> cb = new TxnResultCallback();
+    sp<TxnResultCallback> cb = new TxnResultCallback();
 };
 
-
 // Checks cases where the hub implementation is expected to return an error, but
 // that error can be returned either synchronously or in the asynchronous
 // transaction callback. Returns an AssertionResult that can be used in
 // ASSERT/EXPECT_TRUE. Allows checking the sync result against 1 additional
 // allowed error code apart from OK and TRANSACTION_FAILED, which are always
 // allowed.
-::testing::AssertionResult checkFailureSyncOrAsync(
-    Result result, Result allowedSyncResult,
-    std::future<TransactionResult>&& future) {
-  if (result == Result::OK) {
-    // No error reported synchronously - this is OK, but then we should get an
-    // async callback with a failure status
-    TransactionResult asyncResult;
-    if (!waitForCallback(std::forward<std::future<TransactionResult>>(future),
-                         &asyncResult)) {
-      return ::testing::AssertionFailure()
-          << "Got successful sync result, then failed to receive async cb";
-    } else if (asyncResult == TransactionResult::SUCCESS) {
-      return ::testing::AssertionFailure()
-          << "Got successful sync result, then unexpected successful async "
-             "result";
+::testing::AssertionResult checkFailureSyncOrAsync(Result result, Result allowedSyncResult,
+                                                   std::future<TransactionResult>&& future) {
+    if (result == Result::OK) {
+        // No error reported synchronously - this is OK, but then we should get an
+        // async callback with a failure status
+        TransactionResult asyncResult;
+        if (!waitForCallback(std::forward<std::future<TransactionResult>>(future), &asyncResult)) {
+            return ::testing::AssertionFailure()
+                   << "Got successful sync result, then failed to receive async cb";
+        } else if (asyncResult == TransactionResult::SUCCESS) {
+            return ::testing::AssertionFailure()
+                   << "Got successful sync result, then unexpected successful async "
+                      "result";
+        }
+    } else if (result != allowedSyncResult && result != Result::TRANSACTION_FAILED) {
+        return ::testing::AssertionFailure()
+               << "Got sync result " << asBaseType(result) << ", expected TRANSACTION_FAILED or "
+               << asBaseType(allowedSyncResult);
     }
-  } else if (result != allowedSyncResult &&
-             result != Result::TRANSACTION_FAILED) {
-    return ::testing::AssertionFailure() << "Got sync result "
-        << asBaseType(result) << ", expected TRANSACTION_FAILED or "
-        << asBaseType(allowedSyncResult);
-  }
 
-  return ::testing::AssertionSuccess();
+    return ::testing::AssertionSuccess();
 }
 
 TEST_P(ContexthubTxnTest, TestSendMessageToNonExistentNanoApp) {
-  ContextHubMsg msg;
-  msg.appName = kNonExistentAppId;
-  msg.msgType = 1;
-  msg.msg.resize(4);
-  std::fill(msg.msg.begin(), msg.msg.end(), 0);
+    ContextHubMsg msg;
+    msg.appName = kNonExistentAppId;
+    msg.msgType = 1;
+    msg.msg.resize(4);
+    std::fill(msg.msg.begin(), msg.msg.end(), 0);
 
-  ALOGD("Sending message to non-existent nanoapp");
-  Result result = hubApi->sendMessageToHub(getHubId(), msg);
-  if (result != Result::OK &&
-      result != Result::BAD_PARAMS &&
-      result != Result::TRANSACTION_FAILED) {
-    FAIL() << "Got result " << asBaseType(result) << ", expected OK, BAD_PARAMS"
-        << ", or TRANSACTION_FAILED";
-  }
+    ALOGD("Sending message to non-existent nanoapp");
+    Result result = hubApi->sendMessageToHub(getHubId(), msg);
+    if (result != Result::OK && result != Result::BAD_PARAMS &&
+        result != Result::TRANSACTION_FAILED) {
+        FAIL() << "Got result " << asBaseType(result) << ", expected OK, BAD_PARAMS"
+               << ", or TRANSACTION_FAILED";
+    }
 }
 
 TEST_P(ContexthubTxnTest, TestLoadEmptyNanoApp) {
-  cb->expectedTxnId = 0123;
-  NanoAppBinary emptyApp;
+    cb->expectedTxnId = 0123;
+    NanoAppBinary emptyApp;
 
-  emptyApp.appId = kNonExistentAppId;
-  emptyApp.appVersion = 1;
-  emptyApp.flags = 0;
-  emptyApp.targetChreApiMajorVersion = 1;
-  emptyApp.targetChreApiMinorVersion = 0;
+    emptyApp.appId = kNonExistentAppId;
+    emptyApp.appVersion = 1;
+    emptyApp.flags = 0;
+    emptyApp.targetChreApiMajorVersion = 1;
+    emptyApp.targetChreApiMinorVersion = 0;
 
-  ALOGD("Loading empty nanoapp");
-  Result result = hubApi->loadNanoApp(getHubId(), emptyApp, cb->expectedTxnId);
-  EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
-                                      cb->promise.get_future()));
+    ALOGD("Loading empty nanoapp");
+    Result result = hubApi->loadNanoApp(getHubId(), emptyApp, cb->expectedTxnId);
+    EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
 }
 
 TEST_P(ContexthubTxnTest, TestUnloadNonexistentNanoApp) {
-  cb->expectedTxnId = 1234;
+    cb->expectedTxnId = 1234;
 
-  ALOGD("Unloading nonexistent nanoapp");
-  Result result = hubApi->unloadNanoApp(getHubId(), kNonExistentAppId,
-                                        cb->expectedTxnId);
-  EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
-                                      cb->promise.get_future()));
+    ALOGD("Unloading nonexistent nanoapp");
+    Result result = hubApi->unloadNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId);
+    EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
 }
 
 TEST_P(ContexthubTxnTest, TestEnableNonexistentNanoApp) {
-  cb->expectedTxnId = 2345;
+    cb->expectedTxnId = 2345;
 
-  ALOGD("Enabling nonexistent nanoapp");
-  Result result = hubApi->enableNanoApp(getHubId(), kNonExistentAppId,
-                                        cb->expectedTxnId);
-  EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
-                                      cb->promise.get_future()));
+    ALOGD("Enabling nonexistent nanoapp");
+    Result result = hubApi->enableNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId);
+    EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
 }
 
 TEST_P(ContexthubTxnTest, TestDisableNonexistentNanoApp) {
-  cb->expectedTxnId = 3456;
+    cb->expectedTxnId = 3456;
 
-  ALOGD("Disabling nonexistent nanoapp");
-  Result result = hubApi->disableNanoApp(getHubId(), kNonExistentAppId,
-                                         cb->expectedTxnId);
-  EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS,
-                                      cb->promise.get_future()));
+    ALOGD("Disabling nonexistent nanoapp");
+    Result result = hubApi->disableNanoApp(getHubId(), kNonExistentAppId, cb->expectedTxnId);
+    EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
 }
 
-// Return the test parameters of a vecter of tuples for all IContexthub services and each of its hub
-// id: <service name of IContexthub, hub id of the IContexthub service>
-static std::vector<std::tuple<std::string, std::string>> get_parameters() {
-    std::vector<std::tuple<std::string, std::string>> parameters;
-    std::vector<std::string> service_names =
-            android::hardware::getAllHalInstanceNames(IContexthub::descriptor);
-    for (const std::string& service_name : service_names) {
-        std::vector<std::string> ids = getHubIds(service_name);
-        for (const std::string& id : ids) {
-            parameters.push_back(std::make_tuple(service_name, id));
-        }
-    }
-
-    return parameters;
-}
-
-static std::vector<std::tuple<std::string, std::string>> kTestParameters = get_parameters();
-
 INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
                          android::hardware::PrintInstanceTupleNameToString<>);
 
diff --git a/contexthub/1.1/Android.bp b/contexthub/1.1/Android.bp
new file mode 100644
index 0000000..649f1db
--- /dev/null
+++ b/contexthub/1.1/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.contexthub@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IContexthub.hal",
+    ],
+    interfaces: [
+        "android.hardware.contexthub@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/contexthub/1.1/IContexthub.hal b/contexthub/1.1/IContexthub.hal
new file mode 100644
index 0000000..a3b4bd4
--- /dev/null
+++ b/contexthub/1.1/IContexthub.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub@1.1;
+
+import @1.0::IContexthub;
+import @1.0::Result;
+
+interface IContexthub extends @1.0::IContexthub {
+    /**
+     * Notification sent by the framework to indicate that the user
+     * has changed a setting.
+     *
+     * @param setting User setting that has been modified.
+     * @param newValue The update value of the user setting.
+     */
+    onSettingChanged(Setting setting, SettingValue newValue);
+};
\ No newline at end of file
diff --git a/contexthub/1.1/default/Android.bp b/contexthub/1.1/default/Android.bp
new file mode 100644
index 0000000..86858c0
--- /dev/null
+++ b/contexthub/1.1/default/Android.bp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_binary {
+    name: "android.hardware.contexthub@1.1-service.mock",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.contexthub@1.1-service.rc"],
+    srcs: [
+        "Contexthub.cpp",
+        "service.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "android.hardware.contexthub@1.0",
+        "android.hardware.contexthub@1.1",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+    vintf_fragments: ["android.hardware.contexthub@1.1.xml"],
+}
diff --git a/contexthub/1.1/default/Contexthub.cpp b/contexthub/1.1/default/Contexthub.cpp
new file mode 100644
index 0000000..19cc262
--- /dev/null
+++ b/contexthub/1.1/default/Contexthub.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "Contexthub.h"
+
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::contexthub::V1_0::ContextHub;
+using ::android::hardware::contexthub::V1_0::HubAppInfo;
+using ::android::hardware::contexthub::V1_0::Result;
+
+namespace {
+
+constexpr uint32_t kMockHubId = 0;
+
+}  // anonymous namespace
+
+Return<void> Contexthub::getHubs(getHubs_cb _hidl_cb) {
+    ContextHub hub = {};
+    hub.name = "Mock Context Hub";
+    hub.vendor = "AOSP";
+    hub.toolchain = "n/a";
+    hub.platformVersion = 1;
+    hub.toolchainVersion = 1;
+    hub.hubId = kMockHubId;
+    hub.peakMips = 1;
+    hub.peakPowerDrawMw = 1;
+    hub.maxSupportedMsgLen = 4096;
+    hub.chrePlatformId = UINT64_C(0x476f6f6754000000);
+    hub.chreApiMajorVersion = 1;
+    hub.chreApiMinorVersion = 4;
+
+    // Report a single mock hub
+    std::vector<ContextHub> hubs;
+    hubs.push_back(hub);
+
+    _hidl_cb(hubs);
+    return Void();
+}
+
+Return<Result> Contexthub::registerCallback(uint32_t hubId, const sp<IContexthubCallback>& cb) {
+    if (hubId == kMockHubId) {
+        mCallback = cb;
+        return Result::OK;
+    }
+    return Result::BAD_PARAMS;
+}
+
+// We don't expose any nanoapps, therefore all nanoapp-related API calls return with BAD_PARAMS
+Return<Result> Contexthub::sendMessageToHub(uint32_t /*hubId*/, const ContextHubMsg& /*msg*/) {
+    return Result::BAD_PARAMS;
+}
+
+Return<Result> Contexthub::loadNanoApp(uint32_t /*hubId*/, const NanoAppBinary& /*appBinary*/,
+                                       uint32_t /*transactionId*/) {
+    return Result::BAD_PARAMS;
+}
+
+Return<Result> Contexthub::unloadNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
+                                         uint32_t /*transactionId*/) {
+    return Result::BAD_PARAMS;
+}
+
+Return<Result> Contexthub::enableNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
+                                         uint32_t /*transactionId*/) {
+    return Result::BAD_PARAMS;
+}
+
+Return<Result> Contexthub::disableNanoApp(uint32_t /*hubId*/, uint64_t /*appId*/,
+                                          uint32_t /*transactionId*/) {
+    return Result::BAD_PARAMS;
+}
+
+Return<Result> Contexthub::queryApps(uint32_t hubId) {
+    if (hubId == kMockHubId && mCallback != nullptr) {
+        std::vector<HubAppInfo> nanoapps;
+        mCallback->handleAppsInfo(nanoapps);
+        return Result::OK;
+    }
+    return Result::BAD_PARAMS;
+}
+
+Return<void> Contexthub::onSettingChanged(Setting /*setting*/, SettingValue /*newValue*/) {
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace contexthub
+}  // namespace hardware
+}  // namespace android
diff --git a/contexthub/1.1/default/Contexthub.h b/contexthub/1.1/default/Contexthub.h
new file mode 100644
index 0000000..0da61d1
--- /dev/null
+++ b/contexthub/1.1/default/Contexthub.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android/hardware/contexthub/1.1/IContexthub.h>
+
+namespace android {
+namespace hardware {
+namespace contexthub {
+namespace V1_1 {
+namespace implementation {
+
+class Contexthub : public V1_1::IContexthub {
+    using ContextHubMsg = ::android::hardware::contexthub::V1_0::ContextHubMsg;
+    using IContexthubCallback = ::android::hardware::contexthub::V1_0::IContexthubCallback;
+    using NanoAppBinary = ::android::hardware::contexthub::V1_0::NanoAppBinary;
+    using Result = ::android::hardware::contexthub::V1_0::Result;
+
+  public:
+    // Methods from V1_0::IContexthub
+    Return<void> getHubs(getHubs_cb _hidl_cb) override;
+    Return<Result> registerCallback(uint32_t hubId,
+                                    const ::android::sp<IContexthubCallback>& cb) override;
+    Return<Result> sendMessageToHub(uint32_t hubId, const ContextHubMsg& msg) override;
+    Return<Result> loadNanoApp(uint32_t hubId, const NanoAppBinary& appBinary,
+                               uint32_t transactionId) override;
+    Return<Result> unloadNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
+    Return<Result> enableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
+    Return<Result> disableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) override;
+    Return<Result> queryApps(uint32_t hubId) override;
+
+    // Methods from V1_1::IContexthub
+    Return<void> onSettingChanged(Setting setting, SettingValue newValue) override;
+
+  private:
+    sp<IContexthubCallback> mCallback;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace contexthub
+}  // namespace hardware
+}  // namespace android
diff --git a/contexthub/1.1/default/OWNERS b/contexthub/1.1/default/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/contexthub/1.1/default/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc b/contexthub/1.1/default/android.hardware.contexthub@1.1-service.rc
new file mode 100644
index 0000000..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 95d30d6..42981ad 100644
--- a/current.txt
+++ b/current.txt
@@ -451,9 +451,9 @@
 443659bb9e27221e5da0d16c7a0ecb2dc3a9a03acc8a0b2196b47c50735e2d2e android.hardware.audio.effect@5.0::IVirtualizerEffect
 78fed26a781cdca1b3bcb37520bff705d7764ee81db9cfd37014953c7ad2596e android.hardware.audio.effect@5.0::IVisualizerEffect
 6385b6accab8a544e2ee54ba7bf5aa55dff6153bcedd80fdaae16fe9e0be7050 android.hardware.audio.effect@5.0::types
+95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types
 e18ff318f3fc43db37f554696dc4e551abb9b119bde53950f73e28ce33a97a40 android.hardware.biometrics.face@1.0::IBiometricsFace
 b6e55d7795bbafd011fb95a3b6d3954bf66c349e14cf107f3b72032ce3ceb448 android.hardware.biometrics.face@1.0::IBiometricsFaceClientCallback
-95aa2f59e29e2f84d8e84320ace9b6682b426a16e897b4bd241375cbee0e07f3 android.hardware.biometrics.face@1.0::types
 ecedc58dbcdb13503c19c0ab160ac1dd0530bb1471164149282dd1463c684185 android.hardware.bluetooth.audio@2.0::IBluetoothAudioPort
 fb9c40e4deab40be5476477078fe3d8a4a4495fd9deef4321878d169d675c633 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvider
 f7431f3e3e4e3387fc6f27a6cf423eddcd824a395dc4349d302c995ab44a9895 android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory
@@ -578,6 +578,19 @@
 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
+2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
+cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
+a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types
+9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback
+af334f1fc85c62b343f84b74d0495eed6f495f7fecedb53463db10c202310058 android.hardware.gnss.measurement_corrections@1.0::types
+bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider
+2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback
 b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
 eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
 8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types
@@ -588,17 +601,20 @@
 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
+822369cf4dc16a6f6b9622bcf86cbdc0b692dc82193fc15e967767175cbfdd8f android.hardware.audio@6.0::types
+7241bd4596a927cd46d4b82f5e29e2cbe57f194aa1b25555f1d1d352e8b15c61 android.hardware.audio@6.0::IDevice
 2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory
 bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice
-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
+e7ca0db9a1098210f327a9b152fa6afe6bf019c41e5264c64829d04d50c0a526 android.hardware.audio@6.0::IStreamOutEventCallback
+bee662c62d997d8065e2bcb5c1e7a9578931f22ce28fd02c219fdb4d0630abf7 android.hardware.audio.common@6.0::types
 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect
 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect
@@ -614,12 +630,38 @@
 5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect
 282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect
 0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect
+7e8e1c3d0173c5d503dd01cecff8e3864478557ca6b9e8cc2291598b1a4aea62 android.hardware.biometrics.face@1.1::IBiometricsFace
+ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types
+6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint
+82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback
 79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc 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
+b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice
+99aae72ae75a8ddf63ccffbc585f3a55f4d0847b4adff3d7a0f8bd9e2305bec1 android.hardware.camera.provider@2.6::ICameraProvider
+8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
+a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types
+c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas
+9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener
+f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService
+4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types
+8351cc01eed4c0b4482d9572b5c7ddfd17874d8edb51d6761d348116fc91dd18 android.hardware.contexthub@1.1::IContexthub
+3581d0ba61663cdd45807494dcd697d01c074f27587df9140655f94346969cfe android.hardware.contexthub@1.1::types
+66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory
+994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory
 d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types
 186bc152ae189ab48f3a761a44ddf5edd0d483073c5b6ca1f802f8b50488b754 android.hardware.dumpstate@1.1::IDumpstateDevice
+769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.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
+0a16e5913e94d995cfcf959a1c6f10b0b8e9dfdb5f45ac6e7244711ddd740272 android.hardware.gnss@2.1::IGnssMeasurementCallback
+6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections
+956c1576ca0d6f11b42980ef59052062836b6763fe973af6cb709da50787f710 android.hardware.gnss.measurement_corrections@1.1::types
 ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
 e2f8bc1868fd4a3fd587c172773ea5a8c2f5a3deaf7958394102ca455252b255 android.hardware.health@2.1::types
@@ -630,20 +672,43 @@
 27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice
 adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
 ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types
+df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
+a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer
-9db064ee44268a876be0367ff771e618362d39ec603b6ecab17e1575725fcd87 android.hardware.neuralnetworks@1.3::IDevice
-4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback
-2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
-43088ffc71945b463a7279262cfe2e290f6ed2f15d3fd6032798a3be299fb08f android.hardware.neuralnetworks@1.3::IPreparedModel
-0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-dd39887aa4fb60ce60ea9cc043edeadbbae6e922d09d3946311b0b410024ae14 android.hardware.neuralnetworks@1.3::types
+278817920bfd5292a7713f97f1832cca53de3de640f7670e413d97c6e7fd581c android.hardware.neuralnetworks@1.3::IDevice
+127ba11efb8220dc3aec9a8f441b59eaf1c68d7f03f577833e1824de75a36b17 android.hardware.neuralnetworks@1.3::IExecutionCallback
+6e904be0ddca5ae1de8eba020e6c38ed935ea7d80cd08f47787f137a0ca58555 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
+2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel
+eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
+c9320b04ec302624985180a02d591bea5e435601fc411a6cabb58878e4e1ad68 android.hardware.neuralnetworks@1.3::types
+b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types
+adab52e647d1a1ccfbdabdfc9c73352f8e834b61322e505bc6e3d3a0d3acc259 android.hardware.tv.tuner@1.0::IDemux
+548e1a16fc4f779346e14968a63cd6f160e1e2c8b8c99256b2bac24a24b52a9a android.hardware.tv.tuner@1.0::IDescrambler
+b84597d59f0f1d03c9997d60eb15280f3950c287d46016240d89859789db4d47 android.hardware.tv.tuner@1.0::IDvr
+e512a8b4ddef0d0c29d9f68101363dca7616033a24bab86bfca0829661e7484c android.hardware.tv.tuner@1.0::IDvrCallback
+c113b5bed45b3a67ee3f15de1482742a8fd8d96e45ec72e628ee9be6301d51d7 android.hardware.tv.tuner@1.0::IFilter
+8bbc6bde44573edf800cda2b457852175786a3c73f36666bfb2d3afdce3d0dfa android.hardware.tv.tuner@1.0::IFilterCallback
+ccd985e820ed92a5cb55f524b3549462483d21824ca2df0276f5bc2f42878ea3 android.hardware.tv.tuner@1.0::IFrontend
+818587bab10f2534b5a1ef70ed9bae99019f7d453b2fcb2dda01c6db91c3a805 android.hardware.tv.tuner@1.0::IFrontendCallback
+83de3964a800a0e707731adcbcbfbaa56868549233e4c8dcccc8969fab727d38 android.hardware.tv.tuner@1.0::ILnb
+b2310785bdb55f97bbbb2176e2ee73ed8d2a7ce5895bd20c997b90c5f2868ad8 android.hardware.tv.tuner@1.0::ILnbCallback
+4788787e662293d526ff7789fc24e82533e7f6ff99a967ebc3e3ec6b17628796 android.hardware.tv.tuner@1.0::ITimeFilter
+c350c7783843e0c7cf30f90c918770b0d3c09fc0fe5e532e2f2e7210fcfe71c9 android.hardware.tv.tuner@1.0::ITuner
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
+c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
+2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types
 a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
-44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
-619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
-c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
-9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types
-85af67af743b8cebb65023f196ee3df0e57b88c84d048f40439e98f845bab3d6 android.hardware.radio@1.5::types
-e5947273509cd23b432c1a0781245a1e5a1dedca77f41db6dbcc02c0d7a7e40a android.hardware.radio@1.5::IRadio
+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
+99f5c26b952271d1246c957e1d0271fa39445ee65cc93aa7c187834f98914a33 android.hardware.radio@1.5::types
+b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio
 e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication
-6759e59cef81b5e15137bf99a4cd14236ce0c2974dd307ada265b67e819b9060 android.hardware.radio@1.5::IRadioResponse
+829d3827eeb5a8f563e80fe627419b3231012fc02bc2e79782ec5e9ad9f799a4 android.hardware.radio@1.5::IRadioResponse
+3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors
+3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback
+8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types
+4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types
+b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw
+7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
diff --git a/drm/1.3/Android.bp b/drm/1.3/Android.bp
new file mode 100644
index 0000000..b0ffcb9
--- /dev/null
+++ b/drm/1.3/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.drm@1.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IDrmFactory.hal",
+        "ICryptoFactory.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..4be1575
--- /dev/null
+++ b/drm/1.3/vts/functional/Android.bp
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.drm@1.3-vts",
+    defaults: ["VtsHalTargetTestDefaults"],
+    local_include_dirs: [
+        "include",
+    ],
+    srcs: [
+        "drm_hal_test.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
+        "android.hardware.drm@1.3",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+        "libnativehelper",
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0-helper",
+        "libcrypto_static",
+        "libdrmvtshelper",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
+
+cc_test {
+    name: "VtsHalDrmV1_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    include_dirs: ["hardware/interfaces/drm/1.0/vts/functional"],
+    srcs: [
+        "drm_hal_test_main.cpp",
+    ],
+    whole_static_libs: [
+        "android.hardware.drm@1.0-vts",
+        "android.hardware.drm@1.1-vts",
+        "android.hardware.drm@1.2-vts",
+        "android.hardware.drm@1.3-vts",
+    ],
+    shared_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
+        "android.hardware.drm@1.3",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+        "libnativehelper",
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0-helper",
+        "libcrypto_static",
+        "libdrmvtshelper",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/drm/1.3/vts/functional/drm_hal_test.cpp b/drm/1.3/vts/functional/drm_hal_test.cpp
new file mode 100644
index 0000000..738f5b2
--- /dev/null
+++ b/drm/1.3/vts/functional/drm_hal_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "drm_hal_test@1.3"
+
+#include "android/hardware/drm/1.3/vts/drm_hal_test.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_3 {
+namespace vts {
+
+TEST_P(DrmHalTestV1_3, SchemeSupported) {
+    EXPECT_TRUE(drmFactory_->isCryptoSchemeSupported(GetParam().scheme_));
+}
+
+TEST_P(DrmHalTestV1_3, SignRsaNotAllowed) {
+    hidl_array<uint8_t, 16> kWidevineUUID ({
+        0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
+        0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED
+    });
+
+    if (!drmFactory_->isCryptoSchemeSupported(kWidevineUUID)) {
+        GTEST_SKIP() << "Widevine only test";
+    }
+
+    // signRSA
+    const hidl_vec<uint8_t>& sessionId{};
+    const hidl_string& algorithm{};
+    const hidl_vec<uint8_t>& message{};
+    const hidl_vec<uint8_t>& wrappedKey{};
+    auto res = drmPlugin_->signRSA(
+        sessionId, algorithm, message, wrappedKey,
+        [&](StatusV1_0 status, const hidl_vec<uint8_t>& signature) {
+            EXPECT_EQ(status, StatusV1_0::ERROR_DRM_UNKNOWN);
+            EXPECT_EQ(signature.size(), 0);
+        }
+    );
+    EXPECT_TRUE(res.isOk());
+}
+
+}  // namespace vts
+}  // namespace V1_3
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
diff --git a/drm/1.3/vts/functional/drm_hal_test_main.cpp b/drm/1.3/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000..02b45ea
--- /dev/null
+++ b/drm/1.3/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Instantiate the set of test cases for each vendor module
+ */
+
+#define LOG_TAG "drm_hal_test@1.3"
+
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h" // V1_0 tests
+#include "android/hardware/drm/1.0/vts/drm_hal_vendor_test.h"   // V1_0 tests
+#include "android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h" // V1_1 tests
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h"        // V1_2 tests
+#include "android/hardware/drm/1.3/vts/drm_hal_test.h"          // V1_3 tests
+
+using drm_vts::DrmHalTestParam;
+using drm_vts::PrintParamInstanceToString;
+
+using android::hardware::drm::V1_0::vts::DrmHalVendorFactoryTest;
+using android::hardware::drm::V1_0::vts::DrmHalVendorPluginTest;
+using android::hardware::drm::V1_0::vts::DrmHalVendorDecryptTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyFactoryTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyPluginTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyDecryptTest;
+using android::hardware::drm::V1_1::vts::DrmHalClearkeyTest;
+using android::hardware::drm::V1_2::vts::DrmHalTest;
+using android::hardware::drm::V1_2::vts::DrmHalClearkeyTestV1_2;
+using android::hardware::drm::V1_3::vts::DrmHalTestV1_3;
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+    using ::android::hardware::drm::V1_3::ICryptoFactory;
+    using ::android::hardware::drm::V1_3::IDrmFactory;
+
+    std::vector<std::string> drmInstances =
+            android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+    std::vector<std::string> cryptoInstances =
+            android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+    std::set<std::string> allInstances;
+    allInstances.insert(drmInstances.begin(), drmInstances.end());
+    allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+    std::vector<DrmHalTestParam> allInstanceUuidCombos;
+    for (const auto &instance : allInstances) {
+        auto drmFactory = IDrmFactory::getService(instance);
+        if (drmFactory == nullptr) {
+            continue;
+        }
+        drmFactory->getSupportedCryptoSchemes(
+            [&](const hidl_vec<hidl_array<uint8_t, 16>>& schemes) {
+                for (const auto &scheme : schemes) {
+                    allInstanceUuidCombos.push_back(DrmHalTestParam(instance, scheme));
+                }
+            });
+    }
+    return allInstanceUuidCombos;
+}();
+
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorFactoryTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorPluginTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorDecryptTest,
+                        testing::ValuesIn(kAllInstances),
+                        drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyFactoryTest,
+                         testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyPluginTest,
+                         testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyDecryptTest,
+                         testing::ValuesIn(kAllInstances),
+                         drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_1, DrmHalClearkeyTest,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalTest,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalClearkeyTestV1_2,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_3, DrmHalTestV1_3,
+                         testing::ValuesIn(kAllInstances),
+                         PrintParamInstanceToString);
+
+int main(int argc, char** argv) {
+#if defined(__LP64__)
+    const char* kModulePath = "/data/local/tmp/64/lib";
+#else
+    const char* kModulePath = "/data/local/tmp/32/lib";
+#endif
+    DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath);
+    if (DrmHalTest::gVendorModules->getPathList().size() == 0) {
+        std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
+                ", all vendor tests will be skipped" << std::endl;
+    }
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h
new file mode 100644
index 0000000..d8f5277
--- /dev/null
+++ b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DRM_HAL_TEST_V1_3_H
+#define DRM_HAL_TEST_V1_3_H
+
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "drm_hal_vendor_module_api.h"
+#include "drm_vts_helper.h"
+#include "vendor_modules.h"
+#include "VtsHalHidlTargetCallbackBase.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_3 {
+namespace vts {
+
+using android::hardware::hidl_array;
+using android::hardware::hidl_string;
+
+using drm_vts::DrmHalTestParam;
+
+using IDrmFactoryV1_3 = android::hardware::drm::V1_3::IDrmFactory;
+using IDrmPluginV1_0 = android::hardware::drm::V1_0::IDrmPlugin;
+using StatusV1_0 = android::hardware::drm::V1_0::Status;
+
+class DrmHalTestV1_3 : public ::testing::TestWithParam<DrmHalTestParam> {
+public:
+    DrmHalTestV1_3()
+        : drmFactory_(IDrmFactoryV1_3::getService(GetParam().instance_)) {}
+
+    virtual void SetUp() override {
+        ASSERT_NE(drmFactory_, nullptr);
+
+        // create plugin
+        hidl_string packageName("android.hardware.drm.V1_3.vts");
+        auto res = drmFactory_->createPlugin(
+            GetParam().scheme_, packageName,
+            [&](StatusV1_0 status, const sp<IDrmPluginV1_0>& pluginV1_0) {
+                EXPECT_EQ(StatusV1_0::OK, status);
+                drmPlugin_ = pluginV1_0;
+            });
+        EXPECT_TRUE(res.isOk());
+        ASSERT_NE(drmPlugin_, nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+protected:
+    sp<IDrmFactoryV1_3> drmFactory_;
+    sp<IDrmPluginV1_0> drmPlugin_;
+};
+
+}  // namespace vts
+}  // namespace V1_3
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
+
+#endif  // DRM_HAL_TEST_V1_3_H
diff --git a/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 1a80ecf..c04b4d0 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -22,9 +22,12 @@
 #include <log/log.h>
 
 #include <chrono>
+#include <cmath>
 #include <condition_variable>
 #include <mutex>
 
+#include <cutils/properties.h>
+
 using android::hardware::Return;
 using android::hardware::Void;
 
@@ -36,6 +39,12 @@
 using android::hardware::gnss::V1_0::IGnssMeasurement;
 using android::sp;
 
+static bool IsAutomotiveDevice() {
+    char buffer[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware.type", buffer, "");
+    return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
 #define TIMEOUT_SEC 2  // for basic commands/responses
 
 // for command line argument on how strictly to run the test
@@ -403,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.
@@ -444,9 +481,9 @@
 
   auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
   ASSERT_TRUE(gnssDebug.isOk());
-  if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
-    sp<IGnssDebug> iGnssDebug = gnssDebug;
-    EXPECT_NE(iGnssDebug, nullptr);
+  if (!IsAutomotiveDevice() && info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
+      sp<IGnssDebug> iGnssDebug = gnssDebug;
+      EXPECT_NE(iGnssDebug, nullptr);
   }
 }
 
diff --git a/gnss/1.1/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 cc34290..369a89d 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -29,6 +29,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..88fbff8 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) {
@@ -118,19 +111,22 @@
      */
     const int kFirstGnssLocationTimeoutSeconds = 75;
 
-    wait(kFirstGnssLocationTimeoutSeconds);
-    EXPECT_EQ(location_called_count_, 1);
+    EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+                                                 kFirstGnssLocationTimeoutSeconds));
+    int 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);
 }
@@ -145,12 +141,14 @@
     EXPECT_TRUE(StartAndCheckFirstLocation());
 
     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 +172,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 +216,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..88b7723 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;
     };
 
     /*
@@ -160,29 +148,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 503e419..8530ffb 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -18,9 +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;
 
@@ -33,24 +33,30 @@
 using android::hardware::gnss::V1_1::IGnssConfiguration;
 using android::hardware::gnss::V1_1::IGnssMeasurement;
 
+static bool IsAutomotiveDevice() {
+    char buffer[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware.type", buffer, "");
+    return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
 /*
  * SetupTeardownCreateCleanup:
  * Requests the gnss HAL then calls cleanup
  *
  * 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.
@@ -65,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;
@@ -78,8 +84,10 @@
     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);
@@ -93,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);
         }
     }
 
@@ -127,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;
 
@@ -213,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;
@@ -222,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
@@ -235,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.
@@ -260,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) &&
@@ -295,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) &&
@@ -339,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();
@@ -365,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) &&
@@ -400,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;
@@ -427,6 +467,7 @@
     sources.resize(1);
     sources[0] = source_to_blacklist;
 
+    // setBlacklist when location is still on
     auto result = gnss_configuration_hal->setBlacklist(sources);
     ASSERT_TRUE(result.isOk());
     EXPECT_TRUE(result);
@@ -435,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) &&
@@ -465,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);
@@ -484,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 (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/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..d778d50 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;
 
@@ -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..d8ffd59 100644
--- a/gnss/2.0/default/GnssMeasurement.h
+++ b/gnss/2.0/default/GnssMeasurement.h
@@ -59,7 +59,6 @@
    private:
     void start();
     void stop();
-    GnssData getMockMeasurement();
     void reportMeasurement(const GnssData&);
 
     static sp<IGnssMeasurementCallback> sCallback;
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 14ae43c..b3a3203 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();
@@ -98,7 +102,6 @@
 
     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.
@@ -147,6 +150,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 90a7866..55dc1bc 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;
@@ -48,72 +45,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:
@@ -122,11 +60,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;
@@ -169,7 +107,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;
@@ -192,7 +130,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;
@@ -243,6 +181,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
      */
@@ -252,61 +196,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 39736cc..53f5b9e 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;
 
@@ -51,13 +52,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();
@@ -80,7 +81,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;
@@ -96,7 +97,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;
@@ -111,7 +112,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;
@@ -130,7 +131,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;
@@ -148,7 +149,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;
@@ -180,7 +181,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();
@@ -234,7 +239,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;
@@ -258,7 +263,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);
@@ -269,7 +274,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;
@@ -290,7 +295,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;
     }
@@ -318,7 +329,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;
     }
@@ -348,7 +359,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();
@@ -383,7 +394,7 @@
     iGnssMeasurement->close();
 }
 
-TEST_F(GnssHalTest, TestGnssLocationElapsedRealtime) {
+TEST_P(GnssHalTest, TestGnssLocationElapsedRealtime) {
     StartAndCheckFirstLocation();
 
     ASSERT_TRUE((int)gnss_cb_->last_location_.elapsedRealtime.flags <=
@@ -399,7 +410,7 @@
 }
 
 // This test only verify that injectBestLocation_2_0 does not crash.
-TEST_F(GnssHalTest, TestInjectBestLocation_2_0) {
+TEST_P(GnssHalTest, TestInjectBestLocation_2_0) {
     StartAndCheckFirstLocation();
     gnss_hal_->injectBestLocation_2_0(gnss_cb_->last_location_);
     StopAndClearLocations();
@@ -410,7 +421,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());
 }
@@ -422,7 +433,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;
@@ -453,18 +464,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(
@@ -513,7 +524,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;
@@ -599,7 +610,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.");
@@ -626,7 +642,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);
@@ -744,7 +760,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, BlacklistConstellation) {
+TEST_P(GnssHalTest, BlacklistConstellation) {
+    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;
diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp
new file mode 100644
index 0000000..2122399
--- /dev/null
+++ b/gnss/2.1/Android.bp
@@ -0,0 +1,29 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.gnss@2.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IGnss.hal",
+        "IGnssAntennaInfo.hal",
+        "IGnssAntennaInfoCallback.hal",
+        "IGnssCallback.hal",
+        "IGnssMeasurement.hal",
+        "IGnssMeasurementCallback.hal",
+        "IGnssConfiguration.hal",
+    ],
+    interfaces: [
+        "android.hardware.gnss.measurement_corrections@1.1",
+        "android.hardware.gnss.measurement_corrections@1.0",
+        "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,
+}
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..0e6abbd
--- /dev/null
+++ b/gnss/2.1/IGnssMeasurementCallback.hal
@@ -0,0 +1,182 @@
+/*
+ * 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 receiver inter-signal bias is stored in the data structure.
+         */
+        HAS_RECEIVER_ISB = 1 << 16,
+        /**
+         * A valid receiver inter-signal bias uncertainty is stored in the data structure.
+         */
+        HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17,
+        /**
+         * A valid satellite inter-signal bias is stored in the data structure.
+         */
+        HAS_SATELLITE_ISB = 1 << 18,
+        /**
+         * A valid satellite inter-signal bias uncertainty is stored in the data structure.
+         */
+        HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19,
+    };
+
+    /**
+     * Extends a GNSS Measurement, adding basebandCN0DbHz, GnssMeasurementFlags,
+     * receiverInterSignalBiasNs, receiverInterSignalBiasUncertaintyNs, satelliteInterSignalBiasNs
+     * 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 receiver inter-signal bias (ISB) in nanoseconds.
+         *
+         * This value is the estimated receiver-side inter-system (different from the constellation
+         * in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different from the
+         * carrier frequency in GnssClock.referenceSignalTypeForIsb) bias. The reported receiver ISB
+         * must include signal delays caused by
+         *
+         * - Receiver inter-constellation bias
+         * - Receiver inter-frequency bias
+         * - Receiver inter-code bias
+         *
+         * The value does not include the inter-frequency Ionospheric bias.
+         *
+         * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
+         */
+        double receiverInterSignalBiasNs;
+
+        /**
+         * 1-sigma uncertainty associated with the receiver inter-signal bias in nanoseconds.
+         */
+        double receiverInterSignalBiasUncertaintyNs;
+
+        /**
+         * The satellite inter-signal bias in nanoseconds.
+         *
+         * This value is the satellite-and-control-segment-side inter-system (different from the
+         * constellation in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different
+         * from the carrier frequency in GnssClock.referenceSignalTypeForIsb) bias, including:
+         *
+         * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps),
+         *   BDS-GLO Time Offset (BGTO))
+         * - Group delay (e.g., Total Group Delay (TGD))
+         * - Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only),
+         *   and satellite inter-code bias (e.g., Differential Code Bias (DCB)).
+         *
+         * The receiver ISB of GnssClock.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..d32a0af
--- /dev/null
+++ b/gnss/2.1/default/GnssAntennaInfo.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssAntennaInfo"
+
+#include "GnssAntennaInfo.h"
+#include "Utils.h"
+
+#include <log/log.h>
+
+using ::android::hardware::gnss::common::Utils;
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+sp<IGnssAntennaInfoCallback> GnssAntennaInfo::sCallback = nullptr;
+
+GnssAntennaInfo::GnssAntennaInfo() : mMinIntervalMillis(1000) {}
+
+GnssAntennaInfo::~GnssAntennaInfo() {
+    stop();
+}
+
+// Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow.
+Return<GnssAntennaInfo::GnssAntennaInfoStatus> GnssAntennaInfo::setCallback(
+        const sp<IGnssAntennaInfoCallback>& callback) {
+    ALOGD("setCallback");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback = callback;
+
+    if (mIsActive) {
+        ALOGW("GnssAntennaInfo callback already set. Resetting the callback...");
+        stop();
+    }
+    start();
+
+    return GnssAntennaInfoStatus::SUCCESS;
+}
+
+Return<void> GnssAntennaInfo::close() {
+    ALOGD("close");
+    std::unique_lock<std::mutex> lock(mMutex);
+    stop();
+    sCallback = nullptr;
+    return Void();
+}
+
+// Private methods
+void GnssAntennaInfo::start() {
+    ALOGD("start");
+    mIsActive = true;
+    mThread = std::thread([this]() {
+        while (mIsActive == true) {
+            if (sCallback != nullptr) {
+                auto antennaInfos = Utils::getMockAntennaInfos();
+                this->reportAntennaInfo(antennaInfos);
+            }
+
+            /** For mock implementation this is good. On real device, we should only report
+                antennaInfo at start and when there is a configuration change. **/
+            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
+        }
+    });
+}
+
+void GnssAntennaInfo::stop() {
+    ALOGD("stop");
+    mIsActive = false;
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+}
+
+void GnssAntennaInfo::reportAntennaInfo(
+        const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+
+    if (sCallback == nullptr) {
+        ALOGE("%s: No non-null callback", __func__);
+        return;
+    }
+
+    auto ret = sCallback->gnssAntennaInfoCb(antennaInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/gnss/2.1/default/GnssAntennaInfo.h b/gnss/2.1/default/GnssAntennaInfo.h
new file mode 100644
index 0000000..f4bfd24
--- /dev/null
+++ b/gnss/2.1/default/GnssAntennaInfo.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
+#define ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
+
+#include <android/hardware/gnss/2.1/IGnssAntennaInfo.h>
+
+#include <mutex>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct GnssAntennaInfo : public IGnssAntennaInfo {
+    GnssAntennaInfo();
+    ~GnssAntennaInfo();
+
+    // Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow.
+    Return<GnssAntennaInfoStatus> setCallback(
+            const sp<IGnssAntennaInfoCallback>& callback) override;
+    Return<void> close() override;
+
+  private:
+    void start();
+    void stop();
+    void reportAntennaInfo(
+            const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const;
+
+    static sp<IGnssAntennaInfoCallback> sCallback;
+    std::atomic<long> mMinIntervalMillis;
+    std::atomic<bool> mIsActive;
+    std::thread mThread;
+    mutable std::mutex mMutex;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
\ No newline at end of file
diff --git a/gnss/2.1/default/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..34e20e5
--- /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");
+    std::unique_lock<std::mutex> lock(mMutex);
+    stop();
+    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..3ed7bc5
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurement.h
@@ -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.
+ */
+
+#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&);
+
+    static sp<V2_1::IGnssMeasurementCallback> sCallback_2_1;
+    static sp<V2_0::IGnssMeasurementCallback> sCallback_2_0;
+    std::atomic<long> mMinIntervalMillis;
+    std::atomic<bool> mIsActive;
+    std::thread mThread;
+    mutable std::mutex mMutex;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
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..7b054c0
--- /dev/null
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -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.
+ */
+
+#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 if HAS_INTER_SIGNAL_BIAS is true.
+ */
+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_RECEIVER_ISB) > 0) &&
+            ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_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.receiverInterSignalBiasNs) < 1.0e6);
+            ASSERT_TRUE(measurement.receiverInterSignalBiasUncertaintyNs >= 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);
+
+    hidl_vec<IGnssCallback_2_1::GnssSvInfo> last_sv_info_list;
+    ASSERT_TRUE(gnss_cb_->sv_info_list_cbq_.retrieve(last_sv_info_list, 1));
+
+    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);
+}
\ No newline at end of file
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..2e5b873 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_RECEIVER_ISB |
+                                GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB_UNCERTAINTY |
+                                GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB |
+                                GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB_UNCERTAINTY),
+            .receiverInterSignalBiasNs = 10.0,
+            .receiverInterSignalBiasUncertaintyNs = 100.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 1988171..fd9613b 100644
--- a/gnss/common/utils/vts/Android.bp
+++ b/gnss/common/utils/vts/Android.bp
@@ -30,6 +30,7 @@
     shared_libs: [
         "android.hardware.gnss@1.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 51d3ea1..4b5a50f 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -22,7 +22,9 @@
 namespace gnss {
 namespace common {
 
-using V1_0::GnssConstellationType;
+using GnssConstellationType_V1_0 = V1_0::GnssConstellationType;
+using GnssConstellationType_V2_0 = V2_0::GnssConstellationType;
+
 using V1_0::GnssLocationFlags;
 
 void Utils::checkLocation(const GnssLocation& location, bool check_speed,
@@ -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;
+}
+
 }  // namespace common
 }  // namespace gnss
 }  // namespace hardware
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 dce4c7b..c3cdd18 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -19,10 +19,21 @@
 
 #include <android/hardware/gnss/1.0/IGnss.h>
 #include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
 
 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 {
@@ -31,7 +42,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();
 };
 
 }  // namespace common
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..d279af6
--- /dev/null
+++ b/gnss/measurement_corrections/1.1/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.gnss.measurement_corrections@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IMeasurementCorrections.hal",
+    ],
+    interfaces: [
+        "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss@2.0",
+        "android.hardware.gnss@1.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/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
new file mode 100644
index 0000000..601cabc
--- /dev/null
+++ b/graphics/common/aidl/Android.bp
@@ -0,0 +1,24 @@
+aidl_interface {
+    name: "android.hardware.graphics.common",
+    host_supported: true,
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "android/hardware/graphics/common/*.aidl",
+    ],
+    stability: "vintf",
+    imports: [
+        "android.hardware.common",
+    ],
+    backend: {
+        java: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
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/BufferUsage.aidl b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
new file mode 100644
index 0000000..5f9888a
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/BufferUsage.aidl
@@ -0,0 +1,114 @@
+/*
+ * 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.common;
+
+/**
+ * Buffer usage definitions.
+ */
+@VintfStability
+@Backing(type="long")
+enum BufferUsage {
+    /** bit 0-3 is an enum */
+    CPU_READ_MASK                      = 0xf,
+    /** buffer is never read by CPU */
+    CPU_READ_NEVER                     = 0,
+    /** buffer is rarely read by CPU */
+    CPU_READ_RARELY                    = 2,
+    /** buffer is often read by CPU */
+    CPU_READ_OFTEN                     = 3,
+
+    /** bit 4-7 is an enum */
+    CPU_WRITE_MASK                     = 0xf << 4,
+    /** buffer is never written by CPU */
+    CPU_WRITE_NEVER                    = 0 << 4,
+    /** buffer is rarely written by CPU */
+    CPU_WRITE_RARELY                   = 2 << 4,
+    /** buffer is often written by CPU */
+    CPU_WRITE_OFTEN                    = 3 << 4,
+
+    /** buffer is used as a GPU texture */
+    GPU_TEXTURE                        = 1 << 8,
+
+    /** buffer is used as a GPU render target */
+    GPU_RENDER_TARGET                  = 1 << 9,
+
+    /** bit 10 must be zero */
+
+    /** buffer is used as a composer HAL overlay layer */
+    COMPOSER_OVERLAY                   = 1 << 11,
+    /** buffer is used as a composer HAL client target */
+    COMPOSER_CLIENT_TARGET             = 1 << 12,
+
+    /** bit 13 must be zero */
+
+    /**
+     * Buffer is allocated with hardware-level protection against copying the
+     * contents (or information derived from the contents) into unprotected
+     * memory.
+     */
+    PROTECTED                          = 1 << 14,
+
+    /** buffer is used as a hwcomposer HAL cursor layer */
+    COMPOSER_CURSOR                    = 1 << 15,
+
+    /** buffer is used as a video encoder input */
+    VIDEO_ENCODER                      = 1 << 16,
+
+    /** buffer is used as a camera HAL output */
+    CAMERA_OUTPUT                      = 1 << 17,
+
+    /** buffer is used as a camera HAL input */
+    CAMERA_INPUT                       = 1 << 18,
+
+    /** bit 19 must be zero */
+
+    /** buffer is used as a renderscript allocation */
+    RENDERSCRIPT                       = 1 << 20,
+
+    /** bit 21 must be zero */
+
+    /** buffer is used as a video decoder output */
+    VIDEO_DECODER                      = 1 << 22,
+
+    /** buffer is used as a sensor direct report output */
+    SENSOR_DIRECT_DATA                 = 1 << 23,
+
+    /** buffer is used as a cube map texture */
+    GPU_CUBE_MAP                       = 1 << 25,
+
+    /** buffer contains a complete mipmap hierarchy */
+    GPU_MIPMAP_COMPLETE                = 1 << 26,
+
+    /**
+     * Buffer is used as input for HEIC encoder.
+     */
+    HW_IMAGE_ENCODER                   = 1 << 27,
+
+    /**
+     * buffer is used as as an OpenGL shader storage or uniform
+     * buffer object
+     */
+    GPU_DATA_BUFFER                    = 1 << 24,
+
+    /** bits 25-27 must be zero and are reserved for future versions */
+    /** bits 28-31 are reserved for vendor extensions */
+    VENDOR_MASK                        = 0xf << 28,
+
+    /** bits 32-47 must be zero and are reserved for future versions */
+    /** bits 48-63 are reserved for vendor extensions */
+    VENDOR_MASK_HI                     = 0xffff << 48,
+}
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/HardwareBuffer.aidl b/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
new file mode 100644
index 0000000..5a22c0f
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/HardwareBuffer.aidl
@@ -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.common;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.graphics.common.HardwareBufferDescription;
+
+/**
+ * Stable AIDL counterpart of AHardwareBuffer.
+ *
+ * @note This is different from the public HardwareBuffer.
+ * @sa +ndk libnativewindow#AHardwareBuffer
+ */
+@VintfStability
+parcelable HardwareBuffer {
+    HardwareBufferDescription description;
+    NativeHandle handle;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl b/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl
new file mode 100644
index 0000000..e1e3492
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/HardwareBufferDescription.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.common;
+
+import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.PixelFormat;
+
+/**
+ * Stable AIDL counterpart of AHardwareBuffer_Desc.
+ *
+ * @sa +ndk libnativewindow#AHardwareBuffer_Desc
+ */
+@VintfStability
+parcelable HardwareBufferDescription {
+    int width;
+    int height;
+    int layers;
+    PixelFormat format;
+    BufferUsage usage;
+    int stride;
+}
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
new file mode 100644
index 0000000..4942462
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
@@ -0,0 +1,516 @@
+/*
+ * 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.common;
+
+/**
+ * Pixel formats for graphics buffers.
+ */
+@VintfStability
+@Backing(type="int")
+enum PixelFormat {
+    /**
+     * This value may be used in an operation where the format is optional.
+     */
+    UNSPECIFIED                        = 0,
+    /**
+     * 32-bit format that has 8-bit R, G, B, and A components, in that order,
+     * from the lowest memory address to the highest memory address.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    RGBA_8888                          = 0x1,
+
+    /**
+     * 32-bit format that has 8-bit R, G, B, and unused components, in that
+     * order, from the lowest memory address to the highest memory address.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    RGBX_8888                          = 0x2,
+
+    /**
+     * 24-bit format that has 8-bit R, G, and B components, in that order,
+     * from the lowest memory address to the highest memory address.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    RGB_888                            = 0x3,
+
+    /**
+     * 16-bit packed format that has 5-bit R, 6-bit G, and 5-bit B components,
+     * in that order, from the most-sigfinicant bits to the least-significant
+     * bits.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    RGB_565                            = 0x4,
+
+    /**
+     * 32-bit format that has 8-bit B, G, R, and A components, in that order,
+     * from the lowest memory address to the highest memory address.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    BGRA_8888                          = 0x5,
+
+    /**
+     * Legacy formats deprecated in favor of YCBCR_420_888.
+     */
+    YCBCR_422_SP                       = 0x10,  // NV16
+    YCRCB_420_SP                       = 0x11,  // NV21
+    YCBCR_422_I                        = 0x14,  // YUY2
+
+    /**
+     * 64-bit format that has 16-bit R, G, B, and A components, in that order,
+     * from the lowest memory address to the highest memory address.
+     *
+     * The component values are signed floats, whose interpretation is defined
+     * by the dataspace.
+     */
+    RGBA_FP16                          = 0x16,
+
+    /**
+     * RAW16 is a single-channel, 16-bit, little endian format, typically
+     * representing raw Bayer-pattern images from an image sensor, with minimal
+     * processing.
+     *
+     * The exact pixel layout of the data in the buffer is sensor-dependent, and
+     * needs to be queried from the camera device.
+     *
+     * Generally, not all 16 bits are used; more common values are 10 or 12
+     * bits. If not all bits are used, the lower-order bits are filled first.
+     * All parameters to interpret the raw data (black and white points,
+     * color space, etc) must be queried from the camera device.
+     *
+     * This format assumes
+     * - an even width
+     * - an even height
+     * - a horizontal stride multiple of 16 pixels
+     * - a vertical stride equal to the height
+     * - strides are specified in pixels, not in bytes
+     *
+     *   size = stride * height * 2
+     *
+     * This format must be accepted by the allocator when used with the
+     * following usage flags:
+     *
+     *    - BufferUsage::CAMERA_*
+     *    - BufferUsage::CPU_*
+     *    - BufferUsage::RENDERSCRIPT
+     *
+     * The mapping of the dataspace to buffer contents for RAW16 is as
+     * follows:
+     *
+     *  Dataspace value               | Buffer contents
+     * -------------------------------+-----------------------------------------
+     *  Dataspace::ARBITRARY          | Raw image sensor data, layout is as
+     *                                | defined above.
+     *  Dataspace::DEPTH              | Unprocessed implementation-dependent raw
+     *                                | depth measurements, opaque with 16 bit
+     *                                | samples.
+     *  Other                         | Unsupported
+     */
+    RAW16                              = 0x20,
+
+    /**
+     * BLOB is used to carry task-specific data which does not have a standard
+     * image structure. The details of the format are left to the two
+     * endpoints.
+     *
+     * A typical use case is for transporting JPEG-compressed images from the
+     * Camera HAL to the framework or to applications.
+     *
+     * Buffers of this format must have a height of 1, and width equal to their
+     * size in bytes.
+     *
+     * The mapping of the dataspace to buffer contents for BLOB is as
+     * follows:
+     *
+     *  Dataspace value               | Buffer contents
+     * -------------------------------+-----------------------------------------
+     *  Dataspace::JFIF               | An encoded JPEG image
+     *  Dataspace::DEPTH              | An android_depth_points buffer
+     *  Dataspace::SENSOR             | Sensor event data.
+     *  Other                         | Unsupported
+     */
+    BLOB                               = 0x21,
+
+    /**
+     * A format indicating that the choice of format is entirely up to the
+     * allocator.
+     *
+     * The allocator should examine the usage bits passed in when allocating a
+     * buffer with this format, and it should derive the pixel format from
+     * those usage flags. This format must never be used with any of the
+     * BufferUsage::CPU_* usage flags.
+     *
+     * Even when the internally chosen format has an alpha component, the
+     * clients must assume the alpha vlaue to be 1.0.
+     *
+     * The interpretation of the component values is defined by the dataspace.
+     */
+    IMPLEMENTATION_DEFINED             = 0x22,
+
+    /**
+     * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0
+     * buffer layout, while still describing the general format in a
+     * layout-independent manner. While called YCbCr, it can be used to
+     * describe formats with either chromatic ordering, as well as
+     * whole planar or semiplanar layouts.
+     *
+     * This format must be accepted by the allocator when BufferUsage::CPU_*
+     * are set.
+     *
+     * Buffers with this format must be locked with IMapper::lockYCbCr.
+     * Locking with IMapper::lock must return an error.
+     *
+     * The interpretation of the component values is defined by the dataspace.
+     */
+    YCBCR_420_888                      = 0x23,
+
+    /**
+     * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
+     * image sensor. The actual structure of buffers of this format is
+     * implementation-dependent.
+     *
+     * This format must be accepted by the allocator when used with the
+     * following usage flags:
+     *
+     *    - BufferUsage::CAMERA_*
+     *    - BufferUsage::CPU_*
+     *    - BufferUsage::RENDERSCRIPT
+     *
+     * The mapping of the dataspace to buffer contents for RAW_OPAQUE is as
+     * follows:
+     *
+     *  Dataspace value               | Buffer contents
+     * -------------------------------+-----------------------------------------
+     *  Dataspace::ARBITRARY          | Raw image sensor data.
+     *  Other                         | Unsupported
+     */
+    RAW_OPAQUE                         = 0x24,
+
+    /**
+     * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
+     * unprocessed format, usually representing raw Bayer-pattern images coming from
+     * an image sensor.
+     *
+     * In an image buffer with this format, starting from the first pixel of each
+     * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
+     * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
+     * contains the 2 least significant bits of the 4 pixels, the exact layout data
+     * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
+     * bit of the ith pixel):
+     *
+     *          bit 7                                     bit 0
+     *          =====|=====|=====|=====|=====|=====|=====|=====|
+     * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
+     *          ===============================================
+     *
+     * This format assumes
+     * - a width multiple of 4 pixels
+     * - an even height
+     * - a vertical stride equal to the height
+     * - strides are specified in bytes, not in pixels
+     *
+     *   size = stride * height
+     *
+     * When stride is equal to width * (10 / 8), there will be no padding bytes at
+     * the end of each row, the entire image data is densely packed. When stride is
+     * larger than width * (10 / 8), padding bytes will be present at the end of each
+     * row (including the last row).
+     *
+     * This format must be accepted by the allocator when used with the
+     * following usage flags:
+     *
+     *    - BufferUsage::CAMERA_*
+     *    - BufferUsage::CPU_*
+     *    - BufferUsage::RENDERSCRIPT
+     *
+     * The mapping of the dataspace to buffer contents for RAW10 is as
+     * follows:
+     *
+     *  Dataspace value               | Buffer contents
+     * -------------------------------+-----------------------------------------
+     *  Dataspace::ARBITRARY          | Raw image sensor data.
+     *  Other                         | Unsupported
+     */
+    RAW10                              = 0x25,
+
+    /**
+     * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row,
+     * unprocessed format, usually representing raw Bayer-pattern images coming from
+     * an image sensor.
+     *
+     * In an image buffer with this format, starting from the first pixel of each
+     * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
+     * and second byte contains the top 8 bits of first and second pixel. The third
+     * byte contains the 4 least significant bits of the two pixels, the exact layout
+     * data for each two consecutive pixels is illustrated below (Pi[j] stands for
+     * the jth bit of the ith pixel):
+     *
+     *           bit 7                                            bit 0
+     *          ======|======|======|======|======|======|======|======|
+     * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]|
+     *         |------|------|------|------|------|------|------|------|
+     * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]|
+     *         |------|------|------|------|------|------|------|------|
+     * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]|
+     *          =======================================================
+     *
+     * This format assumes:
+     * - a width multiple of 4 pixels
+     * - an even height
+     * - a vertical stride equal to the height
+     * - strides are specified in bytes, not in pixels
+     *
+     *   size = stride * height
+     *
+     * When stride is equal to width * (12 / 8), there will be no padding bytes at
+     * the end of each row, the entire image data is densely packed. When stride is
+     * larger than width * (12 / 8), padding bytes will be present at the end of
+     * each row (including the last row).
+     *
+     * This format must be accepted by the allocator when used with the
+     * following usage flags:
+     *
+     *    - BufferUsage::CAMERA_*
+     *    - BufferUsage::CPU_*
+     *    - BufferUsage::RENDERSCRIPT
+     *
+     * The mapping of the dataspace to buffer contents for RAW12 is as
+     * follows:
+     *
+     *  Dataspace value               | Buffer contents
+     * -------------------------------+-----------------------------------------
+     *  Dataspace::ARBITRARY          | Raw image sensor data.
+     *  Other                         | Unsupported
+     */
+    RAW12                              = 0x26,
+
+    /** 0x27 to 0x2A are reserved for flexible formats */
+
+    /**
+     * 32-bit packed format that has 2-bit A, 10-bit B, G, and R components,
+     * in that order, from the most-sigfinicant bits to the least-significant
+     * bits.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    RGBA_1010102                       = 0x2B,
+
+    /**
+     * 0x100 - 0x1FF
+     *
+     * 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.
+     */
+
+    /**
+     * Y8 is a YUV planar format comprised of a WxH Y plane, with each pixel
+     * being represented by 8 bits. It is equivalent to just the Y plane from
+     * YV12.
+     *
+     * This format assumes
+     * - an even width
+     * - an even height
+     * - a horizontal stride multiple of 16 pixels
+     * - a vertical stride equal to the height
+     *
+     *   size = stride * height
+     *
+     * This format must be accepted by the allocator when used with the
+     * following usage flags:
+     *
+     *    - BufferUsage::CAMERA_*
+     *    - BufferUsage::CPU_*
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    Y8                                 = 0x20203859,
+
+    /**
+     * Y16 is a YUV planar format comprised of a WxH Y plane, with each pixel
+     * being represented by 16 bits. It is just like Y8, but has double the
+     * bits per pixel (little endian).
+     *
+     * This format assumes
+     * - an even width
+     * - an even height
+     * - a horizontal stride multiple of 16 pixels
+     * - a vertical stride equal to the height
+     * - strides are specified in pixels, not in bytes
+     *
+     *   size = stride * height * 2
+     *
+     * This format must be accepted by the allocator when used with the
+     * following usage flags:
+     *
+     *    - BufferUsage::CAMERA_*
+     *    - BufferUsage::CPU_*
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace. When the dataspace is
+     * Dataspace::DEPTH, each pixel is a distance value measured by a depth
+     * camera, plus an associated confidence value.
+     */
+    Y16                                = 0x20363159,
+
+    /**
+     * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed
+     * by (W/2) x (H/2) Cr and Cb planes.
+     *
+     * This format assumes
+     * - an even width
+     * - an even height
+     * - a horizontal stride multiple of 16 pixels
+     * - a vertical stride equal to the height
+     *
+     *   y_size = stride * height
+     *   c_stride = ALIGN(stride/2, 16)
+     *   c_size = c_stride * height/2
+     *   size = y_size + c_size * 2
+     *   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:
+     *
+     *    - BufferUsage::CAMERA_*
+     *    - BufferUsage::CPU_*
+     *    - BufferUsage::GPU_TEXTURE
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    YV12                               = 0x32315659, // YCrCb 4:2:0 Planar
+
+    /**
+     * 16-bit format that has a single 16-bit depth component.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    DEPTH_16                           = 0x30,
+
+    /**
+     * 32-bit format that has a single 24-bit depth component and, optionally,
+     * 8 bits that are unused.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    DEPTH_24                           = 0x31,
+
+    /**
+     * 32-bit format that has a 24-bit depth component and an 8-bit stencil
+     * component packed into 32-bits.
+     *
+     * The depth component values are unsigned normalized to the range [0, 1],
+     * whose interpretation is defined by the dataspace. The stencil values are
+     * unsigned integers, whose interpretation is defined by the dataspace.
+     */
+    DEPTH_24_STENCIL_8                 = 0x32,
+
+    /**
+     * 32-bit format that has a single 32-bit depth component.
+     *
+     * The component values are signed floats, whose interpretation is defined
+     * by the dataspace.
+     */
+    DEPTH_32F                          = 0x33,
+
+    /**
+     * Two-component format that has a 32-bit depth component, an 8-bit stencil
+     * component, and optionally 24-bits unused.
+     *
+     * The depth component values are signed floats, whose interpretation is
+     * defined by the dataspace. The stencil bits are unsigned integers, whose
+     * interpretation is defined by the dataspace.
+     */
+    DEPTH_32F_STENCIL_8                = 0x34,
+
+    /**
+     * 8-bit format that has a single 8-bit stencil component.
+     *
+     * The component values are unsigned integers, whose interpretation is
+     * defined by the dataspace.
+     */
+    STENCIL_8                          = 0x35,
+
+    /**
+     * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
+     * followed immediately by a Wx(H/2) CbCr plane. Each sample is
+     * represented by a 16-bit little-endian value, with the lower 6 bits set
+     * to zero.
+     *
+     * This format assumes
+     * - an even height
+     * - a vertical stride equal to the height
+     *
+     *   stride_in_bytes = stride * 2
+     *   y_size = stride_in_bytes * height
+     *   cbcr_size = stride_in_bytes * (height / 2)
+     *   cb_offset = y_size
+     *   cr_offset = cb_offset + 2
+     *
+     * This format must be accepted by the allocator when used with the
+     * following usage flags:
+     *
+     *    - BufferUsage::VIDEO_*
+     *    - BufferUsage::CPU_*
+     *    - BufferUsage::GPU_TEXTURE
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     *
+     * This format is appropriate for 10bit video content.
+     *
+     * Buffers with this format must be locked with IMapper::lockYCbCr
+     * or with IMapper::lock.
+     */
+    YCBCR_P010                         = 0x36,
+
+    /**
+     * 24-bit format that has 8-bit H, S, and V components, in that order,
+     * from the lowest memory address to the highest memory address.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+    */
+    HSV_888                            = 0x37,
+}
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..ccb0690
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
@@ -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.
+ */
+
+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.
+     *
+     * These fields indicate the number of horizontally or vertically adjacent pixels that use
+     * the same pixel data. A value of 1 indicates no subsampling.
+     */
+    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..3fca53b
--- /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.PlaneLayoutComponent 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..5f1ed63 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -27,15 +27,21 @@
     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@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",
+        "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/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..e38af00 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -24,13 +24,20 @@
 
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
+        "libEGL",
+        "libGLESv1_CM",
+        "libGLESv2",
         "libfmq",
+        "libgui",
         "libhidlbase",
+        "libprocessgroup",
         "libsync",
+        "libui",
     ],
     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",
@@ -42,10 +49,18 @@
         "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",
+        "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..fa4823e 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -28,6 +28,7 @@
     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",
@@ -40,10 +41,14 @@
         "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",
+        "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..5f700be
--- /dev/null
+++ b/graphics/composer/2.4/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.composer@2.4",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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..937af3d
--- /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",
+    ],
+    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",
+        "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",
+        "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..7a00ed2
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -0,0 +1,684 @@
+/*
+ * 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()); }
+
+    void Test_setActiveConfigWithConstraints(
+            const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss);
+
+    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(GraphicsComposerHidlTest, 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);
+                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) {
+    // 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();
+    if (mReader->mCompositionChanges.size() != 0) {
+        GTEST_SUCCEED() << "Composition change requested, skipping test";
+        return;
+    }
+
+    ASSERT_EQ(0, mReader->mErrors.size());
+    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->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 IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss) {
+    VsyncPeriodChangeTimeline timeline = {};
+
+    for (Display display : mComposerCallback->getDisplays()) {
+        forEachTwoConfigs(display, [&](Config config1, Config config2) {
+            mComposerClient->setActiveConfig(display, config1);
+
+            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
+            }
+
+            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 (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 newTimelime = mComposerCallback->takeLastVsyncPeriodChangeTimeline();
+            if (timeline.refreshRequired && refreshMiss) {
+                EXPECT_TRUE(newTimelime.has_value());
+            }
+
+            if (newTimelime.has_value()) {
+                if (timeline.refreshRequired) {
+                    sendRefreshFrame(newTimelime.value());
+                }
+                waitForVsyncPeriodChange(display, newTimelime.value(), constraints.desiredTimeNanos,
+                                         vsyncPeriod1, vsyncPeriod2);
+            }
+
+            VsyncPeriodNanos vsyncPeriodNanos;
+            EXPECT_EQ(Error::NONE,
+                      mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+            EXPECT_EQ(vsyncPeriodNanos, vsyncPeriod2);
+        });
+    }
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints) {
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime();
+    Test_setActiveConfigWithConstraints(constraints, false);
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_Delayed) {
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constexpr nsecs_t kDelayForChange = 300'000'000;  // 300ms
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime() + kDelayForChange;
+    Test_setActiveConfigWithConstraints(constraints, false);
+}
+
+TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_MissRefresh) {
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime();
+    Test_setActiveConfigWithConstraints(constraints, 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/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..96f6d51
--- /dev/null
+++ b/graphics/mapper/4.0/utils/OWNERS
@@ -0,0 +1,3 @@
+# Graphics team
+marissaw@google.com
+stoza@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..cb90fa0
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -0,0 +1,350 @@
+/*
+ * 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) {
+    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,
+                                                      bool allowFailure, 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) {
+                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) {
+                        if (allowFailure) {
+                            bufferHandle = importBuffer(tmpBuffers[i]);
+                        } else {
+                            ASSERT_NO_FATAL_FAILURE(bufferHandle = importBuffer(tmpBuffers[i]));
+                        }
+                    } else {
+                        if (allowFailure) {
+                            bufferHandle = cloneBuffer(tmpBuffers[i]);
+                        } else {
+                            ASSERT_NO_FATAL_FAILURE(bufferHandle = cloneBuffer(tmpBuffers[i]));
+                        }
+                    }
+                    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, bool allowFailure, uint32_t* outStride) {
+    BufferDescriptor descriptor = createDescriptor(descriptorInfo);
+    if (::testing::Test::HasFatalFailure()) {
+        return nullptr;
+    }
+
+    auto buffers = allocate(descriptor, 1, import, allowFailure, 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) {
+    const native_handle_t* bufferHandle = nullptr;
+    mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+        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..cd40aa4
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -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.
+ */
+
+#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:
+    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, bool allowFailure = false,
+                                                 uint32_t* outStride = nullptr);
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import = true, bool allowFailure = false,
+                                    uint32_t* outStride = nullptr);
+
+    // IMapper methods
+
+    sp<IMapper> getMapper() const;
+
+    BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
+    const native_handle_t* importBuffer(const hidl_handle& rawHandle);
+    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:
+    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);
+
+    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..96f6d51
--- /dev/null
+++ b/graphics/mapper/4.0/vts/OWNERS
@@ -0,0 +1,3 @@
+# Graphics team
+marissaw@google.com
+stoza@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..6cc5e34
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -0,0 +1,2204 @@
+/*
+ * 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/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::hardware::graphics::common::V1_2::BufferUsage;
+using android::hardware::graphics::common::V1_2::PixelFormat;
+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 verifyDummyDescriptorInfoPlaneLayouts(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) {
+        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(32, 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 (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(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes,
+                        uint32_t seed = 0) {
+        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;
+        }
+    }
+
+    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, false, &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, false, &stride));
+
+    // lock buffer for writing
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    int fence = -1;
+    uint8_t* data;
+    ASSERT_NO_FATAL_FAILURE(
+            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+
+    // RGBA_8888
+    fillRGBA8888(data, info.height, stride * 4, info.width * 4);
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(
+            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+    ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(data, info.height, stride * 4, info.width * 4));
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+    if (fence >= 0) {
+        close(fence);
+    }
+}
+
+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, false, &stride));
+
+    // lock buffer for writing
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    int fence = -1;
+    uint8_t* data;
+
+    ASSERT_NO_FATAL_FAILURE(
+            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+
+    android_ycbcr yCbCr;
+    ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(bufferHandle, data, &yCbCr));
+
+    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 < info.height; y++) {
+        for (uint32_t x = 0; x < info.width; x++) {
+            auto val = static_cast<uint8_t>(info.height * y + x);
+
+            yData[yStride * y + x] = val;
+
+            if (y % chromaStep && x % chromaStep == 0) {
+                cbData[cStride * y / chromaStep + x / chromaStep] = val;
+                crData[cStride * y / chromaStep + x / chromaStep] = val;
+            }
+        }
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(
+            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
+
+    ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(bufferHandle, data, &yCbCr));
+
+    yData = static_cast<uint8_t*>(yCbCr.y);
+    cbData = static_cast<uint8_t*>(yCbCr.cb);
+    crData = static_cast<uint8_t*>(yCbCr.cr);
+    for (uint32_t y = 0; y < info.height; y++) {
+        for (uint32_t x = 0; x < info.width; x++) {
+            auto val = static_cast<uint8_t>(info.height * y + x);
+
+            EXPECT_EQ(val, yData[yStride * y + x]);
+
+            if (y % chromaStep == 0 && x % chromaStep == 0) {
+                EXPECT_EQ(val, cbData[cStride * y / chromaStep + x / chromaStep]);
+                EXPECT_EQ(val, crData[cStride * y / chromaStep + x / chromaStep]);
+            }
+        }
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+    if (fence >= 0) {
+        close(fence);
+    }
+}
+
+/**
+ * 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, false, &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);
+
+    int fence;
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->flushLockedBuffer(writeBufferHandle));
+    if (fence >= 0) {
+        ASSERT_EQ(0, sync_wait(fence, 3500));
+        close(fence);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(mGralloc->rereadLockedBuffer(readBufferHandle));
+
+    ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(readData, info.height, stride * 4, info.width * 4));
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(readBufferHandle));
+    if (fence >= 0) {
+        close(fence);
+    }
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(writeBufferHandle));
+    if (fence >= 0) {
+        close(fence);
+    }
+}
+
+/**
+ * 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, true);
+    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(verifyDummyDescriptorInfoPlaneLayouts(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, true);
+    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 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;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   info, gralloc4::MetadataType_ProtectedContent, &vec));
+
+    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;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   info, gralloc4::MetadataType_Compression, &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::getFromBufferDescriptorInfo(Interlaced)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoInterlaced) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Interlaced, &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::getFromBufferDescriptorInfo(ChromaSiting)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoChromaSiting) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                    gralloc4::MetadataType_ChromaSiting, &vec));
+
+    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;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                    gralloc4::MetadataType_PlaneLayouts, &vec));
+
+    std::vector<PlaneLayout> planeLayouts;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+    ASSERT_NO_FATAL_FAILURE(verifyDummyDescriptorInfoPlaneLayouts(planeLayouts));
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Crop)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCrop) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::RGBA_8888;
+    info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getFromBufferDescriptorInfo(info, gralloc4::MetadataType_Crop, &vec));
+
+    std::vector<aidl::android::hardware::graphics::common::Rect> crops;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeCrop(vec, &crops));
+    EXPECT_EQ(1, crops.size());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Dataspace)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoDataspace) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Dataspace, &vec));
+
+    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;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_BlendMode, &vec));
+
+    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;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, &vec));
+
+    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;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, &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::getFromBufferDescriptorInfo(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2094_40) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                    gralloc4::MetadataType_Smpte2094_40, &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::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&) { err = tmpError; });
+        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/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/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/media/c2/1.1/Android.bp b/media/c2/1.1/Android.bp
new file mode 100644
index 0000000..c3e30b2
--- /dev/null
+++ b/media/c2/1.1/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.media.c2@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index a14b86b..30530be 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -216,7 +216,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:
@@ -482,15 +482,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/IDevice.hal b/neuralnetworks/1.3/IDevice.hal
index 79f9c32..e0b04a8 100644
--- a/neuralnetworks/1.3/IDevice.hal
+++ b/neuralnetworks/1.3/IDevice.hal
@@ -48,19 +48,6 @@
     getCapabilities_1_3() generates (ErrorStatus status, Capabilities capabilities);
 
     /**
-     * Returns whether the device is able to complete or abort a task within a
-     * specified duration.
-     *
-     * @return prepareModelDeadline 'true' if the device supports completing or
-     *     aborting model preparation by the deadline when the deadline is supplied,
-     *     'false' otherwise.
-     * @return executionDeadline 'true' if the device supports completing or
-     *     aborting an execution by the deadline when the deadline is supplied,
-     *     'false' otherwise.
-     */
-    supportsDeadlines() generates (bool prepareModelDeadline, bool executionDeadline);
-
-    /**
      * Gets the supported operations in a model.
      *
      * getSupportedOperations indicates which operations of the top-level
@@ -140,14 +127,10 @@
      *
      * prepareModel_1_3 can be called with an optional deadline. If the model
      * is not able to be prepared before the provided deadline, the model
-     * preparation must be aborted, and either {@link
+     * preparation may be aborted, and either {@link
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
-     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
-     * If the service reports that it does not support preparation deadlines via
-     * IDevice::supportsDeadlines, and prepareModel_1_3 is called with a
-     * deadline, then the argument is invalid, and {@link
-     * ErrorStatus::INVALID_ARGUMENT} must be returned.
      *
      * Optionally, the driver may save the prepared model to cache during the
      * asynchronous preparation. Any error that occurs when saving to cache must
@@ -172,9 +155,9 @@
      *     model.
      * @param priority The priority of the prepared model relative to other
      *     prepared models owned by the client.
-     * @param deadline The time by which the model must be prepared. If the
-     *     model cannot be prepared by the deadline, the preparation must be
-     *     aborted.
+     * @param deadline The time by which the model is expected to be prepared.
+     *     If the model cannot be prepared by the deadline, the preparation may
+     *     be aborted.
      * @param modelCache A vector of handles with each entry holding exactly one
      *     cache file descriptor for the security-sensitive cache. The length of
      *     the vector must either be 0 indicating that caching information is
@@ -209,8 +192,8 @@
      *     - GENERAL_FAILURE if there is an unspecified error
      *     - INVALID_ARGUMENT if one of the input arguments related to preparing
      *       the model is invalid
-     *     - MISSED_DEADLINE_* if the deadline for preparing a model cannot be
-     *       met
+     *     - MISSED_DEADLINE_* if the preparation is aborted because the model
+     *       cannot be prepared by the deadline
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
     prepareModel_1_3(Model model, ExecutionPreference preference,
@@ -262,14 +245,11 @@
      *
      * prepareModelFromCache_1_3 can be called with an optional deadline. If the
      * model is not able to prepared before the provided deadline, the model
-     * preparation must be aborted, and either {@link
+     * preparation may be aborted, and either {@link
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT}
-     * or {@link ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The
+     * or {@link ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The
      * error due to an abort must be sent the same way as other errors,
-     * described above. If the service reports that it does not support
-     * preparation deadlines via IDevice::supportsDeadlines, and
-     * prepareModelFromCache_1_3 is called with a deadline, then the argument is
-     * invalid, and {@link ErrorStatus::INVALID_ARGUMENT} must be returned.
+     * described above.
      *
      * The only information that may be unknown to the model at this stage is
      * the shape of the tensors, which may only be known at execution time. As
@@ -279,9 +259,9 @@
      * used with different shapes of inputs on different (possibly concurrent)
      * executions.
      *
-     * @param deadline The time by which the model must be prepared. If the
-     *     model cannot be prepared by the deadline, the preparation must be
-     *     aborted.
+     * @param deadline The time by which the model is expected to be prepared.
+     *     If the model cannot be prepared by the deadline, the preparation may
+     *     be aborted.
      * @param modelCache A vector of handles with each entry holding exactly one
      *     cache file descriptor for the security-sensitive cache. The length of
      *     the vector must match the numModelCache returned from getNumberOfCacheFilesNeeded.
@@ -307,8 +287,8 @@
      *     - GENERAL_FAILURE if caching is not supported or if there is an
      *       unspecified error
      *     - INVALID_ARGUMENT if one of the input arguments is invalid
-     *     - MISSED_DEADLINE_* if the deadline for preparing a model cannot be
-     *       met
+     *     - MISSED_DEADLINE_* if the preparation is aborted because the model
+     *       cannot be prepared by the deadline
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
     prepareModelFromCache_1_3(OptionalTimePoint deadline,
diff --git a/neuralnetworks/1.3/IExecutionCallback.hal b/neuralnetworks/1.3/IExecutionCallback.hal
index 439428a..ea11b17 100644
--- a/neuralnetworks/1.3/IExecutionCallback.hal
+++ b/neuralnetworks/1.3/IExecutionCallback.hal
@@ -47,7 +47,8 @@
      *                 corresponding output
      *               - INVALID_ARGUMENT if one of the input arguments to
      *                 prepareModel is invalid
-     *               - MISSED_DEADLINE_* if the deadline could not be met
+     *               - MISSED_DEADLINE_* if the execution is aborted because it
+     *                 cannot be completed by the deadline
      *               - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      * @param outputShapes A list of shape information of model output operands.
      *                     The index into "outputShapes" corresponds with to index
diff --git a/neuralnetworks/1.3/IFencedExecutionCallback.hal b/neuralnetworks/1.3/IFencedExecutionCallback.hal
index 6030809..949438e 100644
--- a/neuralnetworks/1.3/IFencedExecutionCallback.hal
+++ b/neuralnetworks/1.3/IFencedExecutionCallback.hal
@@ -38,8 +38,8 @@
      *                - DEVICE_UNAVAILABLE if driver is offline or busy
      *                - GENERAL_FAILURE if the asynchronous task resulted in an
      *                  unspecified error
-     *                - MISSED_DEADLINE_* if the deadline for executing a model
-     *                  cannot be met
+     *                - MISSED_DEADLINE_* if the execution is aborted because it
+     *                  cannot be completed by the deadline
      *                - RESOURCE_EXHAUSTED_* if the task was aborted by the
      *                  driver
      * @return timingLaunched The duration starts when executeFenced is called and ends when
diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
index 4ce3691..a1814b5 100644
--- a/neuralnetworks/1.3/IPreparedModel.hal
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -70,14 +70,10 @@
      *
      * execute_1_3 can be called with an optional deadline. If the execution
      * is not able to be completed before the provided deadline, the execution
-     * must be aborted, and either {@link
+     * may be aborted, and either {@link
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
-     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
-     * If the service reports that it does not support execution deadlines via
-     * IDevice::supportsDeadlines, and execute_1_3 is called with a deadline,
-     * then the argument is invalid, and {@link ErrorStatus::INVALID_ARGUMENT}
-     * must be returned.
      *
      * Any number of calls to the execute* and executeSynchronously* functions,
      * in any combination, may be made concurrently, even on the same
@@ -89,9 +85,9 @@
      *                The duration runs from the time the driver sees the call
      *                to the execute_1_3 function to the time the driver invokes
      *                the callback.
-     * @param deadline The time by which the execution must complete. If the
-     *                 execution cannot be finished by the deadline, the
-     *                 execution must be aborted.
+     * @param deadline The time by which the execution is expected to complete.
+     *                 If the execution cannot be completed by the deadline, the
+     *                 execution may be aborted.
      * @param loopTimeoutDuration The maximum amount of time that should be spent
      *                            executing a {@link OperationType::WHILE}
      *                            operation. If a loop condition model does not
@@ -116,8 +112,8 @@
      *                  not large enough to store the resultant values
      *                - INVALID_ARGUMENT if one of the input arguments is
      *                  invalid
-     *                - MISSED_DEADLINE_* if the deadline for executing a model
-     *                  cannot be met
+     *                - MISSED_DEADLINE_* if the execution is aborted because it
+     *                  cannot be completed by the deadline
      *                - RESOURCE_EXHAUSTED_* if the task was aborted by the
      *                  driver
      */
@@ -150,16 +146,12 @@
      * (ErrorStatus::NONE): There must be no failure unless the device itself is
      * in a bad state.
      *
-     * executeSynchronously_1_3 can be called with an optional deadline. If the
+     * executeSynchronously_1_3 may be called with an optional deadline. If the
      * execution is not able to be completed before the provided deadline, the
-     * execution must be aborted, and either {@link
+     * execution may be aborted, and either {@link
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
-     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
-     * If the service reports that it does not support execution deadlines via
-     * IDevice::supportsDeadlines, and executeSynchronously_1_3 is called with a
-     * deadline, then the argument is invalid, and
-     * {@link ErrorStatus::INVALID_ARGUMENT} must be returned.
      *
      * Any number of calls to the execute* and executeSynchronously* functions,
      * in any combination, may be made concurrently, even on the same
@@ -171,9 +163,9 @@
      *                The duration runs from the time the driver sees the call
      *                to the executeSynchronously_1_3 function to the time the driver
      *                returns from the function.
-     * @param deadline The time by which the execution must complete. If the
-     *                 execution cannot be finished by the deadline, the
-     *                 execution must be aborted.
+     * @param deadline The time by which the execution is expected to complete.
+     *                 If the execution cannot be finished by the deadline, the
+     *                 execution may be aborted.
      * @param loopTimeoutDuration The maximum amount of time that should be spent
      *                            executing a {@link OperationType::WHILE}
      *                            operation. If a loop condition model does not
@@ -194,8 +186,8 @@
      *                  corresponding output
      *                - INVALID_ARGUMENT if one of the input arguments is
      *                  invalid
-     *                - MISSED_DEADLINE_* if the deadline for executing a model
-     *                  cannot be met
+     *                - MISSED_DEADLINE_* if the execution is aborted because it
+     *                  cannot be completed by the deadline
      *                - RESOURCE_EXHAUSTED_* if the task was aborted by the
      *                  driver
      * @return outputShapes A list of shape information of model output operands.
@@ -236,17 +228,13 @@
      * any data object referenced by 'request' (described by the
      * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}).
      *
-     * executeFenced can be called with an optional deadline and an optional duration.
+     * executeFenced may be called with an optional deadline and an optional duration.
      * If the execution is not able to be completed before the provided deadline or
      * within the timeout duration (measured from when all sync fences in waitFor are
-     * signaled), whichever comes earlier, the execution must be aborted, and either
+     * signaled), whichever comes earlier, the execution may be aborted, and either
      * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
-     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due
+     * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
-     * If the service reports that it does not support execution deadlines via
-     * IDevice::supportsDeadlines, and executeFenced is called with a
-     * deadline or duration, then the argument is invalid, and
-     * {@link ErrorStatus::INVALID_ARGUMENT} must be returned.
      *
      * If any of the sync fences in waitFor changes to error status after the executeFenced
      * call succeeds, or the execution is aborted because it cannot finish before the deadline
@@ -263,9 +251,9 @@
      * @param waitFor A vector of sync fence file descriptors.
      *                Execution must not start until all sync fences have been signaled.
      * @param measure Specifies whether or not to measure duration of the execution.
-     * @param deadline The time by which the execution must complete. If the
-     *                 execution cannot be finished by the deadline, the
-     *                 execution must be aborted.
+     * @param deadline The time by which the execution is expected to complete.
+     *                 If the execution cannot be finished by the deadline, the
+     *                 execution may be aborted.
      * @param loopTimeoutDuration The maximum amount of time that should be spent
      *                            executing a {@link OperationType::WHILE}
      *                            operation. If a loop condition model does not
@@ -277,18 +265,18 @@
      *                            LoopTimeoutDurationNs::DEFAULT}. When
      *                            provided, the duration must not exceed {@link
      *                            LoopTimeoutDurationNs::MAXIMUM}.
-     * @param duration The length of time within which the execution must
-     *                 complete after all sync fences in waitFor are signaled. If the
-     *                 execution cannot be finished within the duration, the execution
-     *                 must be aborted.
+     * @param duration The length of time within which the execution is expected
+     *                 to complete after all sync fences in waitFor are signaled.
+     *                 If the execution cannot be finished within the duration,
+     *                 the execution may be aborted.
      * @return status Error status of the call, must be:
      *                - NONE if task is successfully launched
      *                - DEVICE_UNAVAILABLE if driver is offline or busy
      *                - GENERAL_FAILURE if there is an unspecified error
      *                - INVALID_ARGUMENT if one of the input arguments is invalid, including
      *                                   fences in error states.
-     *                - MISSED_DEADLINE_* if the deadline for executing a model
-     *                  cannot be met
+     *                - MISSED_DEADLINE_* if the execution is aborted because it
+     *                  cannot be completed by the deadline
      *                - RESOURCE_EXHAUSTED_* if the task was aborted by the
      *                  driver
      * @return syncFence The sync fence that will be signaled when the task is completed.
diff --git a/neuralnetworks/1.3/IPreparedModelCallback.hal b/neuralnetworks/1.3/IPreparedModelCallback.hal
index 11ebbf4..c0d3416 100644
--- a/neuralnetworks/1.3/IPreparedModelCallback.hal
+++ b/neuralnetworks/1.3/IPreparedModelCallback.hal
@@ -47,8 +47,8 @@
      *                 unspecified error
      *               - INVALID_ARGUMENT if one of the input arguments to
      *                 prepareModel is invalid
-     *               - MISSED_DEADLINE_* if the deadline for executing a model
-     *                 cannot be met
+     *               - MISSED_DEADLINE_* if the preparation is aborted because
+     *                 the model cannot be prepared by the deadline
      *               - RESOURCE_EXHAUSTED_* if the task was aborted by the
      *                 driver
      * @param preparedModel A model that has been asynchronously prepared for
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 08d8e6b..daaf22e 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -1584,6 +1584,17 @@
      * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
      *      Available since HAL version 1.2.
+     * * 4: Align corners. An optional {@link OperandType::BOOL}
+     *      scalar, default to false.  If True, the centers of the 4 corner
+     *      pixels of the input and output tensors are aligned, preserving the
+     *      values at the corner pixels.
+     *      Available since HAL version 1.3.
+     * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+     *      scalar, default to false. If True, the pixel centers are assumed to
+     *      be at (0.5, 0.5). This is the default behavior of image.resize in
+     *      TF 2.0. If this parameter is True, then align_corners parameter
+     *      must be False.
+     *      Available since HAL version 1.3.
      *
      * Inputs (resizing by scale, since HAL version 1.2):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
@@ -1602,6 +1613,17 @@
      *      {@link OperandType::FLOAT32} otherwise.
      * * 3: An optional {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
+     * * 4: Align corners. An optional {@link OperandType::BOOL}
+     *      scalar, default to false.  If True, the centers of the 4 corner
+     *      pixels of the input and output tensors are aligned, preserving the
+     *      values at the corner pixels.
+     *      Available since HAL version 1.3.
+     * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+     *      scalar, default to false. If True, the pixel centers are assumed to
+     *      be at (0.5, 0.5). This is the default behavior of image.resize in
+     *      TF 2.0. If this parameter is True, then align_corners parameter
+     *      must be False.
+     *      Available since HAL version 1.3.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
@@ -4870,6 +4892,17 @@
      *      height of the output tensor.
      * * 3: An {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
+     * * 4: Align corners. An optional {@link OperandType::BOOL}
+     *      scalar, default to false.  If True, the centers of the 4 corner
+     *      pixels of the input and output tensors are aligned, preserving the
+     *      values at the corner pixels.
+     *      Available since HAL version 1.3.
+     * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+     *      scalar, default to false. If True, the pixel centers are assumed to
+     *      be at (0.5, 0.5). This is the default behavior of image.resize in
+     *      TF 2.0. If this parameter is True, then align_corners parameter
+     *      must be False.
+     *      Available since HAL version 1.3.
      *
      * Inputs (resizing by scale):
      * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying
@@ -4888,6 +4921,17 @@
      *      {@link OperandType::FLOAT32} otherwise.
      * * 3: An {@link OperandType::BOOL} scalar, default to false.
      *      Set to true to specify NCHW data layout for input0 and output0.
+     * * 4: Align corners. An optional {@link OperandType::BOOL}
+     *      scalar, default to false.  If True, the centers of the 4 corner
+     *      pixels of the input and output tensors are aligned, preserving the
+     *      values at the corner pixels.
+     *      Available since HAL version 1.3.
+     * * 5: Half pixel centers. An optional {@link OperandType::BOOL}
+     *      scalar, default to false. If True, the pixel centers are assumed to
+     *      be at (0.5, 0.5). This is the default behavior of image.resize in
+     *      TF 2.0. If this parameter is True, then align_corners parameter
+     *      must be False.
+     *      Available since HAL version 1.3.
      *
      * Outputs:
      * * 0: The output 4-D tensor, of shape
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index b04abe2..83a8d94 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -626,21 +626,28 @@
             ErrorStatus result;
             hidl_handle syncFenceHandle;
             sp<IFencedExecutionCallback> fencedCallback;
-            Return<void> ret = preparedModel->executeFenced(
-                    request, {}, testConfig.measureTiming, {}, loopTimeoutDuration, {},
-                    [&result, &syncFenceHandle, &fencedCallback](
-                            ErrorStatus error, const hidl_handle& handle,
-                            const sp<IFencedExecutionCallback>& callback) {
-                        result = error;
-                        syncFenceHandle = handle;
-                        fencedCallback = callback;
-                    });
+            auto callbackFunc = [&result, &syncFenceHandle, &fencedCallback](
+                                        ErrorStatus error, const hidl_handle& handle,
+                                        const sp<IFencedExecutionCallback>& callback) {
+                result = error;
+                syncFenceHandle = handle;
+                fencedCallback = callback;
+            };
+            Return<void> ret =
+                    preparedModel->executeFenced(request, {}, testConfig.measureTiming, {},
+                                                 loopTimeoutDuration, {}, callbackFunc);
             ASSERT_TRUE(ret.isOk());
             if (result != ErrorStatus::NONE) {
                 ASSERT_EQ(syncFenceHandle.getNativeHandle(), nullptr);
                 ASSERT_EQ(fencedCallback, nullptr);
-                executionStatus = ErrorStatus::GENERAL_FAILURE;
+                executionStatus = result;
             } else if (syncFenceHandle.getNativeHandle()) {
+                // If a sync fence is returned, try start another run waiting for the sync fence.
+                ret = preparedModel->executeFenced(request, {syncFenceHandle},
+                                                   testConfig.measureTiming, {},
+                                                   loopTimeoutDuration, {}, callbackFunc);
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(result, ErrorStatus::NONE);
                 waitForSyncFence(syncFenceHandle.getNativeHandle()->data[0]);
             }
             if (result == ErrorStatus::NONE) {
@@ -656,9 +663,7 @@
         }
     }
 
-    // The driver is allowed to reject executeFenced, and if they do, we should skip.
-    if ((testConfig.outputType != OutputType::FULLY_SPECIFIED ||
-         testConfig.executor == Executor::FENCED) &&
+    if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
         executionStatus == ErrorStatus::GENERAL_FAILURE) {
         if (skipped != nullptr) {
             *skipped = true;
@@ -691,12 +696,22 @@
                         outputShapes.size() == testModel.main.outputIndexes.size());
             break;
         case OutputType::UNSPECIFIED:
+            if (testConfig.executor == Executor::FENCED) {
+                // For Executor::FENCED, the output shape must be fully specified.
+                ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
+                return;
+            }
             // If the model output operands are not fully specified, outputShapes must have
             // the same number of elements as the number of outputs.
             ASSERT_EQ(ErrorStatus::NONE, executionStatus);
             ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
             break;
         case OutputType::INSUFFICIENT:
+            if (testConfig.executor == Executor::FENCED) {
+                // For Executor::FENCED, the output shape must be fully specified.
+                ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
+                return;
+            }
             ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
             ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
             ASSERT_FALSE(outputShapes[0].isSufficient);
@@ -739,12 +754,12 @@
         case TestKind::DYNAMIC_SHAPE: {
             outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
             measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
-            executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+            executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST, Executor::FENCED};
         } break;
         case TestKind::MEMORY_DOMAIN: {
             outputTypesList = {OutputType::FULLY_SPECIFIED};
             measureTimingList = {MeasureTiming::NO};
-            executorList = {Executor::ASYNC, Executor::SYNC};
+            executorList = {Executor::ASYNC, Executor::SYNC, Executor::FENCED};
             memoryType = MemoryType::DEVICE;
         } break;
         case TestKind::FENCED_COMPUTE: {
@@ -858,12 +873,6 @@
 void GeneratedTestBase::SetUp() {
     testing::TestWithParam<GeneratedTestParam>::SetUp();
     ASSERT_NE(kDevice, nullptr);
-
-    const Return<void> ret =
-            kDevice->supportsDeadlines([this](bool prepareModelDeadline, bool executionDeadline) {
-                mSupportsDeadlines = {prepareModelDeadline, executionDeadline};
-            });
-    ASSERT_TRUE(ret.isOk());
 }
 
 std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
@@ -927,8 +936,13 @@
 INSTANTIATE_GENERATED_TEST(MemoryDomainTest,
                            [](const TestModel& testModel) { return !testModel.expectFailure; });
 
-INSTANTIATE_GENERATED_TEST(FencedComputeTest,
-                           [](const TestModel& testModel) { return !testModel.expectFailure; });
+INSTANTIATE_GENERATED_TEST(FencedComputeTest, [](const TestModel& testModel) {
+    return !testModel.expectFailure &&
+           std::all_of(testModel.main.outputIndexes.begin(), testModel.main.outputIndexes.end(),
+                       [&testModel](uint32_t index) {
+                           return testModel.main.operands[index].data.size() > 0;
+                       });
+});
 
 INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) {
     return testModel.hasQuant8CoupledOperands() && testModel.main.operations.size() == 1;
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
index a8db515..834d335 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
@@ -36,7 +36,6 @@
     void SetUp() override;
     const sp<IDevice> kDevice = getData(std::get<NamedDevice>(GetParam()));
     const test_helper::TestModel& kTestModel = *getData(std::get<NamedModel>(GetParam()));
-    std::pair<bool, bool> mSupportsDeadlines;
 };
 
 using FilterFn = std::function<bool(const test_helper::TestModel&)>;
diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
index fccc612..879989e 100644
--- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
@@ -34,45 +34,52 @@
 using HidlToken =
         hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
 
-enum class DeadlineBoundType { NOW, UNLIMITED };
-constexpr std::array<DeadlineBoundType, 2> deadlineBounds = {DeadlineBoundType::NOW,
-                                                             DeadlineBoundType::UNLIMITED};
+enum class DeadlineBoundType { NOW, UNLIMITED, SHORT };
+constexpr std::array<DeadlineBoundType, 3> deadlineBounds = {
+        DeadlineBoundType::NOW, DeadlineBoundType::UNLIMITED, DeadlineBoundType::SHORT};
 std::string toString(DeadlineBoundType type) {
     switch (type) {
         case DeadlineBoundType::NOW:
             return "NOW";
         case DeadlineBoundType::UNLIMITED:
             return "UNLIMITED";
+        case DeadlineBoundType::SHORT:
+            return "SHORT";
     }
     LOG(FATAL) << "Unrecognized DeadlineBoundType: " << static_cast<int>(type);
     return {};
 }
 
+constexpr auto kShortDuration = std::chrono::milliseconds{5};
+
 using Results = std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing>;
 using MaybeResults = std::optional<Results>;
 
 using ExecutionFunction =
         std::function<MaybeResults(const sp<IPreparedModel>& preparedModel, const Request& request,
-                                   DeadlineBoundType deadlineBound)>;
+                                   const OptionalTimePoint& deadline)>;
 
-static OptionalTimePoint makeOptionalTimePoint(DeadlineBoundType deadlineBoundType) {
-    OptionalTimePoint deadline;
+static OptionalTimePoint makeDeadline(DeadlineBoundType deadlineBoundType) {
+    const auto getNanosecondsSinceEpoch = [](const auto& time) -> uint64_t {
+        const auto timeSinceEpoch = time.time_since_epoch();
+        return std::chrono::duration_cast<std::chrono::nanoseconds>(timeSinceEpoch).count();
+    };
+
+    std::chrono::steady_clock::time_point timePoint;
     switch (deadlineBoundType) {
-        case DeadlineBoundType::NOW: {
-            const auto currentTime = std::chrono::steady_clock::now();
-            const auto currentTimeInNanoseconds =
-                    std::chrono::time_point_cast<std::chrono::nanoseconds>(currentTime);
-            const uint64_t nanosecondsSinceEpoch =
-                    currentTimeInNanoseconds.time_since_epoch().count();
-            deadline.nanosecondsSinceEpoch(nanosecondsSinceEpoch);
-        } break;
-        case DeadlineBoundType::UNLIMITED: {
-            const auto maxTime = std::chrono::time_point<std::chrono::steady_clock,
-                                                         std::chrono::nanoseconds>::max();
-            const uint64_t nanosecondsSinceEpoch = maxTime.time_since_epoch().count();
-            deadline.nanosecondsSinceEpoch(nanosecondsSinceEpoch);
-        } break;
+        case DeadlineBoundType::NOW:
+            timePoint = std::chrono::steady_clock::now();
+            break;
+        case DeadlineBoundType::UNLIMITED:
+            timePoint = std::chrono::steady_clock::time_point::max();
+            break;
+        case DeadlineBoundType::SHORT:
+            timePoint = std::chrono::steady_clock::now() + kShortDuration;
+            break;
     }
+
+    OptionalTimePoint deadline;
+    deadline.nanosecondsSinceEpoch(getNanosecondsSinceEpoch(timePoint));
     return deadline;
 }
 
@@ -80,7 +87,7 @@
                          std::optional<DeadlineBoundType> deadlineBound) {
     OptionalTimePoint deadline;
     if (deadlineBound.has_value()) {
-        deadline = makeOptionalTimePoint(deadlineBound.value());
+        deadline = makeDeadline(deadlineBound.value());
     }
 
     // see if service can handle model
@@ -127,11 +134,11 @@
     } else {
         switch (deadlineBound.value()) {
             case DeadlineBoundType::NOW:
-                // If the execution was launched with a deadline of NOW, the
-                // deadline has already passed when the driver would launch the
-                // execution. In this case, the driver must return
-                // MISSED_DEADLINE_*.
-                EXPECT_TRUE(prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
+            case DeadlineBoundType::SHORT:
+                // Either the driver successfully completed the task or it
+                // aborted and returned MISSED_DEADLINE_*.
+                EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE ||
+                            prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
                             prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT);
                 break;
             case DeadlineBoundType::UNLIMITED:
@@ -145,8 +152,7 @@
     ASSERT_EQ(prepareReturnStatus == ErrorStatus::NONE, preparedModel.get() != nullptr);
 }
 
-void runPrepareModelTests(const sp<IDevice>& device, const Model& model,
-                          bool supportsPrepareModelDeadline) {
+void runPrepareModelTests(const sp<IDevice>& device, const Model& model) {
     // test priority
     for (auto priority : hidl_enum_range<Priority>{}) {
         SCOPED_TRACE("priority: " + toString(priority));
@@ -155,19 +161,17 @@
     }
 
     // test deadline
-    if (supportsPrepareModelDeadline) {
-        for (auto deadlineBound : deadlineBounds) {
-            SCOPED_TRACE("deadlineBound: " + toString(deadlineBound));
-            runPrepareModelTest(device, model, kDefaultPriority, deadlineBound);
-        }
+    for (auto deadlineBound : deadlineBounds) {
+        SCOPED_TRACE("deadlineBound: " + toString(deadlineBound));
+        runPrepareModelTest(device, model, kDefaultPriority, deadlineBound);
     }
 }
 
 static MaybeResults executeAsynchronously(const sp<IPreparedModel>& preparedModel,
-                                          const Request& request, DeadlineBoundType deadlineBound) {
+                                          const Request& request,
+                                          const OptionalTimePoint& deadline) {
     SCOPED_TRACE("asynchronous");
     const MeasureTiming measure = MeasureTiming::NO;
-    const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound);
 
     // launch execution
     const sp<ExecutionCallback> callback = new ExecutionCallback();
@@ -187,14 +191,17 @@
 }
 
 static MaybeResults executeSynchronously(const sp<IPreparedModel>& preparedModel,
-                                         const Request& request, DeadlineBoundType deadlineBound) {
+                                         const Request& request,
+                                         const OptionalTimePoint& deadline) {
     SCOPED_TRACE("synchronous");
     const MeasureTiming measure = MeasureTiming::NO;
-    const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound);
 
     // configure results callback
     MaybeResults results;
-    const auto cb = [&results](const auto&... args) { *results = {args...}; };
+    const auto cb = [&results](ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+                               const Timing& timing) {
+        results.emplace(status, outputShapes, timing);
+    };
 
     // run execution
     const Return<void> ret =
@@ -209,9 +216,10 @@
 void runExecutionTest(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
                       const Request& request, bool synchronous, DeadlineBoundType deadlineBound) {
     const ExecutionFunction execute = synchronous ? executeSynchronously : executeAsynchronously;
+    const auto deadline = makeDeadline(deadlineBound);
 
     // Perform execution and unpack results.
-    const auto results = execute(preparedModel, request, deadlineBound);
+    const auto results = execute(preparedModel, request, deadline);
     if (!results.has_value()) return;
     const auto& [status, outputShapes, timing] = results.value();
 
@@ -222,13 +230,13 @@
     // Validate deadline information if applicable.
     switch (deadlineBound) {
         case DeadlineBoundType::NOW:
-            // If the execution was launched with a deadline of NOW, the
-            // deadline has already passed when the driver would launch the
-            // execution. In this case, the driver must return
-            // MISSED_DEADLINE_*.
-            ASSERT_TRUE(status == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
+        case DeadlineBoundType::SHORT:
+            // Either the driver successfully completed the task or it
+            // aborted and returned MISSED_DEADLINE_*.
+            ASSERT_TRUE(status == ErrorStatus::NONE ||
+                        status == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
                         status == ErrorStatus::MISSED_DEADLINE_PERSISTENT);
-            return;
+            break;
         case DeadlineBoundType::UNLIMITED:
             // If an unlimited deadline is supplied, we expect the execution to
             // proceed normally. In this case, check it normally by breaking out
@@ -256,7 +264,9 @@
     const std::vector<TestBuffer> outputs = getOutputBuffers(request10);
 
     // We want "close-enough" results.
-    checkResults(testModel, outputs);
+    if (status == ErrorStatus::NONE) {
+        checkResults(testModel, outputs);
+    }
 }
 
 void runExecutionTests(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
@@ -268,32 +278,27 @@
     }
 }
 
-void runTests(const sp<IDevice>& device, const TestModel& testModel,
-              std::pair<bool, bool> supportsDeadlines) {
+void runTests(const sp<IDevice>& device, const TestModel& testModel) {
     // setup
-    const auto [supportsPrepareModelDeadline, supportsExecutionDeadline] = supportsDeadlines;
-    if (!supportsPrepareModelDeadline && !supportsExecutionDeadline) return;
     const Model model = createModel(testModel);
 
     // run prepare model tests
-    runPrepareModelTests(device, model, supportsPrepareModelDeadline);
+    runPrepareModelTests(device, model);
 
-    if (supportsExecutionDeadline) {
-        // prepare model
-        sp<IPreparedModel> preparedModel;
-        createPreparedModel(device, model, &preparedModel);
-        if (preparedModel == nullptr) return;
+    // prepare model
+    sp<IPreparedModel> preparedModel;
+    createPreparedModel(device, model, &preparedModel);
+    if (preparedModel == nullptr) return;
 
-        // run execution tests
-        const Request request = nn::convertToV1_3(createRequest(testModel));
-        runExecutionTests(preparedModel, testModel, request);
-    }
+    // run execution tests
+    const Request request = nn::convertToV1_3(createRequest(testModel));
+    runExecutionTests(preparedModel, testModel, request);
 }
 
 class DeadlineTest : public GeneratedTestBase {};
 
 TEST_P(DeadlineTest, Test) {
-    runTests(kDevice, kTestModel, mSupportsDeadlines);
+    runTests(kDevice, kTestModel);
 }
 
 INSTANTIATE_GENERATED_TEST(DeadlineTest,
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 09e9922..7da2da9 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -44,18 +44,12 @@
 }
 
 static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
-                                 const Model& model, ExecutionPreference preference,
-                                 bool testDeadline) {
+                                 const Model& model, ExecutionPreference preference) {
     SCOPED_TRACE(message + " [prepareModel_1_3]");
 
-    OptionalTimePoint deadline;
-    if (testDeadline) {
-        deadline.nanosecondsSinceEpoch(std::numeric_limits<uint64_t>::max());
-    }
-
     sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
     Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3(
-            model, preference, kDefaultPriority, deadline, hidl_vec<hidl_handle>(),
+            model, preference, kDefaultPriority, {}, hidl_vec<hidl_handle>(),
             hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk());
     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -79,13 +73,12 @@
 // to the model does not leave this function.
 static void validate(const sp<IDevice>& device, const std::string& message, Model model,
                      const std::function<void(Model*)>& mutation,
-                     ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER,
-                     bool testDeadline = false) {
+                     ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
     mutation(&model);
-    if (validExecutionPreference(preference) && !testDeadline) {
+    if (validExecutionPreference(preference)) {
         validateGetSupportedOperations(device, message, model);
     }
-    validatePrepareModel(device, message, model, preference, testDeadline);
+    validatePrepareModel(device, message, model, preference);
 }
 
 static uint32_t addOperand(Model* model) {
@@ -585,6 +578,8 @@
     // - CONV_2D, DEPTHWISE_CONV_2D, MAX_POOL_2D, AVERAGE_POOL_2D, L2_POOL_2D, RESIZE_BILINEAR,
     //   SPACE_TO_DEPTH, SPACE_TO_DEPTH, SPACE_TO_BATCH_ND, BATCH_TO_SPACE_ND can have an optional
     //   layout parameter.
+    //   RESIZE_BILINEAR and RESIZE_NEAREST_NEIGHBOR can have optional
+    //   align_corners and half_pixel_centers parameters.
     // - L2_NORMALIZATION, LOCAL_RESPONSE_NORMALIZATION, SOFTMAX can have an optional axis
     //   parameter.
     switch (op.type) {
@@ -607,7 +602,12 @@
             }
         } break;
         case OperationType::RESIZE_BILINEAR: {
-            if (op.inputs.size() == 4 && input == 3) {
+            if (op.inputs.size() >= 4 && input >= 3) {
+                return true;
+            }
+        } break;
+        case OperationType::RESIZE_NEAREST_NEIGHBOR: {
+            if (op.inputs.size() >= 5 && input >= 3) {
                 return true;
             }
         } break;
@@ -693,7 +693,9 @@
     //   parameter.
     if ((op.type == OperationType::L2_NORMALIZATION && op.inputs.size() == 1) ||
         (op.type == OperationType::LOCAL_RESPONSE_NORMALIZATION && op.inputs.size() == 5) ||
-        (op.type == OperationType::SOFTMAX && op.inputs.size() == 2)) {
+        (op.type == OperationType::SOFTMAX && op.inputs.size() == 2) ||
+        (op.type == OperationType::RESIZE_BILINEAR && op.inputs.size() < 6) ||
+        (op.type == OperationType::RESIZE_NEAREST_NEIGHBOR && op.inputs.size() < 6)) {
         return true;
     }
     return false;
@@ -744,19 +746,9 @@
     }
 }
 
-///////////////////////// DEADLINE /////////////////////////
-
-static void deadlineTest(const sp<IDevice>& device, const Model& model) {
-    const std::string message = "deadlineTest: deadline not supported";
-    const auto noop = [](Model*) {};
-    validate(device, message, model, noop, ExecutionPreference::FAST_SINGLE_ANSWER,
-             /*testDeadline=*/true);
-}
-
 ////////////////////////// ENTRY POINT //////////////////////////////
 
-void validateModel(const sp<IDevice>& device, const Model& model,
-                   bool prepareModelDeadlineSupported) {
+void validateModel(const sp<IDevice>& device, const Model& model) {
     mutateOperandTypeTest(device, model);
     mutateOperandRankTest(device, model);
     mutateOperandScaleTest(device, model);
@@ -772,9 +764,6 @@
     addOperationInputTest(device, model);
     addOperationOutputTest(device, model);
     mutateExecutionPreferenceTest(device, model);
-    if (!prepareModelDeadlineSupported) {
-        deadlineTest(device, model);
-    }
 }
 
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 20f4fe2..5e806e5 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -45,8 +45,7 @@
 // that use the request. Note that the request here is passed by value, and any
 // mutation to the request does not leave this function.
 static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
-                     Request request, const std::function<void(Request*)>& mutation,
-                     bool testDeadline = false) {
+                     Request request, const std::function<void(Request*)>& mutation) {
     mutation(&request);
 
     // We'd like to test both with timing requested and without timing
@@ -59,18 +58,13 @@
     };
     MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO;
 
-    OptionalTimePoint deadline;
-    if (testDeadline) {
-        deadline.nanosecondsSinceEpoch(std::numeric_limits<uint64_t>::max());
-    }
-
     // asynchronous
     {
         SCOPED_TRACE(message + " [execute_1_3]");
 
         sp<ExecutionCallback> executionCallback = new ExecutionCallback();
         Return<ErrorStatus> executeLaunchStatus =
-                preparedModel->execute_1_3(request, measure, deadline, {}, executionCallback);
+                preparedModel->execute_1_3(request, measure, {}, {}, executionCallback);
         ASSERT_TRUE(executeLaunchStatus.isOk());
         ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
 
@@ -88,7 +82,7 @@
         SCOPED_TRACE(message + " [executeSynchronously_1_3]");
 
         Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
-                request, measure, deadline, {},
+                request, measure, {}, {},
                 [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
                    const Timing& timing) {
                     ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
@@ -100,7 +94,7 @@
 
     // burst
     // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2.
-    if (!testDeadline) {
+    {
         SCOPED_TRACE(message + " [burst]");
 
         ASSERT_TRUE(nn::compliantWithV1_0(request));
@@ -143,7 +137,7 @@
     {
         SCOPED_TRACE(message + " [executeFenced]");
         Return<void> ret =
-                preparedModel->executeFenced(request, {}, MeasureTiming::NO, deadline, {}, {},
+                preparedModel->executeFenced(request, {}, MeasureTiming::NO, {}, {}, {},
                                              [](ErrorStatus error, const hidl_handle& handle,
                                                 const sp<IFencedExecutionCallback>& callback) {
                                                  ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
@@ -174,23 +168,11 @@
     }
 }
 
-///////////////////////// DEADLINE ////////////////////////////////////
-
-static void deadlineTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
-    const std::string message = "deadlineTest: deadline not supported";
-    const auto noop = [](Request*) {};
-    validate(preparedModel, message, request, noop, /*testDeadline=*/true);
-}
-
 ///////////////////////////// ENTRY POINT //////////////////////////////////
 
-void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request,
-                     bool executionDeadlineSupported) {
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request) {
     removeInputTest(preparedModel, request);
     removeOutputTest(preparedModel, request);
-    if (!executionDeadlineSupported) {
-        deadlineTest(preparedModel, request);
-    }
 }
 
 void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request) {
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
index 16341da..5b07034 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -123,11 +123,9 @@
 INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest);
 
 // Forward declaration from ValidateModel.cpp
-void validateModel(const sp<IDevice>& device, const Model& model,
-                   bool prepareModelDeadlineSupported);
+void validateModel(const sp<IDevice>& device, const Model& model);
 // Forward declaration from ValidateRequest.cpp
-void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request,
-                     bool executionDeadlineSupported);
+void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request);
 // Forward declaration from ValidateRequest.cpp
 void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request);
 // Forward declaration from ValidateBurst.cpp
@@ -147,17 +145,15 @@
     ASSERT_TRUE(ret_null.isOk());
 }
 
-void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request,
-                        std::pair<bool, bool> supportsDeadlines) {
-    const auto [prepareModelDeadlineSupported, executionDeadlineSupported] = supportsDeadlines;
-    validateModel(device, model, prepareModelDeadlineSupported);
+void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request) {
+    validateModel(device, model);
 
     // Create IPreparedModel.
     sp<IPreparedModel> preparedModel;
     createPreparedModel(device, model, &preparedModel);
     if (preparedModel == nullptr) return;
 
-    validateRequest(preparedModel, request, executionDeadlineSupported);
+    validateRequest(preparedModel, request);
     validateExecuteFenced(preparedModel, request);
 
     // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2.
@@ -166,12 +162,10 @@
     validateBurst(preparedModel, request10);
 }
 
-void validateFailure(const sp<IDevice>& device, const Model& model, const Request& request,
-                     std::pair<bool, bool> supportsDeadlines) {
-    const bool prepareModelDeadlineSupported = supportsDeadlines.first;
+void validateFailure(const sp<IDevice>& device, const Model& model, const Request& request) {
     // TODO: Should this always succeed?
     //       What if the invalid input is part of the model (i.e., a parameter).
-    validateModel(device, model, prepareModelDeadlineSupported);
+    validateModel(device, model);
 
     // Create IPreparedModel.
     sp<IPreparedModel> preparedModel;
@@ -185,9 +179,9 @@
     const Model model = createModel(kTestModel);
     const Request request = nn::convertToV1_3(createRequest(kTestModel));
     if (kTestModel.expectFailure) {
-        validateFailure(kDevice, model, request, mSupportsDeadlines);
+        validateFailure(kDevice, model, request);
     } else {
-        validateEverything(kDevice, model, request, mSupportsDeadlines);
+        validateEverything(kDevice, model, request);
     }
 }
 
diff --git a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
index 4e48141..ca64305 100644
--- a/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.3/vts/functional/radio_hidl_hal_api.cpp
@@ -75,38 +75,3 @@
             radioRsp_v1_3->rspInfo.error,
             {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
 }
-
-/*
- * Test IRadio.setSystemSelectionChannels() for the response returned.
- *
- * This test is excluded from manifest, due to non-implementation in Q. Tracked by b/130254624.
- */
-TEST_P(RadioHidlTest_v1_3, setSystemSelectionChannels) {
-    serial = GetRandomSerialNumber();
-
-    RadioAccessSpecifier specifier = {.radioAccessNetwork = RadioAccessNetworks::GERAN,
-                                      .geranBands = {GeranBands::BAND_450, GeranBands::BAND_480},
-                                      .channels = {1, 2}};
-
-    Return<void> res = radio_v1_3->setSystemSelectionChannels(serial, true, {specifier});
-    ASSERT_OK(res);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial);
-    ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
-          toString(radioRsp_v1_3->rspInfo.error).c_str());
-    ASSERT_TRUE(CheckAnyOfErrors(
-            radioRsp_v1_3->rspInfo.error,
-            {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR}));
-
-    if (radioRsp_v1_3->rspInfo.error == RadioError::NONE) {
-        Return<void> res = radio_v1_3->setSystemSelectionChannels(serial, false, {specifier});
-        ASSERT_OK(res);
-        EXPECT_EQ(std::cv_status::no_timeout, wait());
-        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_3->rspInfo.type);
-        EXPECT_EQ(serial, radioRsp_v1_3->rspInfo.serial);
-        ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
-              toString(radioRsp_v1_3->rspInfo.error).c_str());
-        EXPECT_EQ(RadioError::NONE, radioRsp_v1_3->rspInfo.error);
-    }
-}
\ No newline at end of file
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index 6ebbcb4..956f9bd 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -238,7 +238,8 @@
      * 1) Emergency call is completed; or
      * 2) Another setRadioPower_1_5 is issued with forEmergencyCall being false or
      * preferredForEmergencyCall being false; or
-     * 3) Timeout after a long period of time.
+     * 3) Timeout after 30 seconds if dial or emergencyDial is not called.
+     * Once one of these conditions is reached, the modem should move into normal operation.
      *
      * @param serial Serial number of request.
      * @param powerOn To turn on radio -> on = true, to turn off radio -> on = false.
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index 84a455f..e87cad2 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -20,6 +20,7 @@
 import @1.0::SendSmsResult;
 import @1.4::IRadioResponse;
 import @1.5::BarringInfo;
+import @1.5::CellIdentity;
 import @1.5::CellInfo;
 import @1.5::PersoSubstate;
 import @1.5::RegStateResult;
@@ -176,6 +177,7 @@
 
     /**
      * @param info Response info struct containing response type, serial no. and error
+     * @param cellIdentity CellIdentity for the barring infos.
      * @param barringInfos a vector of barring info for all barring service types
      *
      * Valid errors returned:
@@ -184,7 +186,8 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:MODEM_ERR
      */
-    oneway getBarringInfoResponse(RadioResponseInfo info, vec<BarringInfo> barringInfos);
+    oneway getBarringInfoResponse(RadioResponseInfo info, CellIdentity cellIdentity,
+            vec<BarringInfo> barringInfos);
 
     /**
      * @param info Response info struct containing response type, serial no. and error
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 784f776..4d3c2d5 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -693,125 +693,116 @@
     CellIdentityNr nr;
 };
 
-/**
- * Combined list of barring services for UTRAN, EUTRAN, and NGRAN.
- *
- * Barring information is defined in:
- * -UTRAN - 3gpp 25.331 Sec 10.2.48.8.6.
- * -EUTRAN - 3gpp 36.331 Sec 6.3.1 SystemInformationBlockType2
- * -NGRAN - 3gpp 38.331 Sec 6.3.2 UAC-BarringInfo and 22.261 Sec 6.22.2.[2-3]
- */
-enum BarringServiceType : int32_t {
-    /** Applicable to UTRAN */
-    /** Barring for all CS services, including registration */
-    CS_SERVICE,
-    /** Barring for all PS services, including registration */
-    PS_SERVICE,
-    /** Barring for mobile-originated circuit-switched voice calls */
-    CS_VOICE,
-
-    /** Applicable to EUTRAN, NGRAN */
-    /** Barring for mobile-originated signalling for any purpose */
-    MO_SIGNALLING,
-    /** Barring for mobile-originated internet or other interactive data */
-    MO_DATA,
-    /** Barring for circuit-switched fallback calling */
-    CS_FALLBACK,
-    /** Barring for IMS voice calling */
-    MMTEL_VOICE,
-    /** Barring for IMS video calling */
-    MMTEL_VIDEO,
-
-    /** Applicable to UTRAN, EUTRAN, NGRAN */
-    /** Barring for emergency services, either CS or emergency MMTEL */
-    EMERGENCY,
-    /** Barring for short message services */
-    SMS,
-
-    /** Operator-specific barring codes; applicable to NGRAN */
-    OPERATOR_1 = 1001,
-    OPERATOR_2 = 1002,
-    OPERATOR_3 = 1003,
-    OPERATOR_4 = 1004,
-    OPERATOR_5 = 1005,
-    OPERATOR_6 = 1006,
-    OPERATOR_7 = 1007,
-    OPERATOR_8 = 1008,
-    OPERATOR_9 = 1009,
-    OPERATOR_10 = 1010,
-    OPERATOR_11 = 1011,
-    OPERATOR_12 = 1012,
-    OPERATOR_13 = 1013,
-    OPERATOR_14 = 1014,
-    OPERATOR_15 = 1015,
-    OPERATOR_16 = 1016,
-    OPERATOR_17 = 1017,
-    OPERATOR_18 = 1018,
-    OPERATOR_19 = 1019,
-    OPERATOR_20 = 1020,
-    OPERATOR_21 = 1021,
-    OPERATOR_22 = 1022,
-    OPERATOR_23 = 1023,
-    OPERATOR_24 = 1024,
-    OPERATOR_25 = 1025,
-    OPERATOR_26 = 1026,
-    OPERATOR_27 = 1027,
-    OPERATOR_28 = 1028,
-    OPERATOR_29 = 1029,
-    OPERATOR_30 = 1030,
-    OPERATOR_31 = 1031,
-    OPERATOR_32 = 1032,
-};
-
-enum BarringType : int32_t {
-    /** Device is not barred for the given service */
-    NONE,
-    /** Device may be barred based on time and probability factors */
-    CONDITIONAL,
-    /* Device is unconditionally barred */
-    UNCONDITIONAL,
-};
-
-struct ConditionalBarringInfo {
-    /** The barring factor as a percentage 0-100 */
-    int32_t barringFactor;
-
-    /** The number of seconds between re-evaluations of barring */
-    int32_t barringTimeSeconds;
-
-    /**
-     * Indicates whether barring is currently being applied.
-     *
-     * <p>True if the UE applies barring to a conditionally barred
-     * service based on the conditional barring parameters.
-     *
-     * <p>False if the service is conditionally barred but barring
-     * is not currently applied, which could be due to either the
-     * barring criteria not having been evaluated (if the UE has not
-     * attempted to use the service) or due to the criteria being
-     * evaluated and the UE being permitted to use the service
-     * despite conditional barring.
-     */
-    bool isBarred;
-};
-
-safe_union BarringTypeSpecificInfo {
-    /** Barring type is either none or unconditional */
-    Monostate noinit;
-
-    /** Must be included if barring is conditional */
-    ConditionalBarringInfo conditionalBarringInfo;
-};
-
 struct BarringInfo {
-    /** Barring service */
-    BarringServiceType service;
+    /**
+     * Combined list of barring services for UTRAN, EUTRAN, and NGRAN.
+     *
+     * Barring information is defined in:
+     * -UTRAN - 3gpp 25.331 Sec 10.2.48.8.6.
+     * -EUTRAN - 3gpp 36.331 Sec 6.3.1 SystemInformationBlockType2
+     * -NGRAN - 3gpp 38.331 Sec 6.3.2 UAC-BarringInfo and 22.261 Sec 6.22.2.[2-3]
+     */
+    enum ServiceType : int32_t {
+        /** Applicable to UTRAN */
+        /** Barring for all CS services, including registration */
+        CS_SERVICE,
+        /** Barring for all PS services, including registration */
+        PS_SERVICE,
+        /** Barring for mobile-originated circuit-switched voice calls */
+        CS_VOICE,
+
+        /** Applicable to EUTRAN, NGRAN */
+        /** Barring for mobile-originated signalling for any purpose */
+        MO_SIGNALLING,
+        /** Barring for mobile-originated internet or other interactive data */
+        MO_DATA,
+        /** Barring for circuit-switched fallback calling */
+        CS_FALLBACK,
+        /** Barring for IMS voice calling */
+        MMTEL_VOICE,
+        /** Barring for IMS video calling */
+        MMTEL_VIDEO,
+
+        /** Applicable to UTRAN, EUTRAN, NGRAN */
+        /** Barring for emergency services, either CS or emergency MMTEL */
+        EMERGENCY,
+        /** Barring for short message services */
+        SMS,
+
+        /** Operator-specific barring codes; applicable to NGRAN */
+        OPERATOR_1 = 1001,
+        OPERATOR_2 = 1002,
+        OPERATOR_3 = 1003,
+        OPERATOR_4 = 1004,
+        OPERATOR_5 = 1005,
+        OPERATOR_6 = 1006,
+        OPERATOR_7 = 1007,
+        OPERATOR_8 = 1008,
+        OPERATOR_9 = 1009,
+        OPERATOR_10 = 1010,
+        OPERATOR_11 = 1011,
+        OPERATOR_12 = 1012,
+        OPERATOR_13 = 1013,
+        OPERATOR_14 = 1014,
+        OPERATOR_15 = 1015,
+        OPERATOR_16 = 1016,
+        OPERATOR_17 = 1017,
+        OPERATOR_18 = 1018,
+        OPERATOR_19 = 1019,
+        OPERATOR_20 = 1020,
+        OPERATOR_21 = 1021,
+        OPERATOR_22 = 1022,
+        OPERATOR_23 = 1023,
+        OPERATOR_24 = 1024,
+        OPERATOR_25 = 1025,
+        OPERATOR_26 = 1026,
+        OPERATOR_27 = 1027,
+        OPERATOR_28 = 1028,
+        OPERATOR_29 = 1029,
+        OPERATOR_30 = 1030,
+        OPERATOR_31 = 1031,
+        OPERATOR_32 = 1032,
+    } serviceType;
 
     /** The type of barring applied to the service */
-    BarringType type;
+    enum BarringType : int32_t {
+        /** Device is not barred for the given service */
+        NONE,
+        /** Device may be barred based on time and probability factors */
+        CONDITIONAL,
+        /* Device is unconditionally barred */
+        UNCONDITIONAL,
+    } barringType;
 
     /** Type-specific barring info if applicable */
-    BarringTypeSpecificInfo typeSpecificInfo;
+    safe_union BarringTypeSpecificInfo {
+        /** Barring type is either none or unconditional */
+        Monostate noinit;
+
+        /** Must be included if barring is conditional */
+        struct Conditional {
+            /** The barring factor as a percentage 0-100 */
+            int32_t factor;
+
+            /** The number of seconds between re-evaluations of barring */
+            int32_t timeSeconds;
+
+            /**
+             * Indicates whether barring is currently being applied.
+             *
+             * <p>True if the UE applies barring to a conditionally barred
+             * service based on the conditional barring parameters.
+             *
+             * <p>False if the service is conditionally barred but barring
+             * is not currently applied, which could be due to either the
+             * barring criteria not having been evaluated (if the UE has not
+             * attempted to use the service) or due to the criteria being
+             * evaluated and the UE being permitted to use the service
+             * despite conditional barring.
+             */
+            bool isBarred;
+        } conditional;
+    } barringTypeSpecificInfo;
 };
 
 enum IndicationFilter : @1.2::IndicationFilter {
diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp
index 85c4f99..cd30f7d 100644
--- a/radio/1.5/vts/functional/Android.bp
+++ b/radio/1.5/vts/functional/Android.bp
@@ -36,5 +36,5 @@
         "android.hardware.radio.config@1.1",
     ],
     header_libs: ["radio.util.header@1.0"],
-    test_suites: ["general-tests"]
+    test_suites: ["general-tests", "vts-core"]
 }
diff --git a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
index 5f11d19..31466c5 100644
--- a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
+++ b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
@@ -16,11 +16,7 @@
 
 #include <radio_hidl_hal_utils_v1_5.h>
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    RadioHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(PerInstance, RadioHidlTest_v1_5,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 android::hardware::radio::V1_5::IRadio::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
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 7294b9e..003f58e 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -21,7 +21,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() with invalid hysteresisDb
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_invalidHysteresisDb) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_invalidHysteresisDb) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -46,7 +46,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() with empty thresholds
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_EmptyThresholds) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_EmptyThresholds) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -70,7 +70,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() for GERAN
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Geran) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Geran) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -95,7 +95,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() for UTRAN
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Utran) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Utran) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -120,7 +120,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRP) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRP) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -145,7 +145,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRQ) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSRQ) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -170,7 +170,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSSNR) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Eutran_RSSNR) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -191,7 +191,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() for CDMA2000
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Cdma2000) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Cdma2000) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -216,7 +216,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSRSRP
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRP) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -241,7 +241,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSRSRQ
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSRSRQ) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -266,7 +266,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() for EUTRAN
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Disable_RSSNR) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_Disable_RSSNR) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -287,7 +287,7 @@
 /*
  * Test IRadio.setSignalStrengthReportingCriteria_1_5() for NGRAN_SSSINR
  */
-TEST_F(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) {
+TEST_P(RadioHidlTest_v1_5, setSignalStrengthReportingCriteria_1_5_NGRAN_SSSINR) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::SignalThresholdInfo signalThresholdInfo;
@@ -312,7 +312,7 @@
 /*
  * Test IRadio.setLinkCapacityReportingCriteria_1_5() invalid hysteresisDlKbps
  */
-TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisDlKbps) {
+TEST_P(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisDlKbps) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_5->setLinkCapacityReportingCriteria_1_5(
@@ -337,7 +337,7 @@
 /*
  * Test IRadio.setLinkCapacityReportingCriteria_1_5() invalid hysteresisUlKbps
  */
-TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisUlKbps) {
+TEST_P(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_invalidHysteresisUlKbps) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_5->setLinkCapacityReportingCriteria_1_5(
@@ -362,7 +362,7 @@
 /*
  * Test IRadio.setLinkCapacityReportingCriteria_1_5() empty params
  */
-TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_emptyParams) {
+TEST_P(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_emptyParams) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_5->setLinkCapacityReportingCriteria_1_5(
@@ -383,7 +383,7 @@
 /*
  * Test IRadio.setLinkCapacityReportingCriteria_1_5() for GERAN
  */
-TEST_F(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_Geran) {
+TEST_P(RadioHidlTest_v1_5, setLinkCapacityReportingCriteria_1_5_Geran) {
     serial = GetRandomSerialNumber();
 
     Return<void> res = radio_v1_5->setLinkCapacityReportingCriteria_1_5(
@@ -406,7 +406,7 @@
  * Test IRadio.enableUiccApplications() for the response returned.
  * For SIM ABSENT case.
  */
-TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) {
+TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) {
     // This test case only test SIM ABSENT case.
     if (cardStatus.base.base.cardState != CardState::ABSENT) return;
 
@@ -433,7 +433,7 @@
  * Test IRadio.enableUiccApplications() for the response returned.
  * For SIM PRESENT case.
  */
-TEST_F(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) {
+TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) {
     // This test case only test SIM ABSENT case.
     if (cardStatus.base.base.cardState != CardState::PRESENT) return;
 
@@ -479,7 +479,7 @@
 /*
  * Test IRadio.areUiccApplicationsEnabled() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_5, areUiccApplicationsEnabled) {
+TEST_P(RadioHidlTest_v1_5, areUiccApplicationsEnabled) {
     // Disable Uicc applications.
     serial = GetRandomSerialNumber();
     radio_v1_5->areUiccApplicationsEnabled(serial);
@@ -499,7 +499,7 @@
 /*
  * Test IRadio.setSystemSelectionChannels_1_5() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_5, setSystemSelectionChannels_1_5) {
+TEST_P(RadioHidlTest_v1_5, setSystemSelectionChannels_1_5) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
@@ -537,7 +537,7 @@
 /*
  * Test IRadio.startNetworkScan_1_5() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_5, startNetworkScan) {
+TEST_P(RadioHidlTest_v1_5, startNetworkScan) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
@@ -578,7 +578,7 @@
 /*
  * Test IRadio.startNetworkScan_1_5() with invalid specifier.
  */
-TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidArgument) {
+TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidArgument) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::NetworkScanRequest request = {.type = ScanType::ONE_SHOT,
@@ -605,7 +605,7 @@
 /*
  * Test IRadio.startNetworkScan_1_5() with invalid interval (lower boundary).
  */
-TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval1) {
+TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval1) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
@@ -644,7 +644,7 @@
 /*
  * Test IRadio.startNetworkScan_1_5() with invalid interval (upper boundary).
  */
-TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval2) {
+TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidInterval2) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
@@ -683,7 +683,7 @@
 /*
  * Test IRadio.startNetworkScan_1_5() with invalid max search time (lower boundary).
  */
-TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime1) {
+TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime1) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
@@ -722,7 +722,7 @@
 /*
  * Test IRadio.startNetworkScan_1_5() with invalid max search time (upper boundary).
  */
-TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime2) {
+TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidMaxSearchTime2) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
@@ -761,7 +761,7 @@
 /*
  * Test IRadio.startNetworkScan_1_5() with invalid periodicity (lower boundary).
  */
-TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity1) {
+TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity1) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
@@ -800,7 +800,7 @@
 /*
  * Test IRadio.startNetworkScan_1_5() with invalid periodicity (upper boundary).
  */
-TEST_F(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity2) {
+TEST_P(RadioHidlTest_v1_5, startNetworkScan_InvalidPeriodicity2) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
@@ -839,7 +839,7 @@
 /*
  * Test IRadio.startNetworkScan_1_5() with valid periodicity
  */
-TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest1) {
+TEST_P(RadioHidlTest_v1_5, startNetworkScan_GoodRequest1) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
@@ -878,7 +878,7 @@
 /*
  * Test IRadio.startNetworkScan_1_5() with valid periodicity and plmns
  */
-TEST_F(RadioHidlTest_v1_5, startNetworkScan_GoodRequest2) {
+TEST_P(RadioHidlTest_v1_5, startNetworkScan_GoodRequest2) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands rasBands;
@@ -918,7 +918,7 @@
 /*
  * Test IRadio.setupDataCall_1_5() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_5, setupDataCall_1_5) {
+TEST_P(RadioHidlTest_v1_5, setupDataCall_1_5) {
     serial = GetRandomSerialNumber();
 
     ::android::hardware::radio::V1_5::AccessNetwork accessNetwork =
@@ -975,7 +975,7 @@
 /*
  * Test IRadio.setInitialAttachApn_1_5() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_5, setInitialAttachApn_1_5) {
+TEST_P(RadioHidlTest_v1_5, setInitialAttachApn_1_5) {
     serial = GetRandomSerialNumber();
 
     // Create a dataProfileInfo
@@ -1018,7 +1018,7 @@
 /*
  * Test IRadio.setDataProfile_1_5() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_5, setDataProfile_1_5) {
+TEST_P(RadioHidlTest_v1_5, setDataProfile_1_5) {
     serial = GetRandomSerialNumber();
 
     // Create a dataProfileInfo
@@ -1065,7 +1065,7 @@
 /*
  * Test IRadio.setRadioPower_1_5() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancelled) {
+TEST_P(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancelled) {
     // Set radio power to off.
     serial = GetRandomSerialNumber();
     radio_v1_5->setRadioPower_1_5(serial, false, false, false);
@@ -1096,7 +1096,7 @@
 /*
  * Test IRadio.setNetworkSelectionModeManual_1_5() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_5, setNetworkSelectionModeManual_1_5) {
+TEST_P(RadioHidlTest_v1_5, setNetworkSelectionModeManual_1_5) {
     serial = GetRandomSerialNumber();
 
     // can't camp on nonexistent MCCMNC, so we expect this to fail.
@@ -1122,7 +1122,7 @@
 /*
  * Test IRadio.sendCdmaSmsExpectMore() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) {
+TEST_P(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) {
     serial = GetRandomSerialNumber();
 
     // Create a CdmaSmsAddress
@@ -1147,7 +1147,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);
 
@@ -1157,8 +1157,115 @@
 
     if (cardStatus.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));
     }
 }
+
+/*
+ * Test IRadio.getBarringInfo() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_5, getBarringInfo) {
+    serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_5->getBarringInfo(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+
+    ASSERT_TRUE(radioRsp_v1_5->barringInfos.size() > 0);
+
+    std::set<BarringInfo::ServiceType> reportedServices;
+
+    // validate that the service types are in range
+    for (const auto& info : radioRsp_v1_5->barringInfos) {
+        ASSERT_TRUE((info.serviceType >= BarringInfo::ServiceType::CS_SERVICE &&
+                     info.serviceType <= BarringInfo::ServiceType::SMS) ||
+                    (info.serviceType >= BarringInfo::ServiceType::OPERATOR_1 &&
+                     info.serviceType <= BarringInfo::ServiceType::OPERATOR_32));
+        reportedServices.insert(info.serviceType);
+
+        // Any type that is "conditional" must have sane values for conditional barring
+        // factor and time.
+        switch (info.barringType) {
+            case BarringInfo::BarringType::NONE:  // fall through
+            case BarringInfo::BarringType::UNCONDITIONAL:
+                break;
+            case BarringInfo::BarringType::CONDITIONAL: {
+                const int32_t barringFactor = info.barringTypeSpecificInfo.conditional().factor;
+                ASSERT_TRUE(barringFactor >= 0 && barringFactor <= 100);
+                ASSERT_TRUE(info.barringTypeSpecificInfo.conditional().timeSeconds > 0);
+                break;
+            }
+            default:
+                FAIL();
+        }
+    }
+
+    // Certain types of barring are relevant for certain RANs. Ensure that only the right
+    // types are reported. Note that no types are required, simply that for a given technology
+    // only certain types are valid. This is one way to sanity check that implementations are
+    // not providing information that they don't have.
+    static const std::set<BarringInfo::ServiceType> UTRA_SERVICES{
+            BarringInfo::ServiceType::CS_SERVICE, BarringInfo::ServiceType::PS_SERVICE,
+            BarringInfo::ServiceType::CS_VOICE,   BarringInfo::ServiceType::EMERGENCY,
+            BarringInfo::ServiceType::SMS,
+    };
+
+    static const std::set<BarringInfo::ServiceType> EUTRA_SERVICES{
+            BarringInfo::ServiceType::MO_SIGNALLING, BarringInfo::ServiceType::MO_DATA,
+            BarringInfo::ServiceType::CS_FALLBACK,   BarringInfo::ServiceType::MMTEL_VOICE,
+            BarringInfo::ServiceType::MMTEL_VIDEO,   BarringInfo::ServiceType::EMERGENCY,
+            BarringInfo::ServiceType::SMS,
+    };
+
+    static const std::set<BarringInfo::ServiceType> NGRA_SERVICES = {
+            BarringInfo::ServiceType::MO_SIGNALLING, BarringInfo::ServiceType::MO_DATA,
+            BarringInfo::ServiceType::CS_FALLBACK,   BarringInfo::ServiceType::MMTEL_VOICE,
+            BarringInfo::ServiceType::MMTEL_VIDEO,   BarringInfo::ServiceType::EMERGENCY,
+            BarringInfo::ServiceType::SMS,           BarringInfo::ServiceType::OPERATOR_1,
+            BarringInfo::ServiceType::OPERATOR_2,    BarringInfo::ServiceType::OPERATOR_3,
+            BarringInfo::ServiceType::OPERATOR_4,    BarringInfo::ServiceType::OPERATOR_5,
+            BarringInfo::ServiceType::OPERATOR_6,    BarringInfo::ServiceType::OPERATOR_7,
+            BarringInfo::ServiceType::OPERATOR_8,    BarringInfo::ServiceType::OPERATOR_9,
+            BarringInfo::ServiceType::OPERATOR_10,   BarringInfo::ServiceType::OPERATOR_11,
+            BarringInfo::ServiceType::OPERATOR_12,   BarringInfo::ServiceType::OPERATOR_13,
+            BarringInfo::ServiceType::OPERATOR_14,   BarringInfo::ServiceType::OPERATOR_15,
+            BarringInfo::ServiceType::OPERATOR_16,   BarringInfo::ServiceType::OPERATOR_17,
+            BarringInfo::ServiceType::OPERATOR_18,   BarringInfo::ServiceType::OPERATOR_19,
+            BarringInfo::ServiceType::OPERATOR_20,   BarringInfo::ServiceType::OPERATOR_21,
+            BarringInfo::ServiceType::OPERATOR_22,   BarringInfo::ServiceType::OPERATOR_23,
+            BarringInfo::ServiceType::OPERATOR_24,   BarringInfo::ServiceType::OPERATOR_25,
+            BarringInfo::ServiceType::OPERATOR_26,   BarringInfo::ServiceType::OPERATOR_27,
+            BarringInfo::ServiceType::OPERATOR_28,   BarringInfo::ServiceType::OPERATOR_29,
+            BarringInfo::ServiceType::OPERATOR_30,   BarringInfo::ServiceType::OPERATOR_31,
+    };
+
+    const std::set<BarringInfo::ServiceType>* compareTo = nullptr;
+
+    switch (radioRsp_v1_5->barringCellIdentity.getDiscriminator()) {
+        case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::wcdma:
+            // fall through
+        case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::tdscdma:
+            compareTo = &UTRA_SERVICES;
+            break;
+        case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::lte:
+            compareTo = &EUTRA_SERVICES;
+            break;
+        case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::nr:
+            compareTo = &NGRA_SERVICES;
+            break;
+
+        case android::hardware::radio::V1_5::CellIdentity::hidl_discriminator::cdma:
+            // fall through
+        default:
+            FAIL();
+            break;
+    }
+
+    std::set<BarringInfo::ServiceType> diff;
+
+    std::set_difference(reportedServices.begin(), reportedServices.end(), compareTo->begin(),
+                        compareTo->end(), std::inserter(diff, diff.begin()));
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
index a5d236d..ca6bbeb 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
@@ -17,19 +17,7 @@
 #include <radio_hidl_hal_utils_v1_5.h>
 
 void RadioHidlTest_v1_5::SetUp() {
-    radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService<
-            ::android::hardware::radio::V1_5::IRadio>(
-            RadioHidlEnvironment::Instance()
-                    ->getServiceName<::android::hardware::radio::V1_5::IRadio>(
-                            hidl_string(RADIO_SERVICE_NAME)));
-    if (radio_v1_5 == NULL) {
-        sleep(60);
-        radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService<
-                ::android::hardware::radio::V1_5::IRadio>(
-                RadioHidlEnvironment::Instance()
-                        ->getServiceName<::android::hardware::radio::V1_5::IRadio>(
-                                hidl_string(RADIO_SERVICE_NAME)));
-    }
+    radio_v1_5 = android::hardware::radio::V1_5::IRadio::getService(GetParam());
     ASSERT_NE(nullptr, radio_v1_5.get());
 
     radioRsp_v1_5 = new (std::nothrow) RadioResponse_v1_5(*this);
@@ -48,10 +36,8 @@
     EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
 
     sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig =
-            ::testing::VtsHalHidlTargetTestBase::getService<
-                    ::android::hardware::radio::config::V1_1::IRadioConfig>();
-
-    /* Enforce Vts tesing with RadioConfig is existed. */
+            ::android::hardware::radio::config::V1_1::IRadioConfig::getService();
+    /* Enforce Vts testing with RadioConfig is existed. */
     ASSERT_NE(nullptr, radioConfig.get());
 
     /* Enforce Vts Testing with Sim Status Present only. */
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index 77ec01e..6488609 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
+#pragma once
+
 #include <android-base/logging.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <utils/Log.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -86,6 +90,10 @@
     // Whether Uicc applications are enabled or not.
     bool areUiccApplicationsEnabled;
 
+    // Barring Info Response
+    ::android::hardware::radio::V1_5::CellIdentity barringCellIdentity;
+    ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo> barringInfos;
+
     RadioResponse_v1_5(RadioHidlTest_v1_5& parent_v1_5);
     virtual ~RadioResponse_v1_5() = default;
 
@@ -558,6 +566,7 @@
 
     Return<void> getBarringInfoResponse(
             const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>&
                     barringInfos);
 
@@ -794,24 +803,8 @@
             /*barringInfos*/);
 };
 
-// Test environment for Radio HIDL HAL.
-class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-  public:
-    // get the test environment singleton
-    static RadioHidlEnvironment* Instance() {
-        static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
-        return instance;
-    }
-    virtual void registerTestServices() override {
-        registerTestService<::android::hardware::radio::V1_5::IRadio>();
-    }
-
-  private:
-    RadioHidlEnvironment() {}
-};
-
 // The main test class for Radio HIDL.
-class RadioHidlTest_v1_5 : public ::testing::VtsHalHidlTargetTestBase {
+class RadioHidlTest_v1_5 : public ::testing::TestWithParam<std::string> {
   protected:
     std::mutex mtx_;
     std::condition_variable cv_;
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index ce14af5..e4f9ce8 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -970,8 +970,11 @@
 
 Return<void> RadioResponse_v1_5::getBarringInfoResponse(
         const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity,
         const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>&
-        /*barringInfos*/) {
+                barringInfos) {
+    this->barringCellIdentity = cellIdentity;
+    this->barringInfos = barringInfos;
     rspInfo = info;
     parent_v1_5.notify(info.serial);
     return Void();
diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp
new file mode 100644
index 0000000..0742939
--- /dev/null
+++ b/rebootescrow/aidl/Android.bp
@@ -0,0 +1,18 @@
+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,
+            },
+        },
+    },
+}
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..d2422b9
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtils.cpp
@@ -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.
+ */
+
+#include <HadamardUtils.h>
+
+#include <limits>
+
+#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;
+}
+
+// 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;
+            }
+        }
+    }
+    auto hiscore = std::numeric_limits<int32_t>::min();
+    uint16_t winner;
+    // TODO(b/146520538): this needs to be constant time
+    for (size_t i = 0; i < ENCODE_LENGTH; i++) {
+        if (scores[i] > hiscore) {
+            winner = i;
+            hiscore = scores[i];
+
+        } else if (-scores[i] > hiscore) {
+            winner = i | (1 << CODE_K);
+            hiscore = -scores[i];
+        }
+    }
+    return winner;
+}
+
+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..dbc0921
--- /dev/null
+++ b/rebootescrow/aidl/default/RebootEscrow.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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<int8_t>& kek) {
+    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));
+    }
+
+    std::vector<uint8_t> ukek(kek.begin(), kek.end());
+    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<int8_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);
+
+    std::vector<int8_t> signedKeyBytes(keyBytes.begin(), keyBytes.end());
+    *_aidl_return = signedKeyBytes;
+    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..00ff16b
--- /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<int8_t>& kek) override;
+    ndk::ScopedAStatus retrieveKey(std::vector<int8_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/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
new file mode 100644
index 0000000..cd8cc3e
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
@@ -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.
+ */
+
+#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,
+    };
+};
+
+TEST_P(RebootEscrowAidlTest, 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);
+}
+
+TEST_P(RebootEscrowAidlTest, 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);
+}
+
+TEST_P(RebootEscrowAidlTest, 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);
+}
+
+TEST_P(RebootEscrowAidlTest, 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);
+}
+
+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..aaefccb 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -20,7 +20,7 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "SensorsHidlEnvironmentV1_0.cpp",
-        "VtsHalSensorsV1_0TargetTest.cpp"
+        "VtsHalSensorsV1_0TargetTest.cpp",
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
@@ -31,6 +31,8 @@
         "android.hardware.sensors@1.0",
         "VtsHalSensorsTargetTestUtils",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
-
diff --git a/sensors/1.0/vts/functional/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 2cad54d..e298651 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -33,8 +33,7 @@
 using namespace ::android::hardware::sensors::V1_0;
 
 // The main test class for SENSORS HIDL HAL.
-
-class SensorsHidlTest : public SensorsHidlTestBase {
+class SensorsHidlTest : public SensorsHidlTestBase<SensorType, Event, SensorInfo> {
   public:
     virtual void SetUp() override {
         mEnvironment = new SensorsHidlEnvironmentV1_0(GetParam());
@@ -80,7 +79,7 @@
 
     inline sp<ISensors>& S() { return mEnvironment->sensors; }
 
-    SensorsHidlEnvironmentBase* getEnvironment() override { return mEnvironment; }
+    SensorsHidlEnvironmentBase<Event>* getEnvironment() override { return mEnvironment; }
 
   private:
     // Test environment for sensors HAL.
@@ -257,55 +256,55 @@
 // Test if sensor hal can do UI speed accelerometer streaming properly
 TEST_P(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
     testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), sAccelNormChecker);
+                           std::chrono::seconds(5), mAccelNormChecker);
 }
 
 // Test if sensor hal can do normal speed accelerometer streaming properly
 TEST_P(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
     testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), sAccelNormChecker);
+                           std::chrono::seconds(5), mAccelNormChecker);
 }
 
 // Test if sensor hal can do game speed accelerometer streaming properly
 TEST_P(SensorsHidlTest, AccelerometerStreamingOperationFast) {
     testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), sAccelNormChecker);
+                           std::chrono::seconds(5), mAccelNormChecker);
 }
 
 // Test if sensor hal can do UI speed gyroscope streaming properly
 TEST_P(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
     testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), sGyroNormChecker);
+                           std::chrono::seconds(5), mGyroNormChecker);
 }
 
 // Test if sensor hal can do normal speed gyroscope streaming properly
 TEST_P(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
     testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), sGyroNormChecker);
+                           std::chrono::seconds(5), mGyroNormChecker);
 }
 
 // Test if sensor hal can do game speed gyroscope streaming properly
 TEST_P(SensorsHidlTest, GyroscopeStreamingOperationFast) {
     testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), sGyroNormChecker);
+                           std::chrono::seconds(5), mGyroNormChecker);
 }
 
 // Test if sensor hal can do UI speed magnetometer streaming properly
 TEST_P(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
     testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200),
-                           std::chrono::seconds(5), NullChecker());
+                           std::chrono::seconds(5), NullChecker<Event>());
 }
 
 // Test if sensor hal can do normal speed magnetometer streaming properly
 TEST_P(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
     testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20),
-                           std::chrono::seconds(5), NullChecker());
+                           std::chrono::seconds(5), NullChecker<Event>());
 }
 
 // Test if sensor hal can do game speed magnetometer streaming properly
 TEST_P(SensorsHidlTest, MagnetometerStreamingOperationFast) {
     testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5),
-                           std::chrono::seconds(5), NullChecker());
+                           std::chrono::seconds(5), NullChecker<Event>());
 }
 
 // Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
@@ -344,109 +343,109 @@
 // Test sensor event direct report with ashmem for accel sensor at normal rate
 TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              sAccelNormChecker);
+                              mAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for accel sensor at fast rate
 TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
-                              sAccelNormChecker);
+                              mAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for accel sensor at very fast rate
 TEST_P(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM,
-                              RateLevel::VERY_FAST, sAccelNormChecker);
+                              RateLevel::VERY_FAST, mAccelNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at normal rate
 TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at fast rate
 TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for gyro sensor at very fast rate
 TEST_P(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with ashmem for mag sensor at normal rate
 TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
-                              NullChecker());
+                              NullChecker<Event>());
 }
 
 // Test sensor event direct report with ashmem for mag sensor at fast rate
 TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
-                              NullChecker());
+                              NullChecker<Event>());
 }
 
 // Test sensor event direct report with ashmem for mag sensor at very fast rate
 TEST_P(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM,
-                              RateLevel::VERY_FAST, NullChecker());
+                              RateLevel::VERY_FAST, NullChecker<Event>());
 }
 
 // Test sensor event direct report with gralloc for accel sensor at normal rate
 TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              sAccelNormChecker);
+                              mAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for accel sensor at fast rate
 TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
-                              sAccelNormChecker);
+                              mAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for accel sensor at very fast rate
 TEST_P(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC,
-                              RateLevel::VERY_FAST, sAccelNormChecker);
+                              RateLevel::VERY_FAST, mAccelNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at normal rate
 TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at fast rate
 TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for gyro sensor at very fast rate
 TEST_P(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
-                              sGyroNormChecker);
+                              mGyroNormChecker);
 }
 
 // Test sensor event direct report with gralloc for mag sensor at normal rate
 TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
-                              NullChecker());
+                              NullChecker<Event>());
 }
 
 // Test sensor event direct report with gralloc for mag sensor at fast rate
 TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
-                              NullChecker());
+                              NullChecker<Event>());
 }
 
 // Test sensor event direct report with gralloc for mag sensor at very fast rate
 TEST_P(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
     testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC,
-                              RateLevel::VERY_FAST, NullChecker());
+                              RateLevel::VERY_FAST, NullChecker<Event>());
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/sensors/2.0/default/Android.bp b/sensors/2.0/default/Android.bp
index 62c9487..bb38327 100644
--- a/sensors/2.0/default/Android.bp
+++ b/sensors/2.0/default/Android.bp
@@ -20,13 +20,17 @@
     relative_install_path: "hw",
     srcs: [
         "service.cpp",
-        "Sensor.cpp",
-        "Sensors.cpp",
     ],
     init_rc: ["android.hardware.sensors@2.0-service-mock.rc"],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
     shared_libs: [
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
+        // Needed to compile some shared utilities for both 2.0/2.1 impls, but
+        // isn't normally needed for a HAL that only supports 2.0.
+        "android.hardware.sensors@2.1",
         "libcutils",
         "libfmq",
         "libhidlbase",
@@ -34,5 +38,9 @@
         "libpower",
         "libutils",
     ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.X-shared-impl",
+    ],
     vintf_fragments: ["android.hardware.sensors@2.0.xml"],
 }
diff --git a/sensors/2.0/default/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..7213b44 100644
--- a/sensors/2.0/multihal/Android.bp
+++ b/sensors/2.0/multihal/Android.bp
@@ -13,14 +13,21 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_defaults {
-    name: "android.hardware.sensors@2.0-multihal-defaults",
-    header_libs: [
-        "android.hardware.sensors@2.0-multihal.header",
+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"],
     shared_libs: [
-        "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.0-ScopedWakelock",
         "libbase",
         "libcutils",
         "libfmq",
@@ -29,81 +36,5 @@
         "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@2.X-multihal"],
 }
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/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
index 4765fa2..08c59b6 100644
--- a/sensors/2.0/vts/functional/Android.bp
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -19,8 +19,10 @@
     cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "SensorsHidlEnvironmentV2_0.cpp",
-        "VtsHalSensorsV2_0TargetTest.cpp"
+        "VtsHalSensorsV2_0TargetTest.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
@@ -29,9 +31,15 @@
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
+        "android.hardware.sensors@1.0-convert",
         "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
         "libfmq",
         "VtsHalSensorsTargetTestUtils",
+        "VtsHalSensorsV2_0TargetTest-lib",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
     ],
 }
-
diff --git a/sensors/2.0/vts/functional/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 540529d..a0d436f 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -14,1070 +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 non-empty type string
-            EXPECT_FALSE(s.typeAsString.empty());
-
-            // Test defined type matches defined string type
-            EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
-
-            // Test if all sensor has name and vendor
-            EXPECT_FALSE(s.name.empty());
-            EXPECT_FALSE(s.vendor.empty());
-
-            // Test power > 0, maxRange > 0
-            EXPECT_LE(0, s.power);
-            EXPECT_LT(0, s.maxRange);
-
-            // Info type, should have no sensor
-            EXPECT_FALSE(s.type == SensorType::ADDITIONAL_INFO || s.type == SensorType::META_DATA);
-
-            // Test fifoMax >= fifoReserved
-            EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
-                << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
-
-            // Test Reporting mode valid
-            EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
-
-            // Test min max are in the right order
-            EXPECT_LE(s.minDelay, s.maxDelay);
-            // Test min/max delay matches reporting mode
-            EXPECT_NO_FATAL_FAILURE(
-                assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
-        }
-    });
-}
-
-// 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);
-
-    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)) {
@@ -1094,7 +229,7 @@
     constexpr size_t kNumEvents = 1;
     constexpr size_t kMemSize = kNumEvents * kEventSize;
 
-    SensorInfo sensor;
+    SensorInfoType sensor;
     SharedMemType memType;
     RateLevel rate;
 
@@ -1102,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;
@@ -1114,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
@@ -1129,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..8e80e1f
--- /dev/null
+++ b/sensors/2.1/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.sensors@2.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ISensors.hal",
+        "ISensorsCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/sensors/2.1/ISensors.hal b/sensors/2.1/ISensors.hal
new file mode 100644
index 0000000..d401fa5
--- /dev/null
+++ b/sensors/2.1/ISensors.hal
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors@2.1;
+
+import @1.0::Result;
+import @2.0::ISensors;
+import @2.1::ISensorsCallback;
+
+interface ISensors extends @2.0::ISensors {
+    /**
+     * Enumerate all available (static) sensors.
+     *
+     * The SensorInfo for each sensor returned by getSensorsList must be stable
+     * from the initial call to getSensorsList after a device boot until the
+     * entire system restarts. The SensorInfo for each sensor must not change
+     * between subsequent calls to getSensorsList, even across restarts of the
+     * HAL and its dependencies (for example, the sensor handle for a given
+     * sensor must not change across HAL restarts).
+     */
+    getSensorsList_2_1() generates (vec<SensorInfo> list);
+
+    /**
+     * Initialize the Sensors HAL's Fast Message Queues (FMQ) and callback.
+     *
+     * The Fast Message Queues (FMQ) that are used to send data between the
+     * framework and the HAL. The callback is used by the HAL to notify the
+     * framework of asynchronous events, such as a dynamic sensor connection.
+     *
+     * The Event FMQ is used to transport sensor events from the HAL to the
+     * framework. The Event FMQ is created using the eventQueueDescriptor.
+     * Data may only be written to the Event FMQ. Data must not be read from
+     * the Event FMQ since the framework is the only reader. Upon receiving
+     * sensor events, the HAL writes the sensor events to the Event FMQ.
+     *
+     * Once the HAL is finished writing sensor events to the Event FMQ, the HAL
+     * must notify the framework that sensor events are available to be read and
+     * processed. This is accomplished by either:
+     *     1) Calling the Event FMQ’s EventFlag::wake() function with
+              EventQueueFlagBits::READ_AND_PROCESS
+     *     2) Setting the write notification in the Event FMQ’s writeBlocking()
+     *        function to EventQueueFlagBits::READ_AND_PROCESS.
+     *
+     * If the Event FMQ’s writeBlocking() function is used, the read
+     * notification must be set to EventQueueFlagBits::EVENTS_READ in order to
+     * be notified and unblocked when the framework has successfully read events
+     * from the Event FMQ.
+     *
+     * The Wake Lock FMQ is used by the framework to notify the HAL when it is
+     * safe to release its wake_lock. When the framework receives WAKE_UP events
+     * from the Event FMQ and the framework has acquired a wake_lock, the
+     * framework must write the number of WAKE_UP events processed to the Wake
+     * Lock FMQ. When the HAL reads the data from the Wake Lock FMQ, the HAL
+     * decrements its current count of unprocessed WAKE_UP events and releases
+     * its wake_lock if the current count of unprocessed WAKE_UP events is
+     * zero. It is important to note that the HAL must acquire the wake lock and
+     * update its internal state regarding the number of outstanding WAKE_UP
+     * events _before_ posting the event to the Wake Lock FMQ, in order to avoid
+     * a race condition that can lead to loss of wake lock synchronization with
+     * the framework.
+     *
+     * The framework must use the WakeLockQueueFlagBits::DATA_WRITTEN value to
+     * notify the HAL that data has been written to the Wake Lock FMQ and must
+     * be read by HAL.
+     *
+     * The ISensorsCallback is used by the HAL to notify the framework of
+     * asynchronous events, such as a dynamic sensor connection.
+     *
+     * The name of any wake_lock acquired by the Sensors HAL for WAKE_UP events
+     * must begin with "SensorsHAL_WAKEUP".
+     *
+     * If WAKE_LOCK_TIMEOUT_SECONDS has elapsed since the most recent WAKE_UP
+     * event was written to the Event FMQ without receiving a message on the
+     * Wake Lock FMQ, then any held wake_lock for WAKE_UP events must be
+     * released.
+     *
+     * If either the Event FMQ or the Wake Lock FMQ is already initialized when
+     * initialize is invoked, then both existing FMQs must be discarded and the
+     * new descriptors must be used to create new FMQs within the HAL. The
+     * number of outstanding WAKE_UP events should also be reset to zero, and
+     * any outstanding wake_locks held as a result of WAKE_UP events should be
+     * released.
+     *
+     * All active sensor requests and direct channels must be closed and
+     * properly cleaned up when initialize is called in order to ensure that the
+     * HAL and framework's state is consistent (e.g. after a runtime restart).
+     *
+     * initialize must be thread safe and prevent concurrent calls
+     * to initialize from simultaneously modifying state.
+     *
+     * @param eventQueueDescriptor Fast Message Queue descriptor that is used to
+     *     create the Event FMQ which is where sensor events are written. The
+     *     descriptor is obtained from the framework's FMQ that is used to read
+     *     sensor events.
+     * @param wakeLockDescriptor Fast Message Queue descriptor that is used to
+     *     create the Wake Lock FMQ which is where wake_lock events are read
+     *     from. The descriptor is obtained from the framework's FMQ that is
+     *     used to write wake_lock events.
+     * @param sensorsCallback sensors callback that receives asynchronous data
+     *     from the Sensors HAL.
+     * @return result OK on success; BAD_VALUE if descriptor is invalid (such
+     *     as null)
+     */
+    @entry
+    @callflow(next = {"getSensorsList"})
+    initialize_2_1(fmq_sync<Event> eventQueueDescriptor,
+                   fmq_sync<uint32_t> wakeLockDescriptor,
+                   ISensorsCallback sensorsCallback)
+        generates
+              (Result result);
+
+    /**
+     * Inject a single sensor event or push operation environment parameters to
+     * device.
+     *
+     * When device is in NORMAL mode, this function is called to push operation
+     * environment data to device. In this operation, Event is always of
+     * SensorType::AdditionalInfo type. See operation evironment parameters
+     * section in AdditionalInfoType.
+     *
+     * When device is in DATA_INJECTION mode, this function is also used for
+     * injecting sensor events.
+     *
+     * Regardless of OperationMode, injected SensorType::ADDITIONAL_INFO
+     * type events should not be routed back to the sensor event queue.
+     *
+     * @see AdditionalInfoType
+     * @see OperationMode
+     * @param event sensor event to be injected
+     * @return result OK on success; PERMISSION_DENIED if operation is not
+     *     allowed; INVALID_OPERATION, if this functionality is unsupported;
+     *     BAD_VALUE if sensor event cannot be injected.
+     */
+    injectSensorData_2_1(Event event) generates (Result result);
+};
diff --git a/sensors/2.1/ISensorsCallback.hal b/sensors/2.1/ISensorsCallback.hal
new file mode 100644
index 0000000..de521d5
--- /dev/null
+++ b/sensors/2.1/ISensorsCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors@2.1;
+
+import @2.0::ISensorsCallback;
+import @2.1::SensorInfo;
+
+interface ISensorsCallback extends @2.0::ISensorsCallback {
+    /**
+     * Notify the framework that new dynamic sensors have been connected.
+     *
+     * If a dynamic sensor was previously connected and has not been
+     * disconnected, then that sensor must not be included in sensorInfos.
+     *
+     * @param sensorInfos vector of SensorInfo for each dynamic sensor that
+     *     was connected.
+     */
+    oneway onDynamicSensorsConnected_2_1(vec<SensorInfo> sensorInfos);
+};
diff --git a/sensors/2.1/default/Android.bp b/sensors/2.1/default/Android.bp
new file mode 100644
index 0000000..27b439d
--- /dev/null
+++ b/sensors/2.1/default/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+    name: "android.hardware.sensors@2.1-service.mock",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "SensorsV2_1.cpp",
+        "service.cpp",
+    ],
+    init_rc: ["android.hardware.sensors@2.1-service-mock.rc"],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.X-shared-impl",
+    ],
+    vintf_fragments: ["android.hardware.sensors@2.1.xml"],
+}
diff --git a/sensors/2.1/default/OWNERS b/sensors/2.1/default/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/sensors/2.1/default/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/sensors/2.1/default/SensorsV2_1.cpp b/sensors/2.1/default/SensorsV2_1.cpp
new file mode 100644
index 0000000..2e3d315
--- /dev/null
+++ b/sensors/2.1/default/SensorsV2_1.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorsV2_1.h"
+
+#include "Sensor.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+using V2_X::implementation::ISensorsEventCallback;
+using V2_X::implementation::OnChangeSensor;
+
+class HingeAngleSensor : public OnChangeSensor {
+  public:
+    HingeAngleSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+        : OnChangeSensor(callback) {
+        mSensorInfo.sensorHandle = sensorHandle;
+        mSensorInfo.name = "Hinge Angle Sensor";
+        mSensorInfo.vendor = "Vendor String";
+        mSensorInfo.version = 1;
+        mSensorInfo.type = SensorType::HINGE_ANGLE;
+        mSensorInfo.typeAsString = "";
+        mSensorInfo.maxRange = 360.0f;
+        mSensorInfo.resolution = 1.0f;
+        mSensorInfo.power = 0.001f;
+        mSensorInfo.minDelay = 40 * 1000;  // microseconds
+        mSensorInfo.maxDelay = V2_X::implementation::kDefaultMaxDelayUs;
+        mSensorInfo.fifoReservedEventCount = 0;
+        mSensorInfo.fifoMaxEventCount = 0;
+        mSensorInfo.requiredPermission = "";
+        mSensorInfo.flags = static_cast<uint32_t>(V1_0::SensorFlagBits::ON_CHANGE_MODE);
+    }
+};
+
+SensorsV2_1::SensorsV2_1() {
+    AddSensor<HingeAngleSensor>();
+}
+
+// Methods from ::android::hardware::sensors::V2_1::ISensors follow.
+Return<void> SensorsV2_1::getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        sensors.push_back(sensor.second->getSensorInfo());
+    }
+
+    // Call the HIDL callback with the SensorInfo
+    _hidl_cb(sensors);
+
+    return Void();
+}
+
+Return<Result> SensorsV2_1::initialize_2_1(
+        const ::android::hardware::MQDescriptorSync<V2_1::Event>& eventQueueDescriptor,
+        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+        const sp<V2_1::ISensorsCallback>& sensorsCallback) {
+    auto eventQueue = std::make_unique<MessageQueue<V2_1::Event, kSynchronizedReadWrite>>(
+            eventQueueDescriptor, true /* resetPointers */);
+    std::unique_ptr<EventMessageQueueWrapperBase> wrapper =
+            std::make_unique<EventMessageQueueWrapperV2_1>(eventQueue);
+    mCallbackWrapper = new ISensorsCallbackWrapper(sensorsCallback);
+    return initializeBase(wrapper, wakeLockDescriptor, mCallbackWrapper);
+}
+
+Return<Result> SensorsV2_1::injectSensorData_2_1(const V2_1::Event& event) {
+    return injectSensorData(convertToOldEvent(event));
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/sensors/2.1/default/SensorsV2_1.h b/sensors/2.1/default/SensorsV2_1.h
new file mode 100644
index 0000000..9f7fe04
--- /dev/null
+++ b/sensors/2.1/default/SensorsV2_1.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_1_H
+#define ANDROID_HARDWARE_SENSORS_V2_1_H
+
+#include "Sensors.h"
+
+#include "EventMessageQueueWrapper.h"
+
+#include <android/hardware/sensors/2.1/ISensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+using Result = ::android::hardware::sensors::V1_0::Result;
+using Sensors = ::android::hardware::sensors::V2_X::implementation::Sensors<ISensors>;
+
+class ISensorsCallbackWrapper : public V2_0::ISensorsCallback {
+  public:
+    ISensorsCallbackWrapper(const sp<V2_1::ISensorsCallback>& callback) : mCallback(callback) {}
+
+    Return<void> onDynamicSensorsConnected(const hidl_vec<V1_0::SensorInfo>& sensorInfos) override {
+        return mCallback->onDynamicSensorsConnected_2_1(convertToNewSensorInfos(sensorInfos));
+    }
+
+    Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& sensorHandles) override {
+        return mCallback->onDynamicSensorsDisconnected(sensorHandles);
+    }
+
+  private:
+    sp<V2_1::ISensorsCallback> mCallback;
+};
+
+struct SensorsV2_1 : public Sensors {
+    SensorsV2_1();
+
+    // Methods from ::android::hardware::sensors::V2_1::ISensors follow.
+    Return<void> getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) override;
+
+    Return<Result> initialize_2_1(
+            const ::android::hardware::MQDescriptorSync<V2_1::Event>& eventQueueDescriptor,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+            const sp<V2_1::ISensorsCallback>& sensorsCallback) override;
+
+    Return<Result> injectSensorData_2_1(const V2_1::Event& event) override;
+
+  private:
+    sp<ISensorsCallbackWrapper> mCallbackWrapper;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_1_H
\ No newline at end of file
diff --git a/sensors/2.1/default/android.hardware.sensors@2.1-service-mock.rc b/sensors/2.1/default/android.hardware.sensors@2.1-service-mock.rc
new file mode 100644
index 0000000..d4147e7
--- /dev/null
+++ b/sensors/2.1/default/android.hardware.sensors@2.1-service-mock.rc
@@ -0,0 +1,7 @@
+service vendor.sensors-hal-2-1-mock /vendor/bin/hw/android.hardware.sensors@2.1-service.mock
+    interface android.hardware.sensors@2.0::ISensors default
+    interface android.hardware.sensors@2.1::ISensors default
+    class hal
+    user system
+    group system
+    rlimit rtprio 10 10
diff --git a/sensors/2.1/default/android.hardware.sensors@2.1.xml b/sensors/2.1/default/android.hardware.sensors@2.1.xml
new file mode 100644
index 0000000..18bd3ae
--- /dev/null
+++ b/sensors/2.1/default/android.hardware.sensors@2.1.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.sensors</name>
+        <transport>hwbinder</transport>
+        <version>2.1</version>
+        <interface>
+            <name>ISensors</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/sensors/2.1/default/service.cpp b/sensors/2.1/default/service.cpp
new file mode 100644
index 0000000..1f3087c
--- /dev/null
+++ b/sensors/2.1/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.sensors@2.1-service"
+
+#include <android/hardware/sensors/2.1/ISensors.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include "SensorsV2_1.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::sensors::V2_1::ISensors;
+using android::hardware::sensors::V2_1::implementation::SensorsV2_1;
+
+int main(int /* argc */, char** /* argv */) {
+    configureRpcThreadpool(1, true);
+
+    android::sp<ISensors> sensors = new SensorsV2_1();
+    if (sensors->registerAsService() != ::android::OK) {
+        ALOGE("Failed to register Sensors HAL instance");
+        return -1;
+    }
+
+    joinRpcThreadpool();
+    return 1;  // joinRpcThreadpool shouldn't exit
+}
diff --git a/sensors/2.1/types.hal b/sensors/2.1/types.hal
new file mode 100644
index 0000000..503bece
--- /dev/null
+++ b/sensors/2.1/types.hal
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors@2.1;
+
+import @1.0::EventPayload;
+import @1.0::SensorType;
+import @1.0::SensorFlagBits;
+
+@export(name="", value_prefix="SENSOR_TYPE_")
+enum SensorType : @1.0::SensorType {
+    /**
+     * HINGE_ANGLE
+     * reporting-mode: on-change
+     * wake-up sensor: yes
+     *
+     * A sensor of this type measures the angle, in degrees, between two
+     * integral parts of the device. Movement of a hinge measured by this sensor
+     * type is expected to alter the ways in which the user may interact with
+     * the device, for example by unfolding or revealing a display.
+     *
+     * Sensor data is output using @1.0::EventPayload.scalar.
+     *
+     * Implement wake-up proximity sensor before implementing a non wake-up
+     * proximity sensor.
+     */
+    HINGE_ANGLE                     = 36,
+};
+
+struct Event {
+    /** Time measured in nanoseconds, in "elapsedRealtimeNano()'s" timebase. */
+    int64_t timestamp;
+
+    /** sensor identifier */
+    int32_t sensorHandle;
+
+    @2.1::SensorType sensorType;
+
+    /** Union discriminated on sensorType */
+    EventPayload u;
+};
+
+struct SensorInfo {
+    /**
+     * handle that identifies this sensors. This handle is used to reference
+     * this sensor throughout the HAL API.
+     */
+    int32_t sensorHandle;
+
+    /**
+     * Name of this sensor.
+     * All sensors of the same "type" must have a different "name".
+     */
+    string name;
+
+    /** vendor of the hardware part */
+    string vendor;
+
+    /**
+     * version of the hardware part + driver. The value of this field
+     * must increase when the driver is updated in a way that changes the
+     * output of this sensor. This is important for fused sensors when the
+     * fusion algorithm is updated.
+     */
+    int32_t version;
+
+    /** this sensor's type. */
+    @2.1::SensorType type;
+
+    /**
+     * type of this sensor as a string.
+     *
+     * When defining an OEM specific sensor or sensor manufacturer specific
+     * sensor, use your reserve domain name as a prefix.
+     * e.g. com.google.glass.onheaddetector
+     *
+     * For sensors of known type defined in SensorType (value <
+     * SensorType::DEVICE_PRIVATE_BASE), this can be an empty string.
+     */
+    string typeAsString;
+
+    /** maximum range of this sensor's value in SI units */
+    float maxRange;
+
+    /** smallest difference between two values reported by this sensor */
+    float resolution;
+
+    /** rough estimate of this sensor's power consumption in mA */
+    float power;
+
+    /**
+     * this value depends on the reporting mode:
+     *
+     *   continuous: minimum sample period allowed in microseconds
+     *   on-change : 0
+     *   one-shot  :-1
+     *   special   : 0, unless otherwise noted
+     */
+    int32_t minDelay;
+
+    /**
+     * number of events reserved for this sensor in the batch mode FIFO.
+     * If there is a dedicated FIFO for this sensor, then this is the
+     * size of this FIFO. If the FIFO is shared with other sensors,
+     * this is the size reserved for that sensor and it can be zero.
+     */
+    uint32_t fifoReservedEventCount;
+
+    /**
+     * maximum number of events of this sensor that could be batched.
+     * This is especially relevant when the FIFO is shared between
+     * several sensors; this value is then set to the size of that FIFO.
+     */
+    uint32_t fifoMaxEventCount;
+
+    /**
+     * permission required to see this sensor, register to it and receive data.
+     * Set to "" if no permission is required. Some sensor types like the
+     * heart rate monitor have a mandatory require_permission.
+     * For sensors that always require a specific permission, like the heart
+     * rate monitor, the android framework might overwrite this string
+     * automatically.
+     */
+    string requiredPermission;
+
+    /**
+     * This value is defined only for continuous mode and on-change sensors.
+     * It is the delay between two sensor events corresponding to the lowest
+     * frequency that this sensor supports. When lower frequencies are requested
+     * through batch()/setDelay() the events will be generated at this frequency
+     * instead.
+     * It can be used by the framework or applications to estimate when the
+     * batch FIFO may be full.
+     *
+     * NOTE: periodNs is in nanoseconds where as maxDelay/minDelay are in
+     *       microseconds.
+     *
+     *       continuous, on-change: maximum sampling period allowed in
+     *                              microseconds.
+     *
+     *          one-shot, special : 0
+     */
+    int32_t maxDelay;
+
+    /** Bitmask of SensorFlagBits */
+    bitfield<SensorFlagBits> flags;
+};
\ No newline at end of file
diff --git a/sensors/2.1/vts/functional/Android.bp b/sensors/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..c4f5e9d
--- /dev/null
+++ b/sensors/2.1/vts/functional/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalSensorsV2_1TargetTest",
+    cflags: [
+        "-DLOG_TAG=\"sensors_hidl_hal_test\"",
+    ],
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalSensorsV2_1TargetTest.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libfmq",
+        "VtsHalSensorsTargetTestUtils",
+        "VtsHalSensorsV2_1TargetTest-lib",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
diff --git a/sensors/2.1/vts/functional/AndroidTest.xml b/sensors/2.1/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..0d8593e
--- /dev/null
+++ b/sensors/2.1/vts/functional/AndroidTest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalSensorsV2_1TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="stop"/>
+        <option name="teardown-command" value="start"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalSensorsV2_1TargetTest->/data/local/tmp/VtsHalSensorsV2_1TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-timeout" value="900000" />
+        <option name="runtime-hint" value="300000"/>
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalSensorsV2_1TargetTest" />
+    </test>
+</configuration>
diff --git a/sensors/2.1/vts/functional/OWNERS b/sensors/2.1/vts/functional/OWNERS
new file mode 100644
index 0000000..892da15
--- /dev/null
+++ b/sensors/2.1/vts/functional/OWNERS
@@ -0,0 +1,8 @@
+# Sensors team
+arthuri@google.com
+bduddie@google.com
+stange@google.com
+
+# VTS team
+trong@google.com
+yim@google.com
diff --git a/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp b/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp
new file mode 100644
index 0000000..230bb6c
--- /dev/null
+++ b/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VtsHalSensorsV2_XTargetTest.h"
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 android::hardware::sensors::V2_1::ISensors::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/sensors/common/default/2.X/Android.bp b/sensors/common/default/2.X/Android.bp
new file mode 100644
index 0000000..8b0d52f
--- /dev/null
+++ b/sensors/common/default/2.X/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_static {
+    name: "android.hardware.sensors@2.X-shared-impl",
+    vendor: true,
+    export_include_dirs: ["."],
+    srcs: [
+        "Sensor.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+}
diff --git a/sensors/common/default/2.X/OWNERS b/sensors/common/default/2.X/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/sensors/common/default/2.X/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/sensors/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..2b4b3bf
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/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.
+
+cc_defaults {
+    name: "android.hardware.sensors@2.X-multihal-defaults",
+    header_libs: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
+}
+
+cc_library_headers {
+    name: "android.hardware.sensors@2.0-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",
+    ],
+    vendor_available: true,
+    export_header_lib_headers: [
+        "android.hardware.sensors@2.0-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",
+    ],
+    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,
+    export_header_lib_headers: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+}
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp
similarity index 100%
rename from sensors/2.0/multihal/HalProxy.cpp
rename to sensors/common/default/2.X/multihal/HalProxy.cpp
diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/common/default/2.X/multihal/ScopedWakelock.cpp
similarity index 100%
rename from sensors/2.0/multihal/ScopedWakelock.cpp
rename to sensors/common/default/2.X/multihal/ScopedWakelock.cpp
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/common/default/2.X/multihal/include/HalProxy.h
similarity index 100%
rename from sensors/2.0/multihal/include/HalProxy.h
rename to sensors/common/default/2.X/multihal/include/HalProxy.h
diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/common/default/2.X/multihal/include/ScopedWakelock.h
similarity index 100%
rename from sensors/2.0/multihal/include/ScopedWakelock.h
rename to sensors/common/default/2.X/multihal/include/ScopedWakelock.h
diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/common/default/2.X/multihal/include/SubHal.h
similarity index 100%
rename from sensors/2.0/multihal/include/SubHal.h
rename to sensors/common/default/2.X/multihal/include/SubHal.h
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..afb63cc
--- /dev/null
+++ b/sensors/common/default/2.X/multihal/tests/Android.bp
@@ -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.
+
+cc_defaults {
+    name: "android.hardware.sensors@2.X-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.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: [
+        "-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: [
+        "-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,
+    static_libs: [
+        "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",
+        "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/common/default/2.X/multihal/tests/HalProxy_test.cpp
similarity index 100%
rename from sensors/2.0/multihal/tests/HalProxy_test.cpp
rename to sensors/common/default/2.X/multihal/tests/HalProxy_test.cpp
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/2.0/multihal/tests/fake_subhal/Sensor.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
similarity index 100%
rename from sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
rename to sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h
similarity index 100%
rename from sensors/2.0/multihal/tests/fake_subhal/Sensor.h
rename to sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp
similarity index 100%
rename from sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
rename to sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.cpp
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h
similarity index 100%
rename from sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
rename to sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h
diff --git a/sensors/common/utils/Android.bp b/sensors/common/utils/Android.bp
new file mode 100644
index 0000000..aec6c4b
--- /dev/null
+++ b/sensors/common/utils/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+    name: "android.hardware.sensors@2.X-shared-utils",
+    vendor_available: true,
+    defaults: ["hidl_defaults"],
+    export_include_dirs: ["."],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libbinder",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.sensors@1.0-convert",
+    ],
+}
diff --git a/sensors/common/utils/EventMessageQueueWrapper.h b/sensors/common/utils/EventMessageQueueWrapper.h
new file mode 100644
index 0000000..bf3261f
--- /dev/null
+++ b/sensors/common/utils/EventMessageQueueWrapper.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_1_EVENTMESSAGEQUEUEWRAPPER_H
+#define ANDROID_HARDWARE_SENSORS_V2_1_EVENTMESSAGEQUEUEWRAPPER_H
+
+#include "convertV2_1.h"
+
+#include <android/hardware/sensors/2.1/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <log/log.h>
+
+#include <atomic>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+class EventMessageQueueWrapperBase : public RefBase {
+  public:
+    virtual ~EventMessageQueueWrapperBase() {}
+
+    virtual std::atomic<uint32_t>* getEventFlagWord() = 0;
+    virtual size_t availableToRead() = 0;
+    virtual bool read(V2_1::Event* events, size_t numToRead) = 0;
+    virtual bool write(const std::vector<V2_1::Event>& events) = 0;
+};
+
+class EventMessageQueueWrapperV1_0 : public EventMessageQueueWrapperBase {
+  public:
+    using EventMessageQueue = MessageQueue<V1_0::Event, kSynchronizedReadWrite>;
+
+    EventMessageQueueWrapperV1_0(std::unique_ptr<EventMessageQueue>& queue)
+        : mQueue(std::move(queue)) {}
+
+    const ::android::hardware::MQDescriptorSync<V1_0::Event>* getDesc() {
+        return mQueue->getDesc();
+    }
+
+    virtual std::atomic<uint32_t>* getEventFlagWord() override {
+        return mQueue->getEventFlagWord();
+    }
+
+    virtual size_t availableToRead() override { return mQueue->availableToRead(); }
+
+    virtual bool read(V2_1::Event* events, size_t numToRead) override {
+        return mQueue->read(reinterpret_cast<V1_0::Event*>(events), numToRead);
+    }
+
+    virtual bool write(const std::vector<V2_1::Event>& events) override {
+        const std::vector<V1_0::Event>& oldEvents = convertToOldEvents(events);
+        return mQueue->write(oldEvents.data(), oldEvents.size());
+    }
+
+  private:
+    std::unique_ptr<EventMessageQueue> mQueue;
+};
+
+class EventMessageQueueWrapperV2_1 : public EventMessageQueueWrapperBase {
+  public:
+    using EventMessageQueue = MessageQueue<V2_1::Event, kSynchronizedReadWrite>;
+
+    EventMessageQueueWrapperV2_1(std::unique_ptr<EventMessageQueue>& queue)
+        : mQueue(std::move(queue)) {}
+
+    const ::android::hardware::MQDescriptorSync<V2_1::Event>* getDesc() {
+        return mQueue->getDesc();
+    }
+
+    std::atomic<uint32_t>* getEventFlagWord() override { return mQueue->getEventFlagWord(); }
+
+    virtual size_t availableToRead() override { return mQueue->availableToRead(); }
+
+    virtual bool read(V2_1::Event* events, size_t numToRead) override {
+        return mQueue->read(events, numToRead);
+    }
+
+    bool write(const std::vector<V2_1::Event>& events) override {
+        return mQueue->write(events.data(), events.size());
+    }
+
+  private:
+    std::unique_ptr<EventMessageQueue> mQueue;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_1_EVENTMESSAGEQUEUEWRAPPER_H
\ No newline at end of file
diff --git a/sensors/common/utils/ISensorsWrapper.h b/sensors/common/utils/ISensorsWrapper.h
new file mode 100644
index 0000000..e9c22b1
--- /dev/null
+++ b/sensors/common/utils/ISensorsWrapper.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H
+#define ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H
+
+#include "EventMessageQueueWrapper.h"
+#include "ISensorsWrapper.h"
+
+#include "android/hardware/sensors/1.0/ISensors.h"
+#include "android/hardware/sensors/1.0/types.h"
+#include "android/hardware/sensors/2.0/ISensors.h"
+#include "android/hardware/sensors/2.0/ISensorsCallback.h"
+#include "android/hardware/sensors/2.1/ISensors.h"
+#include "android/hardware/sensors/2.1/ISensorsCallback.h"
+#include "android/hardware/sensors/2.1/types.h"
+
+#include <utils/LightRefBase.h>
+
+#include <cassert>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::sensors::V1_0::ISensors;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::RateLevel;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V2_1::Event;
+using ::android::hardware::sensors::V2_1::ISensorsCallback;
+
+// TODO: Look into providing this as a param if it needs to be a different value
+// than the framework.
+static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 256;
+
+/*
+ * The ISensorsWrapper interface includes all function from supported Sensors HAL versions. This
+ * allows for the SensorDevice to use the ISensorsWrapper interface to interact with the Sensors
+ * HAL regardless of the current version of the Sensors HAL that is loaded. Each concrete
+ * instantiation of ISensorsWrapper must correspond to a specific Sensors HAL version. This design
+ * is beneficial because only the functions that change between Sensors HAL versions must be newly
+ * implemented, any previously implemented function that does not change may remain the same.
+ *
+ * Functions that exist across all versions of the Sensors HAL should be implemented as pure
+ * virtual functions which forces the concrete instantiations to implement the functions.
+ *
+ * Functions that do not exist across all versions of the Sensors HAL should include a default
+ * implementation that generates an error if called. The default implementation should never
+ * be called and must be overridden by Sensors HAL versions that support the function.
+ */
+class ISensorsWrapperBase : public VirtualLightRefBase {
+  public:
+    virtual bool supportsPolling() const = 0;
+
+    virtual bool supportsMessageQueues() const = 0;
+
+    virtual void linkToDeath(android::sp<android::hardware::hidl_death_recipient> deathRecipient,
+                             uint64_t cookie) = 0;
+
+    virtual Return<void> getSensorsList(
+            ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) = 0;
+
+    virtual Return<Result> setOperationMode(OperationMode mode) = 0;
+
+    virtual Return<Result> activate(int32_t sensorHandle, bool enabled) = 0;
+
+    virtual Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                                 int64_t maxReportLatencyNs) = 0;
+
+    virtual Return<Result> flush(int32_t sensorHandle) = 0;
+
+    virtual Return<Result> injectSensorData(const Event& event) = 0;
+
+    virtual Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                               ISensors::registerDirectChannel_cb _hidl_cb) = 0;
+
+    virtual Return<Result> unregisterDirectChannel(int32_t channelHandle) = 0;
+
+    virtual Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle,
+                                            RateLevel rate,
+                                            ISensors::configDirectReport_cb _hidl_cb) = 0;
+
+    virtual Return<void> poll(int32_t /* maxCount */, ISensors::poll_cb /* _hidl_cb */) {
+        // Enforce this method is never invoked as it should be overridden if it's meant to be used.
+        assert(false);
+        return Return<void>();
+    }
+
+    virtual EventMessageQueueWrapperBase* getEventQueue() { return nullptr; }
+
+    virtual Return<Result> initialize(const MQDescriptorSync<uint32_t>& /* wakeLockDesc */,
+                                      const ::android::sp<ISensorsCallback>& /* callback */) {
+        // Enforce this method is never invoked as it should be overridden if it's meant to be used.
+        assert(false);
+        return Result::INVALID_OPERATION;
+    }
+};
+
+template <typename T>
+class SensorsWrapperBase : public ISensorsWrapperBase {
+  public:
+    SensorsWrapperBase(sp<T> sensors) : mSensors(sensors){};
+
+    void linkToDeath(android::sp<android::hardware::hidl_death_recipient> deathRecipient,
+                     uint64_t cookie) override {
+        mSensors->linkToDeath(deathRecipient, cookie);
+    }
+
+    virtual Return<void> getSensorsList(
+            ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override {
+        return mSensors->getSensorsList(
+                [&](const auto& list) { _hidl_cb(convertToNewSensorInfos(list)); });
+    }
+
+    Return<Result> setOperationMode(OperationMode mode) override {
+        return mSensors->setOperationMode(mode);
+    }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override {
+        return mSensors->activate(sensorHandle, enabled);
+    }
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override {
+        return mSensors->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+    }
+
+    Return<Result> flush(int32_t sensorHandle) override { return mSensors->flush(sensorHandle); }
+
+    virtual Return<Result> injectSensorData(const Event& event) override {
+        return mSensors->injectSensorData(convertToOldEvent(event));
+    }
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       ISensors::registerDirectChannel_cb _hidl_cb) override {
+        return mSensors->registerDirectChannel(mem, _hidl_cb);
+    }
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+        return mSensors->unregisterDirectChannel(channelHandle);
+    }
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    ISensors::configDirectReport_cb _hidl_cb) override {
+        return mSensors->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+    }
+
+  protected:
+    sp<T> mSensors;
+};
+
+class ISensorsWrapperV1_0 : public SensorsWrapperBase<hardware::sensors::V1_0::ISensors> {
+  public:
+    ISensorsWrapperV1_0(sp<hardware::sensors::V1_0::ISensors> sensors)
+        : SensorsWrapperBase(sensors){};
+
+    bool supportsPolling() const override { return true; }
+
+    bool supportsMessageQueues() const override { return false; }
+
+    Return<void> poll(int32_t maxCount,
+                      hardware::sensors::V1_0::ISensors::poll_cb _hidl_cb) override {
+        return mSensors->poll(maxCount, _hidl_cb);
+    }
+};
+
+class ISensorsWrapperV2_0 : public SensorsWrapperBase<hardware::sensors::V2_0::ISensors> {
+  public:
+    typedef MessageQueue<::android::hardware::sensors::V1_0::Event,
+                         ::android::hardware::kSynchronizedReadWrite>
+            EventMessageQueue;
+
+    ISensorsWrapperV2_0(sp<hardware::sensors::V2_0::ISensors> sensors)
+        : SensorsWrapperBase(sensors) {
+        auto eventQueue = std::make_unique<EventMessageQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+                                                              true /* configureEventFlagWord */);
+        mEventQueue = std::make_unique<EventMessageQueueWrapperV1_0>(eventQueue);
+    };
+
+    bool supportsPolling() const override { return false; }
+
+    bool supportsMessageQueues() const override { return true; }
+
+    EventMessageQueueWrapperBase* getEventQueue() override { return mEventQueue.get(); }
+
+    Return<Result> initialize(const MQDescriptorSync<uint32_t>& wakeLockDesc,
+                              const ::android::sp<ISensorsCallback>& callback) override {
+        return mSensors->initialize(*mEventQueue->getDesc(), wakeLockDesc, callback);
+    }
+
+  private:
+    std::unique_ptr<EventMessageQueueWrapperV1_0> mEventQueue;
+};
+
+class ISensorsWrapperV2_1 : public SensorsWrapperBase<hardware::sensors::V2_1::ISensors> {
+  public:
+    typedef MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite> EventMessageQueueV2_1;
+
+    ISensorsWrapperV2_1(sp<hardware::sensors::V2_1::ISensors> sensors)
+        : SensorsWrapperBase(sensors) {
+        auto eventQueue = std::make_unique<EventMessageQueueV2_1>(
+                MAX_RECEIVE_BUFFER_EVENT_COUNT, true /* configureEventFlagWord */);
+        mEventQueue = std::make_unique<EventMessageQueueWrapperV2_1>(eventQueue);
+    };
+
+    bool supportsPolling() const override { return false; }
+
+    bool supportsMessageQueues() const override { return true; }
+
+    EventMessageQueueWrapperBase* getEventQueue() override { return mEventQueue.get(); }
+
+    Return<void> getSensorsList(
+            ::android::hardware::sensors::V2_1::ISensors::getSensorsList_2_1_cb _hidl_cb) override {
+        return mSensors->getSensorsList_2_1(_hidl_cb);
+    }
+
+    Return<Result> injectSensorData(const Event& event) override {
+        return mSensors->injectSensorData_2_1(event);
+    }
+
+    Return<Result> initialize(const MQDescriptorSync<uint32_t>& wakeLockDesc,
+                              const ::android::sp<ISensorsCallback>& callback) override {
+        return mSensors->initialize_2_1(*mEventQueue->getDesc(), wakeLockDesc, callback);
+    }
+
+  private:
+    std::unique_ptr<EventMessageQueueWrapperV2_1> mEventQueue;
+};
+
+inline sp<ISensorsWrapperV2_0> wrapISensors(sp<V2_0::ISensors> sensors) {
+    return new ISensorsWrapperV2_0(sensors);
+}
+
+inline sp<ISensorsWrapperV2_1> wrapISensors(sp<V2_1::ISensors> sensors) {
+    return new ISensorsWrapperV2_1(sensors);
+}
+
+class NoOpSensorsCallback : public ISensorsCallback {
+  public:
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<V1_0::SensorInfo>& /* sensorInfos */) override {
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& /* sensorHandles */) override {
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsConnected_2_1(
+            const hidl_vec<SensorInfo>& /* sensorInfos */) override {
+        return Return<void>();
+    }
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_1_ISENSORSWRAPPER_H
\ No newline at end of file
diff --git a/sensors/common/utils/OWNERS b/sensors/common/utils/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/sensors/common/utils/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/sensors/common/utils/convertV2_1.h b/sensors/common/utils/convertV2_1.h
new file mode 100644
index 0000000..9231011
--- /dev/null
+++ b/sensors/common/utils/convertV2_1.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SENSORS_V2_1_CONVERT_H
+#define ANDROID_HARDWARE_SENSORS_V2_1_CONVERT_H
+
+#include <android/hardware/sensors/2.1/types.h>
+#include <hardware/sensors.h>
+#include <sensors/convert.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_1 {
+namespace implementation {
+
+static_assert(sizeof(V1_0::Event) == sizeof(V2_1::Event),
+              "New and old Event types must have the same size");
+static_assert(sizeof(V1_0::SensorInfo) == sizeof(V2_1::SensorInfo),
+              "New and old SensorInfo types must have the same size");
+
+// The following conversion methods are safe as the only difference between
+// V1_0 and V2_1 for these types is an added enum value to SensorType which doesn't
+// change the memory layout of the types.
+inline const V1_0::Event& convertToOldEvent(const V2_1::Event& event) {
+    return reinterpret_cast<const V1_0::Event&>(event);
+}
+
+inline const std::vector<V1_0::Event>& convertToOldEvents(const std::vector<V2_1::Event>& events) {
+    return reinterpret_cast<const std::vector<V1_0::Event>&>(events);
+}
+
+inline V1_0::Event* convertToOldEvent(V2_1::Event* event) {
+    return reinterpret_cast<V1_0::Event*>(event);
+}
+
+inline const V2_1::SensorInfo& convertToNewSensorInfo(const V1_0::SensorInfo& info) {
+    return reinterpret_cast<const V2_1::SensorInfo&>(info);
+}
+
+inline const V1_0::SensorInfo& convertToOldSensorInfo(const V2_1::SensorInfo& info) {
+    return reinterpret_cast<const V1_0::SensorInfo&>(info);
+}
+
+inline const V2_1::Event& convertToNewEvent(const V1_0::Event& event) {
+    return reinterpret_cast<const V2_1::Event&>(event);
+}
+
+inline const std::vector<V2_1::Event>& convertToNewEvents(const std::vector<V1_0::Event>& events) {
+    return reinterpret_cast<const std::vector<V2_1::Event>&>(events);
+}
+
+inline const hidl_vec<V2_1::Event>& convertToNewEvents(const hidl_vec<V1_0::Event>& events) {
+    return reinterpret_cast<const hidl_vec<V2_1::Event>&>(events);
+}
+
+inline const hidl_vec<V2_1::SensorInfo>& convertToNewSensorInfos(
+        const hidl_vec<V1_0::SensorInfo>& infos) {
+    return reinterpret_cast<const hidl_vec<V2_1::SensorInfo>&>(infos);
+}
+
+inline const hidl_vec<V1_0::SensorInfo>& convertToOldSensorInfos(
+        const hidl_vec<V2_1::SensorInfo>& infos) {
+    return reinterpret_cast<const hidl_vec<V1_0::SensorInfo>&>(infos);
+}
+
+inline void convertFromSensorEvent(const sensors_event_t& src, V2_1::Event* dst) {
+    switch ((SensorType)src.type) {
+        case SensorType::HINGE_ANGLE:
+            // Only fill in values for hinge angle as other sensors
+            // will have it filled in by legacy code.
+            *dst = {
+                    .timestamp = src.timestamp,
+                    .sensorHandle = src.sensor,
+                    .sensorType = (SensorType)src.type,
+            };
+            dst->u.scalar = src.data[0];
+            break;
+        default:
+            V1_0::implementation::convertFromSensorEvent(src, convertToOldEvent(dst));
+            break;
+    }
+}
+
+inline void convertToSensorEvent(const V2_1::Event& src, sensors_event_t* dst) {
+    switch (src.sensorType) {
+        case SensorType::HINGE_ANGLE:
+            // Only fill in values for hinge angle as other sensors
+            // will have it filled in by legacy code.
+            *dst = {.version = sizeof(sensors_event_t),
+                    .sensor = src.sensorHandle,
+                    .type = (int32_t)src.sensorType,
+                    .reserved0 = 0,
+                    .timestamp = src.timestamp};
+            dst->data[0] = src.u.scalar;
+            break;
+        default:
+            V1_0::implementation::convertToSensorEvent(convertToOldEvent(src), dst);
+            break;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SENSORS_V2_1_CONVERT_H
diff --git a/sensors/common/vts/2_X/Android.bp b/sensors/common/vts/2_X/Android.bp
new file mode 100644
index 0000000..8cdb5d1
--- /dev/null
+++ b/sensors/common/vts/2_X/Android.bp
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+    name: "VtsHalSensorsV2_XTargetTest-defaults",
+    cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "SensorsHidlEnvironmentV2_X.cpp",
+    ],
+    export_include_dirs: ["."],
+    header_libs: [
+        "android.hardware.sensors@2.X-shared-utils",
+    ],
+    shared_libs: [
+        "libbinder",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@1.0-convert",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
+        "libfmq",
+        "VtsHalSensorsTargetTestUtils",
+    ],
+}
+
+cc_test_library {
+    name: "VtsHalSensorsV2_0TargetTest-lib",
+    defaults: ["VtsHalSensorsV2_XTargetTest-defaults"],
+}
+
+cc_test_library {
+    name: "VtsHalSensorsV2_1TargetTest-lib",
+    cflags: ["-DSENSORS_HAL_2_1"],
+    defaults: ["VtsHalSensorsV2_XTargetTest-defaults"],
+}
diff --git a/sensors/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..745ab2d
--- /dev/null
+++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
@@ -0,0 +1,916 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "SensorsHidlEnvironmentV2_X.h"
+#include "convertV2_1.h"
+#include "sensors-vts-utils/SensorsHidlTestBase.h"
+#include "sensors-vts-utils/SensorsTestSharedMemory.h"
+
+#include <android/hardware/sensors/2.1/ISensors.h>
+#include <android/hardware/sensors/2.1/types.h>
+
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include <cinttypes>
+#include <condition_variable>
+#include <cstring>
+#include <map>
+#include <vector>
+
+/**
+ * This file contains the core tests and test logic for both sensors HAL 2.0
+ * and 2.1. To make it easier to share the code between both VTS test suites,
+ * this is defined as a header so they can both include and use all pieces of
+ * code.
+ */
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::MetaDataEventType;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
+using ::android::hardware::sensors::V1_0::SensorStatus;
+using ::android::hardware::sensors::V1_0::SharedMemType;
+using ::android::hardware::sensors::V1_0::Vec3;
+using ::android::hardware::sensors::V2_1::implementation::convertToOldSensorInfos;
+using std::chrono::duration_cast;
+using std::chrono::microseconds;
+using std::chrono::milliseconds;
+using std::chrono::nanoseconds;
+
+using EventV1_0 = ::android::hardware::sensors::V1_0::Event;
+using ISensorsType = ::android::hardware::sensors::V2_1::ISensors;
+using SensorTypeVersion = ::android::hardware::sensors::V2_1::SensorType;
+using EventType = ::android::hardware::sensors::V2_1::Event;
+using SensorInfoType = ::android::hardware::sensors::V2_1::SensorInfo;
+using SensorsHidlTestBaseV2_X = SensorsHidlTestBase<SensorTypeVersion, EventType, SensorInfoType>;
+
+constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+
+class EventCallback : public IEventCallback<EventType> {
+  public:
+    void reset() {
+        mFlushMap.clear();
+        mEventMap.clear();
+    }
+
+    void onEvent(const EventType& event) override {
+        if (event.sensorType == SensorTypeVersion::META_DATA &&
+            event.u.meta.what == MetaDataEventType::META_DATA_FLUSH_COMPLETE) {
+            std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+            mFlushMap[event.sensorHandle]++;
+            mFlushCV.notify_all();
+        } else if (event.sensorType != SensorTypeVersion::ADDITIONAL_INFO) {
+            std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+            mEventMap[event.sensorHandle].push_back(event);
+            mEventCV.notify_all();
+        }
+    }
+
+    int32_t getFlushCount(int32_t sensorHandle) {
+        std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+        return mFlushMap[sensorHandle];
+    }
+
+    void waitForFlushEvents(const std::vector<SensorInfoType>& sensorsToWaitFor,
+                            int32_t numCallsToFlush, milliseconds timeout) {
+        std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+        mFlushCV.wait_for(lock, timeout,
+                          [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); });
+    }
+
+    const std::vector<EventType> getEvents(int32_t sensorHandle) {
+        std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+        return mEventMap[sensorHandle];
+    }
+
+    void waitForEvents(const std::vector<SensorInfoType>& sensorsToWaitFor, milliseconds timeout) {
+        std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+        mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); });
+    }
+
+  protected:
+    bool flushesReceived(const std::vector<SensorInfoType>& sensorsToWaitFor,
+                         int32_t numCallsToFlush) {
+        for (const SensorInfoType& sensor : sensorsToWaitFor) {
+            if (getFlushCount(sensor.sensorHandle) < numCallsToFlush) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    bool eventsReceived(const std::vector<SensorInfoType>& sensorsToWaitFor) {
+        for (const SensorInfoType& sensor : sensorsToWaitFor) {
+            if (getEvents(sensor.sensorHandle).size() == 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    std::map<int32_t, int32_t> mFlushMap;
+    std::recursive_mutex mFlushMutex;
+    std::condition_variable_any mFlushCV;
+
+    std::map<int32_t, std::vector<EventType>> mEventMap;
+    std::recursive_mutex mEventMutex;
+    std::condition_variable_any mEventCV;
+};
+
+/**
+ * Define the template specific versions of the static helper methods in
+ * SensorsHidlTestBase used to test that hinge angle is exposed properly.
+ */
+template <>
+SensorFlagBits expectedReportModeForType(::android::hardware::sensors::V2_1::SensorType type) {
+    switch (type) {
+        case ::android::hardware::sensors::V2_1::SensorType::HINGE_ANGLE:
+            return SensorFlagBits::ON_CHANGE_MODE;
+        default:
+            return expectedReportModeForType(
+                    static_cast<::android::hardware::sensors::V1_0::SensorType>(type));
+    }
+}
+
+template <>
+void assertTypeMatchStringType(::android::hardware::sensors::V2_1::SensorType type,
+                               const hidl_string& stringType) {
+    switch (type) {
+        case (::android::hardware::sensors::V2_1::SensorType::HINGE_ANGLE):
+            ASSERT_STREQ(SENSOR_STRING_TYPE_HINGE_ANGLE, stringType.c_str());
+            break;
+        default:
+            assertTypeMatchStringType(
+                    static_cast<::android::hardware::sensors::V1_0::SensorType>(type), stringType);
+            break;
+    }
+}
+
+// The main test class for SENSORS HIDL HAL.
+class SensorsHidlTest : public SensorsHidlTestBaseV2_X {
+  public:
+    virtual void SetUp() override {
+        mEnvironment = new SensorsHidlEnvironmentV2_X(GetParam());
+        mEnvironment->HidlSetUp();
+        // Ensure that we have a valid environment before performing tests
+        ASSERT_NE(getSensors(), nullptr);
+    }
+
+    virtual void TearDown() override { mEnvironment->HidlTearDown(); }
+
+  protected:
+    SensorInfoType defaultSensorByType(SensorTypeVersion type) override;
+    std::vector<SensorInfoType> getSensorsList();
+    // implementation wrapper
+
+    Return<void> getSensorsList(ISensorsType::getSensorsList_cb _hidl_cb) override {
+        return getSensors()->getSensorsList(
+                [&](const auto& list) { _hidl_cb(convertToOldSensorInfos(list)); });
+    }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override {
+        return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+    }
+
+    Return<Result> flush(int32_t sensorHandle) override {
+        return getSensors()->flush(sensorHandle);
+    }
+
+    Return<Result> injectSensorData(const EventType& event) override {
+        return getSensors()->injectSensorData(event);
+    }
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       ISensorsType::registerDirectChannel_cb _hidl_cb) override;
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+        return getSensors()->unregisterDirectChannel(channelHandle);
+    }
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    ISensorsType::configDirectReport_cb _hidl_cb) override {
+        return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+    }
+
+    inline sp<ISensorsWrapperBase>& getSensors() { return mEnvironment->mSensors; }
+
+    SensorsHidlEnvironmentBase<EventType>* getEnvironment() override { return mEnvironment; }
+
+    // Test helpers
+    void runSingleFlushTest(const std::vector<SensorInfoType>& sensors, bool activateSensor,
+                            int32_t expectedFlushCount, Result expectedResponse);
+    void runFlushTest(const std::vector<SensorInfoType>& sensors, bool activateSensor,
+                      int32_t flushCalls, int32_t expectedFlushCount, Result expectedResponse);
+
+    // Helper functions
+    void activateAllSensors(bool enable);
+    std::vector<SensorInfoType> getNonOneShotSensors();
+    std::vector<SensorInfoType> getNonOneShotAndNonSpecialSensors();
+    std::vector<SensorInfoType> getOneShotSensors();
+    std::vector<SensorInfoType> getInjectEventSensors();
+    int32_t getInvalidSensorHandle();
+    bool getDirectChannelSensor(SensorInfoType* sensor, SharedMemType* memType, RateLevel* rate);
+    void verifyDirectChannel(SharedMemType memType);
+    void verifyRegisterDirectChannel(
+            std::shared_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem,
+            int32_t* directChannelHandle, bool supportsSharedMemType,
+            bool supportsAnyDirectChannel);
+    void verifyConfigure(const SensorInfoType& sensor, SharedMemType memType,
+                         int32_t directChannelHandle, bool directChannelSupported);
+    void verifyUnregisterDirectChannel(int32_t directChannelHandle, bool directChannelSupported);
+    void checkRateLevel(const SensorInfoType& sensor, int32_t directChannelHandle,
+                        RateLevel rateLevel);
+    void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
+                                   bool* supportsAnyDirectChannel);
+
+  private:
+    // Test environment for sensors HAL.
+    SensorsHidlEnvironmentV2_X* mEnvironment;
+};
+
+Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
+    // If activating a sensor, add the handle in a set so that when test fails it can be turned off.
+    // The handle is not removed when it is deactivating on purpose so that it is not necessary to
+    // check the return value of deactivation. Deactivating a sensor more than once does not have
+    // negative effect.
+    if (enabled) {
+        mSensorHandles.insert(sensorHandle);
+    }
+    return getSensors()->activate(sensorHandle, enabled);
+}
+
+Return<void> SensorsHidlTest::registerDirectChannel(const SharedMemInfo& mem,
+                                                    ISensors::registerDirectChannel_cb cb) {
+    // If registeration of a channel succeeds, add the handle of channel to a set so that it can be
+    // unregistered when test fails. Unregister a channel does not remove the handle on purpose.
+    // Unregistering a channel more than once should not have negative effect.
+    getSensors()->registerDirectChannel(mem, [&](auto result, auto channelHandle) {
+        if (result == Result::OK) {
+            mDirectChannelHandles.insert(channelHandle);
+        }
+        cb(result, channelHandle);
+    });
+    return Void();
+}
+
+SensorInfoType SensorsHidlTest::defaultSensorByType(SensorTypeVersion type) {
+    SensorInfoType ret;
+
+    ret.type = (SensorTypeVersion)-1;
+    getSensors()->getSensorsList([&](const auto& list) {
+        const size_t count = list.size();
+        for (size_t i = 0; i < count; ++i) {
+            if (list[i].type == type) {
+                ret = list[i];
+                return;
+            }
+        }
+    });
+
+    return ret;
+}
+
+std::vector<SensorInfoType> SensorsHidlTest::getSensorsList() {
+    std::vector<SensorInfoType> ret;
+
+    getSensors()->getSensorsList([&](const auto& list) {
+        const size_t count = list.size();
+        ret.reserve(list.size());
+        for (size_t i = 0; i < count; ++i) {
+            ret.push_back(list[i]);
+        }
+    });
+
+    return ret;
+}
+
+std::vector<SensorInfoType> SensorsHidlTest::getNonOneShotSensors() {
+    std::vector<SensorInfoType> sensors;
+    for (const SensorInfoType& info : getSensorsList()) {
+        if (extractReportMode(info.flags) != SensorFlagBits::ONE_SHOT_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+std::vector<SensorInfoType> SensorsHidlTest::getNonOneShotAndNonSpecialSensors() {
+    std::vector<SensorInfoType> sensors;
+    for (const SensorInfoType& info : getSensorsList()) {
+        SensorFlagBits reportMode = extractReportMode(info.flags);
+        if (reportMode != SensorFlagBits::ONE_SHOT_MODE &&
+            reportMode != SensorFlagBits::SPECIAL_REPORTING_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+std::vector<SensorInfoType> SensorsHidlTest::getOneShotSensors() {
+    std::vector<SensorInfoType> sensors;
+    for (const SensorInfoType& info : getSensorsList()) {
+        if (extractReportMode(info.flags) == SensorFlagBits::ONE_SHOT_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+std::vector<SensorInfoType> SensorsHidlTest::getInjectEventSensors() {
+    std::vector<SensorInfoType> sensors;
+    for (const SensorInfoType& info : getSensorsList()) {
+        if (info.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION)) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
+int32_t SensorsHidlTest::getInvalidSensorHandle() {
+    // Find a sensor handle that does not exist in the sensor list
+    int32_t maxHandle = 0;
+    for (const SensorInfoType& sensor : getSensorsList()) {
+        maxHandle = std::max(maxHandle, sensor.sensorHandle);
+    }
+    return maxHandle + 1;
+}
+
+// Test if sensor list returned is valid
+TEST_P(SensorsHidlTest, SensorListValid) {
+    getSensors()->getSensorsList([&](const auto& list) {
+        const size_t count = list.size();
+        for (size_t i = 0; i < count; ++i) {
+            const auto& s = list[i];
+            SCOPED_TRACE(::testing::Message()
+                         << i << "/" << count << ": "
+                         << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                         << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
+                         << " name=" << s.name);
+
+            // Test non-empty type string
+            EXPECT_FALSE(s.typeAsString.empty());
+
+            // Test defined type matches defined string type
+            EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
+
+            // Test if all sensor has name and vendor
+            EXPECT_FALSE(s.name.empty());
+            EXPECT_FALSE(s.vendor.empty());
+
+            // Test power > 0, maxRange > 0
+            EXPECT_LE(0, s.power);
+            EXPECT_LT(0, s.maxRange);
+
+            // Info type, should have no sensor
+            EXPECT_FALSE(s.type == SensorTypeVersion::ADDITIONAL_INFO ||
+                         s.type == SensorTypeVersion::META_DATA);
+
+            // Test fifoMax >= fifoReserved
+            EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
+                    << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
+
+            // Test Reporting mode valid
+            EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
+
+            // Test min max are in the right order
+            EXPECT_LE(s.minDelay, s.maxDelay);
+            // Test min/max delay matches reporting mode
+            EXPECT_NO_FATAL_FAILURE(
+                    assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
+        }
+    });
+}
+
+// Test that SetOperationMode returns the expected value
+TEST_P(SensorsHidlTest, SetOperationMode) {
+    std::vector<SensorInfoType> sensors = getInjectEventSensors();
+    if (getInjectEventSensors().size() > 0) {
+        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+        ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+    } else {
+        ASSERT_EQ(Result::BAD_VALUE, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+    }
+}
+
+// Test that an injected event is written back to the Event FMQ
+TEST_P(SensorsHidlTest, InjectSensorEventData) {
+    std::vector<SensorInfoType> sensors = getInjectEventSensors();
+    if (sensors.size() == 0) {
+        return;
+    }
+
+    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+
+    EventCallback callback;
+    getEnvironment()->registerCallback(&callback);
+
+    // AdditionalInfo event should not be sent to Event FMQ
+    EventType additionalInfoEvent;
+    additionalInfoEvent.sensorType = SensorTypeVersion::ADDITIONAL_INFO;
+    additionalInfoEvent.timestamp = android::elapsedRealtimeNano();
+
+    EventType injectedEvent;
+    injectedEvent.timestamp = android::elapsedRealtimeNano();
+    Vec3 data = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
+    injectedEvent.u.vec3 = data;
+
+    for (const auto& s : sensors) {
+        additionalInfoEvent.sensorHandle = s.sensorHandle;
+        EXPECT_EQ(Result::OK, getSensors()->injectSensorData(additionalInfoEvent));
+
+        injectedEvent.sensorType = s.type;
+        injectedEvent.sensorHandle = s.sensorHandle;
+        EXPECT_EQ(Result::OK, getSensors()->injectSensorData(injectedEvent));
+    }
+
+    // Wait for events to be written back to the Event FMQ
+    callback.waitForEvents(sensors, milliseconds(1000) /* timeout */);
+
+    for (const auto& s : sensors) {
+        auto events = callback.getEvents(s.sensorHandle);
+        auto lastEvent = events.back();
+
+        // Verify that only a single event has been received
+        ASSERT_EQ(events.size(), 1);
+
+        // Verify that the event received matches the event injected and is not the additional
+        // info event
+        ASSERT_EQ(lastEvent.sensorType, s.type);
+        ASSERT_EQ(lastEvent.sensorType, s.type);
+        ASSERT_EQ(lastEvent.timestamp, injectedEvent.timestamp);
+        ASSERT_EQ(lastEvent.u.vec3.x, injectedEvent.u.vec3.x);
+        ASSERT_EQ(lastEvent.u.vec3.y, injectedEvent.u.vec3.y);
+        ASSERT_EQ(lastEvent.u.vec3.z, injectedEvent.u.vec3.z);
+        ASSERT_EQ(lastEvent.u.vec3.status, injectedEvent.u.vec3.status);
+    }
+
+    getEnvironment()->unregisterCallback();
+    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+}
+
+void SensorsHidlTest::activateAllSensors(bool enable) {
+    for (const SensorInfoType& sensorInfo : getSensorsList()) {
+        if (isValidType(sensorInfo.type)) {
+            batch(sensorInfo.sensorHandle, sensorInfo.minDelay, 0 /* maxReportLatencyNs */);
+            activate(sensorInfo.sensorHandle, enable);
+        }
+    }
+}
+
+// Test that if initialize is called twice, then the HAL writes events to the FMQs from the second
+// call to the function.
+TEST_P(SensorsHidlTest, CallInitializeTwice) {
+    // Create a helper class so that a second environment is able to be instantiated
+    class SensorsHidlEnvironmentTest : public SensorsHidlEnvironmentV2_X {
+      public:
+        SensorsHidlEnvironmentTest(const std::string& service_name)
+            : SensorsHidlEnvironmentV2_X(service_name) {}
+    };
+
+    if (getSensorsList().size() == 0) {
+        // No sensors
+        return;
+    }
+
+    constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000;  // 1s
+    constexpr int32_t kNumEvents = 1;
+
+    // Create a new environment that calls initialize()
+    std::unique_ptr<SensorsHidlEnvironmentTest> newEnv =
+            std::make_unique<SensorsHidlEnvironmentTest>(GetParam());
+    newEnv->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if setting up the new environment failed
+    }
+
+    activateAllSensors(true);
+    // Verify that the old environment does not receive any events
+    EXPECT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0);
+    // Verify that the new event queue receives sensor events
+    EXPECT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, newEnv.get(), newEnv.get()).size(),
+              kNumEvents);
+    activateAllSensors(false);
+
+    // Cleanup the test environment
+    newEnv->HidlTearDown();
+
+    // Restore the test environment for future tests
+    getEnvironment()->HidlTearDown();
+    getEnvironment()->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if resetting the environment failed
+    }
+
+    // Ensure that the original environment is receiving events
+    activateAllSensors(true);
+    EXPECT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+    activateAllSensors(false);
+}
+
+TEST_P(SensorsHidlTest, CleanupConnectionsOnInitialize) {
+    activateAllSensors(true);
+
+    // Verify that events are received
+    constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000;  // 1s
+    constexpr int32_t kNumEvents = 1;
+    ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents);
+
+    // Clear the active sensor handles so they are not disabled during TearDown
+    auto handles = mSensorHandles;
+    mSensorHandles.clear();
+    getEnvironment()->HidlTearDown();
+    getEnvironment()->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if resetting the environment failed
+    }
+
+    // Verify no events are received until sensors are re-activated
+    ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0);
+    activateAllSensors(true);
+    ASSERT_GE(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), kNumEvents);
+
+    // Disable sensors
+    activateAllSensors(false);
+
+    // Restore active sensors prior to clearing the environment
+    mSensorHandles = handles;
+}
+
+void SensorsHidlTest::runSingleFlushTest(const std::vector<SensorInfoType>& sensors,
+                                         bool activateSensor, int32_t expectedFlushCount,
+                                         Result expectedResponse) {
+    runFlushTest(sensors, activateSensor, 1 /* flushCalls */, expectedFlushCount, expectedResponse);
+}
+
+void SensorsHidlTest::runFlushTest(const std::vector<SensorInfoType>& sensors, bool activateSensor,
+                                   int32_t flushCalls, int32_t expectedFlushCount,
+                                   Result expectedResponse) {
+    EventCallback callback;
+    getEnvironment()->registerCallback(&callback);
+
+    for (const SensorInfoType& sensor : sensors) {
+        // Configure and activate the sensor
+        batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */);
+        activate(sensor.sensorHandle, activateSensor);
+
+        // Flush the sensor
+        for (int32_t i = 0; i < flushCalls; i++) {
+            Result flushResult = flush(sensor.sensorHandle);
+            ASSERT_EQ(flushResult, expectedResponse);
+        }
+    }
+
+    // Wait up to one second for the flush events
+    callback.waitForFlushEvents(sensors, flushCalls, milliseconds(1000) /* timeout */);
+
+    // Deactivate all sensors after waiting for flush events so pending flush events are not
+    // abandoned by the HAL.
+    for (const SensorInfoType& sensor : sensors) {
+        activate(sensor.sensorHandle, false);
+    }
+    getEnvironment()->unregisterCallback();
+
+    // Check that the correct number of flushes are present for each sensor
+    for (const SensorInfoType& sensor : sensors) {
+        ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount);
+    }
+}
+
+TEST_P(SensorsHidlTest, FlushSensor) {
+    // Find a sensor that is not a one-shot sensor
+    std::vector<SensorInfoType> sensors = getNonOneShotSensors();
+    if (sensors.size() == 0) {
+        return;
+    }
+
+    constexpr int32_t kFlushes = 5;
+    runSingleFlushTest(sensors, true /* activateSensor */, 1 /* expectedFlushCount */, Result::OK);
+    runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, Result::OK);
+}
+
+TEST_P(SensorsHidlTest, FlushOneShotSensor) {
+    // Find a sensor that is a one-shot sensor
+    std::vector<SensorInfoType> sensors = getOneShotSensors();
+    if (sensors.size() == 0) {
+        return;
+    }
+
+    runSingleFlushTest(sensors, true /* activateSensor */, 0 /* expectedFlushCount */,
+                       Result::BAD_VALUE);
+}
+
+TEST_P(SensorsHidlTest, FlushInactiveSensor) {
+    // Attempt to find a non-one shot sensor, then a one-shot sensor if necessary
+    std::vector<SensorInfoType> sensors = getNonOneShotSensors();
+    if (sensors.size() == 0) {
+        sensors = getOneShotSensors();
+        if (sensors.size() == 0) {
+            return;
+        }
+    }
+
+    runSingleFlushTest(sensors, false /* activateSensor */, 0 /* expectedFlushCount */,
+                       Result::BAD_VALUE);
+}
+
+TEST_P(SensorsHidlTest, Batch) {
+    if (getSensorsList().size() == 0) {
+        return;
+    }
+
+    activateAllSensors(false /* enable */);
+    for (const SensorInfoType& sensor : getSensorsList()) {
+        // Call batch on inactive sensor
+        // One shot sensors have minDelay set to -1 which is an invalid
+        // parameter. Use 0 instead to avoid errors.
+        int64_t samplingPeriodNs = extractReportMode(sensor.flags) == SensorFlagBits::ONE_SHOT_MODE
+                                           ? 0
+                                           : sensor.minDelay;
+        ASSERT_EQ(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */),
+                  Result::OK);
+
+        // Activate the sensor
+        activate(sensor.sensorHandle, true /* enabled */);
+
+        // Call batch on an active sensor
+        ASSERT_EQ(batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */),
+                  Result::OK);
+    }
+    activateAllSensors(false /* enable */);
+
+    // Call batch on an invalid sensor
+    SensorInfoType sensor = getSensorsList().front();
+    sensor.sensorHandle = getInvalidSensorHandle();
+    ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
+              Result::BAD_VALUE);
+}
+
+TEST_P(SensorsHidlTest, Activate) {
+    if (getSensorsList().size() == 0) {
+        return;
+    }
+
+    // Verify that sensor events are generated when activate is called
+    for (const SensorInfoType& sensor : getSensorsList()) {
+        batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */);
+        ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);
+
+        // Call activate on a sensor that is already activated
+        ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);
+
+        // Deactivate the sensor
+        ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK);
+
+        // Call deactivate on a sensor that is already deactivated
+        ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK);
+    }
+
+    // Attempt to activate an invalid sensor
+    int32_t invalidHandle = getInvalidSensorHandle();
+    ASSERT_EQ(activate(invalidHandle, true), Result::BAD_VALUE);
+    ASSERT_EQ(activate(invalidHandle, false), Result::BAD_VALUE);
+}
+
+TEST_P(SensorsHidlTest, NoStaleEvents) {
+    constexpr milliseconds kFiveHundredMs(500);
+    constexpr milliseconds kOneSecond(1000);
+
+    // Register the callback to receive sensor events
+    EventCallback callback;
+    getEnvironment()->registerCallback(&callback);
+
+    // This test is not valid for one-shot or special-report-mode sensors
+    const std::vector<SensorInfoType> sensors = getNonOneShotAndNonSpecialSensors();
+    milliseconds maxMinDelay(0);
+    for (const SensorInfoType& sensor : sensors) {
+        milliseconds minDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
+        maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
+    }
+
+    // Activate the sensors so that they start generating events
+    activateAllSensors(true);
+
+    // According to the CDD, the first sample must be generated within 400ms + 2 * sample_time
+    // and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount
+    // of time to guarantee that a sample has arrived.
+    callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
+    activateAllSensors(false);
+
+    // Save the last received event for each sensor
+    std::map<int32_t, int64_t> lastEventTimestampMap;
+    for (const SensorInfoType& sensor : sensors) {
+        // Some on-change sensors may not report an event without stimulus
+        if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) {
+            ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
+        }
+        if (callback.getEvents(sensor.sensorHandle).size() >= 1) {
+            lastEventTimestampMap[sensor.sensorHandle] =
+                    callback.getEvents(sensor.sensorHandle).back().timestamp;
+        }
+    }
+
+    // Allow some time to pass, reset the callback, then reactivate the sensors
+    usleep(duration_cast<microseconds>(kOneSecond + (5 * maxMinDelay)).count());
+    callback.reset();
+    activateAllSensors(true);
+    callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
+    activateAllSensors(false);
+
+    for (const SensorInfoType& sensor : sensors) {
+        // Skip sensors that did not previously report an event
+        if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
+            continue;
+        }
+        // Skip on-change sensors that do not consistently report an initial event
+        if (callback.getEvents(sensor.sensorHandle).size() < 1) {
+            continue;
+        }
+        // Ensure that the first event received is not stale by ensuring that its timestamp is
+        // sufficiently different from the previous event
+        const EventType newEvent = callback.getEvents(sensor.sensorHandle).front();
+        milliseconds delta = duration_cast<milliseconds>(
+                nanoseconds(newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]));
+        milliseconds sensorMinDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
+        ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay));
+    }
+}
+
+void SensorsHidlTest::checkRateLevel(const SensorInfoType& sensor, int32_t directChannelHandle,
+                                     RateLevel rateLevel) {
+    configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel,
+                       [&](Result result, int32_t reportToken) {
+                           if (isDirectReportRateSupported(sensor, rateLevel)) {
+                               ASSERT_EQ(result, Result::OK);
+                               if (rateLevel != RateLevel::STOP) {
+                                   ASSERT_GT(reportToken, 0);
+                               }
+                           } else {
+                               ASSERT_EQ(result, Result::BAD_VALUE);
+                           }
+                       });
+}
+
+void SensorsHidlTest::queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
+                                                bool* supportsAnyDirectChannel) {
+    *supportsSharedMemType = false;
+    *supportsAnyDirectChannel = false;
+    for (const SensorInfoType& curSensor : getSensorsList()) {
+        if (isDirectChannelTypeSupported(curSensor, memType)) {
+            *supportsSharedMemType = true;
+        }
+        if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM) ||
+            isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) {
+            *supportsAnyDirectChannel = true;
+        }
+
+        if (*supportsSharedMemType && *supportsAnyDirectChannel) {
+            break;
+        }
+    }
+}
+
+void SensorsHidlTest::verifyRegisterDirectChannel(
+        std::shared_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem,
+        int32_t* directChannelHandle, bool supportsSharedMemType, bool supportsAnyDirectChannel) {
+    char* buffer = mem->getBuffer();
+    memset(buffer, 0xff, mem->getSize());
+
+    registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
+        if (supportsSharedMemType) {
+            ASSERT_EQ(result, Result::OK);
+            ASSERT_GT(channelHandle, 0);
+
+            // Verify that the memory has been zeroed
+            for (size_t i = 0; i < mem->getSize(); i++) {
+                ASSERT_EQ(buffer[i], 0x00);
+            }
+        } else {
+            Result expectedResult =
+                    supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
+            ASSERT_EQ(result, expectedResult);
+            ASSERT_EQ(channelHandle, -1);
+        }
+        *directChannelHandle = channelHandle;
+    });
+}
+
+void SensorsHidlTest::verifyConfigure(const SensorInfoType& sensor, SharedMemType memType,
+                                      int32_t directChannelHandle, bool supportsAnyDirectChannel) {
+    if (isDirectChannelTypeSupported(sensor, memType)) {
+        // Verify that each rate level is properly supported
+        checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL);
+        checkRateLevel(sensor, directChannelHandle, RateLevel::FAST);
+        checkRateLevel(sensor, directChannelHandle, RateLevel::VERY_FAST);
+        checkRateLevel(sensor, directChannelHandle, RateLevel::STOP);
+
+        // Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP
+        configDirectReport(-1 /* sensorHandle */, directChannelHandle, RateLevel::NORMAL,
+                           [](Result result, int32_t /* reportToken */) {
+                               ASSERT_EQ(result, Result::BAD_VALUE);
+                           });
+        configDirectReport(
+                -1 /* sensorHandle */, directChannelHandle, RateLevel::STOP,
+                [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
+    } else {
+        // directChannelHandle will be -1 here, HAL should either reject it as a bad value if there
+        // is some level of direct channel report, otherwise return INVALID_OPERATION if direct
+        // channel is not supported at all
+        Result expectedResult =
+                supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
+        configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL,
+                           [expectedResult](Result result, int32_t /* reportToken */) {
+                               ASSERT_EQ(result, expectedResult);
+                           });
+    }
+}
+
+void SensorsHidlTest::verifyUnregisterDirectChannel(int32_t directChannelHandle,
+                                                    bool supportsAnyDirectChannel) {
+    Result expectedResult = supportsAnyDirectChannel ? Result::OK : Result::INVALID_OPERATION;
+    ASSERT_EQ(unregisterDirectChannel(directChannelHandle), expectedResult);
+}
+
+void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) {
+    constexpr size_t kNumEvents = 1;
+    constexpr size_t kMemSize = kNumEvents * kEventSize;
+
+    std::shared_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem(
+            SensorsTestSharedMemory<SensorTypeVersion, EventType>::create(memType, kMemSize));
+    ASSERT_NE(mem, nullptr);
+
+    bool supportsSharedMemType;
+    bool supportsAnyDirectChannel;
+    queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel);
+
+    for (const SensorInfoType& sensor : getSensorsList()) {
+        int32_t directChannelHandle = 0;
+        verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType,
+                                    supportsAnyDirectChannel);
+        verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel);
+        verifyUnregisterDirectChannel(directChannelHandle, supportsAnyDirectChannel);
+    }
+}
+
+TEST_P(SensorsHidlTest, DirectChannelAshmem) {
+    verifyDirectChannel(SharedMemType::ASHMEM);
+}
+
+TEST_P(SensorsHidlTest, DirectChannelGralloc) {
+    verifyDirectChannel(SharedMemType::GRALLOC);
+}
+
+bool SensorsHidlTest::getDirectChannelSensor(SensorInfoType* sensor, SharedMemType* memType,
+                                             RateLevel* rate) {
+    bool found = false;
+    for (const SensorInfoType& curSensor : getSensorsList()) {
+        if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM)) {
+            *memType = SharedMemType::ASHMEM;
+            *sensor = curSensor;
+            found = true;
+            break;
+        } else if (isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) {
+            *memType = SharedMemType::GRALLOC;
+            *sensor = curSensor;
+            found = true;
+            break;
+        }
+    }
+
+    if (found) {
+        // Find a supported rate level
+        constexpr int kNumRateLevels = 3;
+        RateLevel rates[kNumRateLevels] = {RateLevel::NORMAL, RateLevel::FAST,
+                                           RateLevel::VERY_FAST};
+        *rate = RateLevel::STOP;
+        for (int i = 0; i < kNumRateLevels; i++) {
+            if (isDirectReportRateSupported(*sensor, rates[i])) {
+                *rate = rates[i];
+            }
+        }
+
+        // At least one rate level must be supported
+        EXPECT_NE(*rate, RateLevel::STOP);
+    }
+    return found;
+}
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..ca4346a 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -20,9 +20,6 @@
     cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
     srcs: [
         "GrallocWrapper.cpp",
-        "SensorsHidlEnvironmentBase.cpp",
-        "SensorsHidlTestBase.cpp",
-        "SensorsTestSharedMemory.cpp",
     ],
     export_include_dirs: [
         "include",
@@ -30,6 +27,9 @@
     local_include_dirs: [
         "include/sensors-vts-utils",
     ],
+    shared_libs: [
+        "libutils",
+    ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
@@ -37,5 +37,7 @@
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "android.hardware.sensors@2.1",
     ],
 }
diff --git a/sensors/common/vts/utils/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/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.3/Android.bp b/soundtrigger/2.3/Android.bp
new file mode 100644
index 0000000..3253a86
--- /dev/null
+++ b/soundtrigger/2.3/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.soundtrigger@2.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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/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/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 1e07edd..7e206a7 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -81,6 +81,10 @@
 Return<Result> Frontend::scan(const FrontendSettings& /* settings */, FrontendScanType /* type */) {
     ALOGV("%s", __FUNCTION__);
 
+    FrontendScanMessage msg;
+    msg.isLocked(true);
+    mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
+
     return Result::SUCCESS;
 }
 
@@ -90,11 +94,66 @@
     return Result::SUCCESS;
 }
 
-Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& /* statusTypes */,
+Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
                                  getStatus_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
     vector<FrontendStatus> statuses;
+    for (int i = 0; i < statusTypes.size(); i++) {
+        FrontendStatusType type = statusTypes[i];
+        FrontendStatus status;
+        // assign randomly selected values for testing.
+        switch (type) {
+            case FrontendStatusType::DEMOD_LOCK: {
+                status.isDemodLocked(true);
+                break;
+            }
+            case FrontendStatusType::SNR: {
+                status.snr(221);
+                break;
+            }
+            case FrontendStatusType::FEC: {
+                status.innerFec(FrontendInnerFec::FEC_2_9);  // value = 1 << 7
+                break;
+            }
+            case FrontendStatusType::MODULATION: {
+                FrontendModulationStatus modulationStatus;
+                modulationStatus.isdbt(FrontendIsdbtModulation::MOD_16QAM);  // value = 1 << 3
+                status.modulation(modulationStatus);
+                break;
+            }
+            case FrontendStatusType::PLP_ID: {
+                status.plpId(101);  // type uint8_t
+                break;
+            }
+            case FrontendStatusType::LAYER_ERROR: {
+                vector<bool> v = {false, true, true};
+                status.isLayerError(v);
+                break;
+            }
+            case FrontendStatusType::ATSC3_PLP_INFO: {
+                vector<FrontendStatusAtsc3PlpInfo> v;
+                FrontendStatusAtsc3PlpInfo info1{
+                        .plpId = 3,
+                        .isLocked = false,
+                        .uec = 313,
+                };
+                FrontendStatusAtsc3PlpInfo info2{
+                        .plpId = 5,
+                        .isLocked = true,
+                        .uec = 515,
+                };
+                v.push_back(info1);
+                v.push_back(info2);
+                status.plpInfo(v);
+                break;
+            }
+            default: {
+                continue;
+            }
+        }
+        statuses.push_back(status);
+    }
     _hidl_cb(Result::SUCCESS, statuses);
 
     return Void();
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index c6017f0..4fd3355 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -109,7 +109,37 @@
 Return<void> Tuner::getFrontendInfo(FrontendId /* frontendId */, getFrontendInfo_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    FrontendInfo info;
+    vector<FrontendStatusType> statusCaps = {
+            FrontendStatusType::DEMOD_LOCK,
+            FrontendStatusType::SNR,
+            FrontendStatusType::FEC,
+            FrontendStatusType::MODULATION,
+            FrontendStatusType::PLP_ID,
+            FrontendStatusType::LAYER_ERROR,
+            FrontendStatusType::ATSC3_PLP_INFO,
+    };
+    FrontendInfo::FrontendCapabilities frontendCaps;
+    FrontendIsdbtCapabilities isdbtCaps{
+            .modeCap = FrontendIsdbtMode::MODE_1 | FrontendIsdbtMode::MODE_2,
+            .bandwidthCap = (unsigned int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ,
+            .modulationCap = (unsigned int)FrontendIsdbtModulation::MOD_16QAM,
+            // ISDBT shares coderate and guard interval with DVBT
+            .coderateCap = FrontendDvbtCoderate::CODERATE_4_5 | FrontendDvbtCoderate::CODERATE_6_7,
+            .guardIntervalCap = (unsigned int)FrontendDvbtGuardInterval::INTERVAL_1_128,
+    };
+    frontendCaps.isdbtCaps(isdbtCaps);
+    // assign randomly selected values for testing.
+    FrontendInfo info{
+            .type = FrontendType::ISDBT,
+            .minFrequency = 139,
+            .maxFrequency = 1139,
+            .minSymbolRate = 45,
+            .maxSymbolRate = 1145,
+            .acquireRange = 30,
+            .exclusiveGroupId = 57,
+            .statusCaps = statusCaps,
+            .frontendCaps = frontendCaps,
+    };
 
     _hidl_cb(Result::SUCCESS, info);
     return Void();
diff --git a/tv/tuner/1.0/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/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 820c58c..f693e7c 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.
@@ -44,6 +44,8 @@
 #include <iostream>
 #include <map>
 
+#include "VtsHalTvTunerV1_0TestConfigurations.h"
+
 #define WAIT_TIMEOUT 3000000000
 #define WAIT_TIMEOUT_data_ready 3000000000 * 4
 
@@ -84,9 +86,11 @@
 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::IDemux;
 using android::hardware::tv::tuner::V1_0::IDescrambler;
@@ -103,6 +107,8 @@
 using android::hardware::tv::tuner::V1_0::RecordStatus;
 using android::hardware::tv::tuner::V1_0::Result;
 
+using ::testing::AssertionResult;
+
 namespace {
 
 using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
@@ -150,11 +156,7 @@
 // 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;
-};
+const uint8_t FRONTEND_EVENT_CALLBACK_WAIT_COUNT = 4;
 
 enum FilterEventType : uint8_t {
     UNDEFINED,
@@ -172,6 +174,7 @@
     PlaybackSettings setting;
 };
 
+/******************************** Start FrontendCallback **********************************/
 class FrontendCallback : public IFrontendCallback {
   public:
     virtual Return<void> onEvent(FrontendEventType frontendEventType) override {
@@ -182,28 +185,38 @@
         return Void();
     }
 
-    virtual Return<void> onScanMessage(FrontendScanMessageType /* type */,
-                                       const FrontendScanMessage& /* message */) override {
+    virtual Return<void> onScanMessage(FrontendScanMessageType type,
+                                       const FrontendScanMessage& message) override {
         android::Mutex::Autolock autoLock(mMsgLock);
+        ALOGD("[vts] scan message. Type: %d", mScanMessageType);
         mScanMessageReceived = true;
+        mScanMessageType = type;
+        mScanLockMessageReceived =
+                mScanLockMessageReceived | (type == FrontendScanMessageType::LOCKED);
+        mScanMessage = message;
         mMsgCondition.signal();
         return Void();
     };
 
-    void testOnEvent(sp<IFrontend>& frontend, FrontendSettings settings);
-    void testOnDiseqcMessage(sp<IFrontend>& frontend, FrontendSettings settings);
+    void tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings);
+    void tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings);
+    void scanTestOnMessageLock(sp<IFrontend>& frontend, FrontendSettings settings,
+                               FrontendScanType type);
 
   private:
     bool mEventReceived = false;
-    bool mDiseqcMessageReceived = false;
     bool mScanMessageReceived = false;
+    bool mScanLockMessageReceived = false;
     FrontendEventType mEventType;
+    FrontendScanMessageType mScanMessageType;
+    FrontendScanMessage mScanMessage;
     hidl_vec<uint8_t> mEventMessage;
     android::Mutex mMsgLock;
     android::Condition mMsgCondition;
+    uint8_t mOnEvenRetry = 0;
 };
 
-void FrontendCallback::testOnEvent(sp<IFrontend>& frontend, FrontendSettings settings) {
+void FrontendCallback::tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings) {
     Result result = frontend->tune(settings);
 
     EXPECT_TRUE(result == Result::SUCCESS);
@@ -215,29 +228,77 @@
             return;
         }
     }
+    mEventReceived = false;
 }
 
-void FrontendCallback::testOnDiseqcMessage(sp<IFrontend>& frontend, FrontendSettings settings) {
+void FrontendCallback::tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings) {
     Result result = frontend->tune(settings);
 
     EXPECT_TRUE(result == Result::SUCCESS);
 
     android::Mutex::Autolock autoLock(mMsgLock);
-    while (!mDiseqcMessageReceived) {
+wait:
+    while (!mEventReceived) {
         if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
-            EXPECT_TRUE(false) << "diseqc message not received within timeout";
+            EXPECT_TRUE(false) << "event not received within timeout";
             return;
         }
     }
+    if (mEventType != FrontendEventType::LOCKED) {
+        ALOGD("[vts] frontend callback event received. Type: %d", mEventType);
+        mEventReceived = false;
+        if (mOnEvenRetry++ < FRONTEND_EVENT_CALLBACK_WAIT_COUNT) {
+            goto wait;
+        }
+    }
+    EXPECT_TRUE(mEventType == FrontendEventType::LOCKED) << "LOCK event not received";
+    mEventReceived = false;
+    mOnEvenRetry = 0;
 }
 
+void FrontendCallback::scanTestOnMessageLock(sp<IFrontend>& frontend, FrontendSettings settings,
+                                             FrontendScanType type) {
+    Result result = frontend->scan(settings, type);
+    EXPECT_TRUE(result == Result::SUCCESS);
+    android::Mutex::Autolock autoLock(mMsgLock);
+    int messagesCount = 0;
+
+wait:
+    int count = 0;
+    while (!mScanMessageReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            ALOGD("[vts] waiting for scan message callback...");
+            if (count++ > 10) {
+                EXPECT_TRUE(false) << "WAITING TOO LONG!!";
+                return;
+            }
+        }
+    }
+
+    if (mScanMessageType != FrontendScanMessageType::END) {
+        ALOGD("[vts] frontend scan message received. Type: %d", mScanMessageType);
+        mScanMessageReceived = false;
+        if (messagesCount++ > 3) {
+            EXPECT_TRUE(false) << "WAITING ON TOO MANY MSGS!!";
+            return;
+        }
+        goto wait;
+    }
+
+    EXPECT_TRUE(mScanLockMessageReceived) << "scan lock message not received before scan ended";
+    mScanMessageReceived = false;
+    mScanLockMessageReceived = false;
+}
+/******************************** End FrontendCallback **********************************/
+
+/******************************** Start FilterCallback **********************************/
 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;
+        mFilterEvent = filterEvent;
         readFilterEventData();
         mPidFilterOutputCount++;
         // mFilterIdToMQ.erase(filterEvent.filterId);
@@ -276,9 +337,9 @@
 
     uint32_t mFilterId;
     FilterEventType mFilterEventType;
-    std::unique_ptr<FilterMQ> mFilterIdToMQ;
-    EventFlag* mFilterIdToMQEventFlag;
-    DemuxFilterEvent mFilterIdToEvent;
+    std::unique_ptr<FilterMQ> mFilterMQ;
+    EventFlag* mFilterMQEventFlag;
+    DemuxFilterEvent mFilterEvent;
 
     android::Mutex mMsgLock;
     android::Mutex mFilterOutputLock;
@@ -313,10 +374,10 @@
 }
 
 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);
+    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) {
@@ -332,7 +393,7 @@
 
 void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
     android::Mutex::Autolock autoLock(mFilterOutputLock);
-    // Read from mFilterIdToMQ[event.filterId] per event and filter type
+    // Read from mFilterMQ[event.filterId] per event and filter type
 
     // Assemble to filterOutput[filterId]
 
@@ -345,7 +406,7 @@
 
 bool FilterCallback::readFilterEventData() {
     bool result = false;
-    DemuxFilterEvent filterEvent = mFilterIdToEvent;
+    DemuxFilterEvent filterEvent = mFilterEvent;
     ALOGW("[vts] reading from filter FMQ %d", mFilterId);
     // todo separate filter handlers
     for (int i = 0; i < filterEvent.events.size(); i++) {
@@ -357,6 +418,7 @@
                 mDataLength = filterEvent.events[i].pes().dataLength;
                 break;
             case FilterEventType::MEDIA:
+                mDataLength = filterEvent.events[i].media().dataLength;
                 break;
             case FilterEventType::RECORD:
                 break;
@@ -371,17 +433,19 @@
         // match";
 
         mDataOutputBuffer.resize(mDataLength);
-        result = mFilterIdToMQ->read(mDataOutputBuffer.data(), 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";
         }*/
     }
-    mFilterIdToMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+    mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
     return result;
 }
+/******************************** End FilterCallback **********************************/
 
+/******************************** Start DvrCallback **********************************/
 class DvrCallback : public IDvrCallback {
   public:
     virtual Return<void> onRecordStatus(DemuxFilterStatus status) override {
@@ -445,11 +509,10 @@
     uint16_t mDataLength = 0;
     std::vector<uint8_t> mDataOutputBuffer;
 
-    std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
+    std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterMQ;
     std::unique_ptr<FilterMQ> mPlaybackMQ;
     std::unique_ptr<FilterMQ> mRecordMQ;
-    std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
-    std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
+    std::map<uint32_t, EventFlag*> mFilterMQEventFlag;
 
     android::Mutex mMsgLock;
     android::Mutex mPlaybackThreadLock;
@@ -635,22 +698,32 @@
     mRecordThreadRunning = false;
     android::Mutex::Autolock autoLock(mRecordThreadLock);
 }
+/********************************** End DvrCallback ************************************/
 
+/***************************** Start Test Implementation ******************************/
 class TunerHidlTest : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
         mService = ITuner::getService(GetParam());
         ASSERT_NE(mService, nullptr);
+        initFrontendConfig();
+        initFrontendScanConfig();
+        initFilterConfig();
     }
 
     sp<ITuner> mService;
 
   protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
     static void description(const std::string& description) {
         RecordProperty("description", description);
     }
 
     sp<IFrontend> mFrontend;
+    FrontendInfo mFrontendInfo;
     sp<FrontendCallback> mFrontendCallback;
     sp<IDescrambler> mDescrambler;
     sp<IDemux> mDemux;
@@ -661,274 +734,165 @@
     sp<FilterCallback> mFilterCallback;
     sp<DvrCallback> mDvrCallback;
     MQDesc mFilterMQDescriptor;
-    MQDesc mPlaybackMQDescriptor;
+    MQDesc mDvrMQDescriptor;
     MQDesc mRecordMQDescriptor;
     vector<uint32_t> mUsedFilterIds;
+    hidl_vec<FrontendId> mFeIds;
 
     uint32_t mDemuxId;
-    uint32_t mFilterId;
+    uint32_t mFilterId = -1;
 
     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();
+    AssertionResult getFrontendIds();
+    AssertionResult getFrontendInfo(uint32_t frontendId);
+    AssertionResult openFrontend(uint32_t frontendId);
+    AssertionResult setFrontendCallback();
+    AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type);
+    AssertionResult stopScanFrontend();
+    AssertionResult tuneFrontend(FrontendConfig config);
+    AssertionResult stopTuneFrontend();
+    AssertionResult closeFrontend();
 
-    ::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);
+    AssertionResult openDemux();
+    AssertionResult setDemuxFrontendDataSource(uint32_t frontendId);
+    AssertionResult closeDemux();
+
+    AssertionResult openDvrInDemux(DvrType type);
+    AssertionResult configDvr(DvrSettings setting);
+    AssertionResult getDvrMQDescriptor();
+
+    AssertionResult openFilterInDemux(DemuxFilterType type);
+    AssertionResult getNewlyOpenedFilterId(uint32_t& filterId);
+    AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId);
+    AssertionResult getFilterMQDescriptor(uint32_t filterId);
+    AssertionResult startFilter(uint32_t filterId);
+    AssertionResult stopFilter(uint32_t filterId);
+    AssertionResult closeFilter(uint32_t filterId);
+
+    AssertionResult createDescrambler();
+    AssertionResult closeDescrambler();
+
+    AssertionResult playbackDataFlowTest(vector<FilterConfig> filterConf, PlaybackConf playbackConf,
+                                         vector<string> goldenOutputFiles);
+    AssertionResult recordDataFlowTest(vector<FilterConfig> filterConf,
+                                       RecordSettings recordSetting,
+                                       vector<string> goldenOutputFiles);
+    AssertionResult broadcastDataFlowTest(vector<string> goldenOutputFiles);
+
+    FilterEventType getFilterEventType(DemuxFilterType type);
 };
 
-::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) {
+/*========================== Start Frontend APIs Tests Implementation ==========================*/
+AssertionResult TunerHidlTest::getFrontendIds() {
     Result status;
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        mFeIds = frontendIds;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
 
+AssertionResult TunerHidlTest::getFrontendInfo(uint32_t frontendId) {
+    Result status;
+    mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) {
+        mFrontendInfo = frontendInfo;
+        status = result;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult TunerHidlTest::openFrontend(uint32_t frontendId) {
+    Result status;
     mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) {
         mFrontend = frontend;
         status = result;
     });
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
-    }
+    return AssertionResult(status == Result::SUCCESS);
+}
 
+AssertionResult TunerHidlTest::setFrontendCallback() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontend first.";
     mFrontendCallback = new FrontendCallback();
     auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
-
-    return ::testing::AssertionResult(callbackStatus.isOk());
+    return AssertionResult(callbackStatus.isOk());
 }
 
-::testing::AssertionResult TunerHidlTest::tuneFrontend(int32_t frontendId) {
-    if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
+AssertionResult TunerHidlTest::scanFrontend(FrontendConfig config, FrontendScanType type) {
+    EXPECT_TRUE(mFrontendCallback)
+            << "test with openFrontend/setFrontendCallback/getFrontendInfo first.";
 
-    // Frontend Settings for testing
-    FrontendSettings frontendSettings;
-    FrontendAtscSettings frontendAtscSettings{
-            .frequency = 0,
-            .modulation = FrontendAtscModulation::UNDEFINED,
-    };
-    frontendSettings.atsc(frontendAtscSettings);
-    mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
+    EXPECT_TRUE(mFrontendInfo.type == config.type)
+            << "FrontendConfig does not match the frontend info of the given id.";
 
-    FrontendDvbtSettings frontendDvbtSettings{
-            .frequency = 0,
-    };
-    frontendSettings.dvbt(frontendDvbtSettings);
-    mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
-
-    return ::testing::AssertionResult(true);
+    mFrontendCallback->scanTestOnMessageLock(mFrontend, config.settings, type);
+    return AssertionResult(true);
 }
 
-::testing::AssertionResult TunerHidlTest::stopTuneFrontend(int32_t frontendId) {
+AssertionResult TunerHidlTest::stopScanFrontend() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontend first.";
     Result status;
-    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
+    status = mFrontend->stopScan();
+    return AssertionResult(status == Result::SUCCESS);
+}
 
+AssertionResult TunerHidlTest::tuneFrontend(FrontendConfig config) {
+    EXPECT_TRUE(mFrontendCallback)
+            << "test with openFrontend/setFrontendCallback/getFrontendInfo first.";
+
+    EXPECT_TRUE(mFrontendInfo.type == config.type)
+            << "FrontendConfig does not match the frontend info of the given id.";
+
+    mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
+    return AssertionResult(true);
+}
+
+AssertionResult TunerHidlTest::stopTuneFrontend() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontend first.";
+    Result status;
     status = mFrontend->stopTune();
-    return ::testing::AssertionResult(status == Result::SUCCESS);
+    return AssertionResult(status == Result::SUCCESS);
 }
 
-::testing::AssertionResult TunerHidlTest::closeFrontend(int32_t frontendId) {
+AssertionResult TunerHidlTest::closeFrontend() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontend first.";
     Result status;
-    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
     status = mFrontend->close();
     mFrontend = nullptr;
-    return ::testing::AssertionResult(status == Result::SUCCESS);
+    mFrontendCallback = nullptr;
+    return AssertionResult(status == Result::SUCCESS);
 }
+/*=========================== End Frontend APIs Tests Implementation ===========================*/
 
-::testing::AssertionResult TunerHidlTest::createDemux() {
+/*============================ Start Demux APIs Tests Implementation ============================*/
+AssertionResult TunerHidlTest::openDemux() {
     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);
+    return 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);
+AssertionResult TunerHidlTest::setDemuxFrontendDataSource(uint32_t frontendId) {
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mFrontend) << "Test with openFrontend first.";
+    auto status = mDemux->setFrontendDataSource(frontendId);
+    return AssertionResult(status.isOk());
 }
 
-::testing::AssertionResult TunerHidlTest::closeDemux() {
-    Result status;
-    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    status = mDemux->close();
+AssertionResult TunerHidlTest::closeDemux() {
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    auto status = mDemux->close();
     mDemux = nullptr;
-    return ::testing::AssertionResult(status == Result::SUCCESS);
+    return AssertionResult(status.isOk());
 }
 
-::testing::AssertionResult TunerHidlTest::createDescrambler() {
+AssertionResult TunerHidlTest::openFilterInDemux(DemuxFilterType type) {
     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();
-    }
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
 
     // Create demux callback
     mFilterCallback = new FilterCallback();
@@ -940,21 +904,322 @@
                            status = result;
                        });
 
-    if (status != Result::SUCCESS) {
-        return ::testing::AssertionFailure();
+    if (status == Result::SUCCESS) {
+        mFilterCallback->setFilterEventType(getFilterEventType(type));
     }
 
+    return AssertionResult(status == Result::SUCCESS);
+}
+/*============================ End Demux APIs Tests Implementation ============================*/
+
+/*=========================== Start Filter APIs Tests Implementation ===========================*/
+AssertionResult TunerHidlTest::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) {
-        return ::testing::AssertionFailure();
+    if (status == Result::SUCCESS) {
+        mFilterCallback->setFilterId(mFilterId);
+        mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId);
+        mFilters[mFilterId] = mFilter;
+        mFilterCallbacks[mFilterId] = mFilterCallback;
+        filterId = mFilterId;
     }
 
-    mFilterCallback->setFilterId(mFilterId);
+    return AssertionResult(status == Result::SUCCESS || status == Result::UNAVAILABLE);
+}
 
+AssertionResult TunerHidlTest::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 TunerHidlTest::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 TunerHidlTest::startFilter(uint32_t filterId) {
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    Result status = mFilters[filterId]->start();
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult TunerHidlTest::stopFilter(uint32_t filterId) {
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    Result status = mFilters[filterId]->stop();
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult TunerHidlTest::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);
+}
+/*=========================== End Filter APIs Tests Implementation ===========================*/
+
+/*======================== Start Descrambler APIs Tests Implementation ========================*/
+AssertionResult TunerHidlTest::createDescrambler() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
+        mDescrambler = descrambler;
+        status = result;
+    });
+    if (status != Result::SUCCESS) {
+        return failure();
+    }
+
+    status = mDescrambler->setDemuxSource(mDemuxId);
+    if (status != Result::SUCCESS) {
+        return failure();
+    }
+
+    // Test if demux source can be set more than once.
+    status = mDescrambler->setDemuxSource(mDemuxId);
+    return AssertionResult(status == Result::INVALID_STATE);
+}
+
+AssertionResult TunerHidlTest::closeDescrambler() {
+    Result status;
+    if (!mDescrambler && createDescrambler() == failure()) {
+        return failure();
+    }
+
+    status = mDescrambler->close();
+    mDescrambler = nullptr;
+    return AssertionResult(status == Result::SUCCESS);
+}
+/*========================= End Descrambler APIs Tests Implementation =========================*/
+
+/*============================ Start Dvr APIs Tests Implementation ============================*/
+AssertionResult TunerHidlTest::openDvrInDemux(DvrType type) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+
+    // Create dvr callback
+    mDvrCallback = new DvrCallback();
+
+    mDemux->openDvr(type, FMQ_SIZE_1M, mDvrCallback, [&](Result result, const sp<IDvr>& dvr) {
+        mDvr = dvr;
+        status = result;
+    });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult TunerHidlTest::configDvr(DvrSettings setting) {
+    Result status = mDvr->configure(setting);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult TunerHidlTest::getDvrMQDescriptor() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvr) << "Test with openDvr first.";
+
+    mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+        mDvrMQDescriptor = dvrMQDesc;
+        status = result;
+    });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+/*============================ End Dvr APIs Tests Implementation ============================*/
+
+/*========================== Start Data Flow Tests Implementation ==========================*/
+AssertionResult TunerHidlTest::broadcastDataFlowTest(vector<string> /*goldenOutputFiles*/) {
+    EXPECT_TRUE(mFrontend) << "Test with openFilterInDemux first.";
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mFilterCallback) << "Test with getFilterMQDescriptor first.";
+
+    // Data Verify Module
+    std::map<uint32_t, sp<FilterCallback>>::iterator it;
+    for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) {
+        it->second->testFilterDataOutput();
+    }
+    return success();
+}
+
+/*
+ * TODO: re-enable the tests after finalizing the test refactoring.
+ */
+/*AssertionResult TunerHidlTest::playbackDataFlowTest(
+        vector<FilterConf> filterConf, PlaybackConf playbackConf,
+        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) ==
+                    failure() ||
+            // TODO use a map to save the FMQs/EvenFlags and pass to callback
+            getFilterMQDescriptor() == failure()) {
+            return failure();
+        }
+        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 failure();
+        }
+    }
+
+    // Playback Input Module
+    PlaybackSettings playbackSetting = playbackConf.setting;
+    if (addPlaybackToDemux(playbackSetting) == failure() ||
+        getPlaybackMQDescriptor() == failure()) {
+        return failure();
+    }
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
+            return failure();
+        }
+    }
+    mDvrCallback->startPlaybackInputThread(playbackConf, mPlaybackMQDescriptor);
+    status = mDvr->start();
+    if (status != Result::SUCCESS) {
+        return failure();
+    }
+
+    // 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 failure();
+        }
+    }
+    if (mDvr->stop() != Result::SUCCESS) {
+        return failure();
+    }
+    mUsedFilterIds.clear();
+    mFilterCallbacks.clear();
+    mFilters.clear();
+    return closeDemux();
+}
+
+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 failure();
+    }
+
+    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) ==
+                    failure() ||
+            // TODO use a map to save the FMQs/EvenFlags and pass to callback
+            getFilterMQDescriptor() == failure()) {
+            return failure();
+        }
+        filterIdsSize = mUsedFilterIds.size();
+        mUsedFilterIds.resize(filterIdsSize + 1);
+        mUsedFilterIds[filterIdsSize] = mFilterId;
+        mFilters[mFilterId] = mFilter;
+    }
+
+    // Record Config Module
+    if (addRecordToDemux(recordSetting) == failure() ||
+        getRecordMQDescriptor() == failure()) {
+        return failure();
+    }
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
+            return failure();
+        }
+    }
+
+    mDvrCallback->startRecordOutputThread(recordSetting, mRecordMQDescriptor);
+    status = mDvr->start();
+    if (status != Result::SUCCESS) {
+        return failure();
+    }
+
+    if (setDemuxFrontendDataSource(feIds[0]) != success()) {
+        return failure();
+    }
+
+    // Data Verify Module
+    mDvrCallback->testRecordOutput();
+
+    // Clean Up Module
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
+            return failure();
+        }
+    }
+    if (mFrontend->stopTune() != Result::SUCCESS) {
+        return failure();
+    }
+    mUsedFilterIds.clear();
+    mFilterCallbacks.clear();
+    mFilters.clear();
+    return closeDemux();
+}*/
+/*========================= End Data Flow Tests Implementation =========================*/
+
+/*=============================== Start Helper Functions ===============================*/
+FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) {
     FilterEventType eventType = FilterEventType::UNDEFINED;
     switch (type.mainType) {
         case DemuxFilterMainType::TS:
@@ -998,358 +1263,151 @@
         default:
             break;
     }
-    mFilterCallback->setFilterEventType(eventType);
+    return eventType;
+}
+/*============================== End Helper Functions ==============================*/
+/***************************** End Test Implementation *****************************/
 
-    // Configure the filter
-    status = mFilter->configure(setting);
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
+/******************************** Start Test Entry **********************************/
+/*============================== Start Frontend Tests ==============================*/
+TEST_P(TunerHidlTest, getFrontendIds) {
+    description("Get Frontend ids and verify frontends exist");
+    ASSERT_TRUE(getFrontendIds());
+    ASSERT_TRUE(mFeIds.size() > 0);
 }
 
-::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor() {
-    Result status;
+TEST_P(TunerHidlTest, openFrontend) {
+    description("Open all the existing Frontends and close them");
+    ASSERT_TRUE(getFrontendIds());
+    ASSERT_TRUE(mFeIds.size() > 0);
 
-    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,
-        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();
-}
-
-::testing::AssertionResult TunerHidlTest::broadcastDataFlowTest(
-        vector<FilterConf> filterConf, 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);
-
-    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();
-}
-
-::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");
-        return;
-    }
-
-    for (size_t i = 0; i < feIds.size(); i++) {
-        ASSERT_TRUE(createFrontend(feIds[i]));
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(openFrontend(mFeIds[i]));
+        ASSERT_TRUE(closeFrontend());
     }
 }
 
 TEST_P(TunerHidlTest, TuneFrontend) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
-
-    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");
-        return;
-    }
-
-    for (size_t i = 0; i < feIds.size(); i++) {
-        ASSERT_TRUE(tuneFrontend(feIds[i]));
+    description("Tune one Frontend with specific setting and check Lock event");
+    ASSERT_TRUE(getFrontendIds());
+    ASSERT_TRUE(mFeIds.size() > 0);
+    ALOGW("[vts] expected Frontend type is %d", frontendArray[0].type);
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+        ALOGW("[vts] Frontend type is %d", mFrontendInfo.type);
+        if (mFrontendInfo.type != frontendArray[0].type) {
+            continue;
+        }
+        ASSERT_TRUE(openFrontend(mFeIds[i]));
+        ASSERT_TRUE(setFrontendCallback());
+        ASSERT_TRUE(stopTuneFrontend());
+        ASSERT_TRUE(tuneFrontend(frontendArray[0]));
+        ASSERT_TRUE(stopTuneFrontend());
+        ASSERT_TRUE(closeFrontend());
+        break;
     }
 }
 
-TEST_P(TunerHidlTest, StopTuneFrontend) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
+TEST_P(TunerHidlTest, AutoScanFrontend) {
+    description("Run an auto frontend scan with specific setting and check lock scanMessage");
+    ASSERT_TRUE(getFrontendIds());
+    ASSERT_TRUE(mFeIds.size() > 0);
 
-    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");
-        return;
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+        if (mFrontendInfo.type != frontendArray[0].type) {
+            continue;
+        }
+        ASSERT_TRUE(openFrontend(mFeIds[i]));
+        ASSERT_TRUE(setFrontendCallback());
+        ASSERT_TRUE(stopScanFrontend());
+        ASSERT_TRUE(scanFrontend(frontendScanArray[0], FrontendScanType::SCAN_AUTO));
+        ASSERT_TRUE(stopScanFrontend());
+        ASSERT_TRUE(closeFrontend());
+        break;
     }
+}
+/*=============================== End Frontend Tests ===============================*/
 
-    for (size_t i = 0; i < feIds.size(); i++) {
-        ASSERT_TRUE(stopTuneFrontend(feIds[i]));
+/*============================ Start Demux/Filter Tests ============================*/
+TEST_P(TunerHidlTest, OpenDemuxWithFrontendDataSource) {
+    description("Open Demux with a Frontend as its data source.");
+    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 != frontendArray[0].type) {
+            continue;
+        }
+        ASSERT_TRUE(openFrontend(mFeIds[i]));
+        ASSERT_TRUE(setFrontendCallback());
+        ASSERT_TRUE(openDemux());
+        ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i]));
+        ASSERT_TRUE(closeDemux());
+        ASSERT_TRUE(closeFrontend());
+        break;
     }
 }
 
-TEST_P(TunerHidlTest, CloseFrontend) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
+TEST_P(TunerHidlTest, OpenFilterInDemux) {
+    description("Open a filter in Demux.");
+    ASSERT_TRUE(getFrontendIds());
+    ASSERT_TRUE(mFeIds.size() > 0);
 
-    description("Close Frontends");
-    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
-        status = result;
-        feIds = frontendIds;
-    });
-
-    if (feIds.size() == 0) {
-        ALOGW("[   WARN   ] Frontend isn't available");
-        return;
-    }
-
-    for (size_t i = 0; i < feIds.size(); i++) {
-        ASSERT_TRUE(closeFrontend(feIds[i]));
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+        if (mFrontendInfo.type != frontendArray[0].type) {
+            continue;
+        }
+        ASSERT_TRUE(openFrontend(mFeIds[i]));
+        ASSERT_TRUE(setFrontendCallback());
+        ASSERT_TRUE(openDemux());
+        ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i]));
+        ASSERT_TRUE(openFilterInDemux(filterArray[0].type));
+        uint32_t filterId;
+        ASSERT_TRUE(getNewlyOpenedFilterId(filterId));
+        ASSERT_TRUE(closeFilter(filterId));
+        ASSERT_TRUE(closeDemux());
+        ASSERT_TRUE(closeFrontend());
+        break;
     }
 }
 
-TEST_P(TunerHidlTest, CreateDemuxWithFrontend) {
-    Result status;
-    hidl_vec<FrontendId> feIds;
+TEST_P(TunerHidlTest, StartFilterInDemux) {
+    description("Open and start a filter in Demux.");
+    ASSERT_TRUE(getFrontendIds());
+    ASSERT_TRUE(mFeIds.size() > 0);
 
-    description("Create Demux with Frontend");
-    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
-        status = result;
-        feIds = frontendIds;
-    });
-
-    if (feIds.size() == 0) {
-        ALOGW("[   WARN   ] Frontend isn't available");
-        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();
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+        if (mFrontendInfo.type != frontendArray[0].type) {
+            continue;
+        }
+        ASSERT_TRUE(openFrontend(mFeIds[i]));
+        ASSERT_TRUE(setFrontendCallback());
+        ASSERT_TRUE(openDemux());
+        ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i]));
+        ASSERT_TRUE(openFilterInDemux(filterArray[0].type));
+        uint32_t filterId;
+        ASSERT_TRUE(getNewlyOpenedFilterId(filterId));
+        ASSERT_TRUE(configFilter(filterArray[0].setting, filterId));
+        ASSERT_TRUE(getFilterMQDescriptor(filterId));
+        ASSERT_TRUE(startFilter(filterId));
+        ASSERT_TRUE(stopFilter(filterId));
+        ASSERT_TRUE(closeFilter(filterId));
+        ASSERT_TRUE(closeDemux());
+        ASSERT_TRUE(closeFrontend());
+        break;
     }
 }
+/*============================ End Demux/Filter Tests ============================*/
 
-TEST_P(TunerHidlTest, CreateDemux) {
-    description("Create Demux");
-    ASSERT_TRUE(createDemux());
-}
-
-TEST_P(TunerHidlTest, CloseDemux) {
-    description("Close Demux");
-    ASSERT_TRUE(closeDemux());
-}
-
-TEST_P(TunerHidlTest, CreateDescrambler) {
+/*============================ Start Descrambler Tests ============================*/
+/*
+ * TODO: re-enable the tests after finalizing the test refactoring.
+ */
+/*TEST_P(TunerHidlTest, CreateDescrambler) {
     description("Create Descrambler");
     ASSERT_TRUE(createDescrambler());
 }
@@ -1357,11 +1415,44 @@
 TEST_P(TunerHidlTest, CloseDescrambler) {
     description("Close Descrambler");
     ASSERT_TRUE(closeDescrambler());
+}*/
+/*============================== End Descrambler Tests ==============================*/
+
+/*============================== Start Data Flow Tests ==============================*/
+TEST_P(TunerHidlTest, BroadcastDataFlowWithAudioFilterTest) {
+    description("Open Demux with a Frontend as its data source.");
+    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 != frontendArray[0].type) {
+            continue;
+        }
+        ASSERT_TRUE(openFrontend(mFeIds[i]));
+        ASSERT_TRUE(setFrontendCallback());
+        ASSERT_TRUE(openDemux());
+        ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i]));
+        ASSERT_TRUE(openFilterInDemux(filterArray[0].type));
+        uint32_t filterId;
+        ASSERT_TRUE(getNewlyOpenedFilterId(filterId));
+        ASSERT_TRUE(configFilter(filterArray[0].setting, filterId));
+        ASSERT_TRUE(getFilterMQDescriptor(filterId));
+        ASSERT_TRUE(startFilter(filterId));
+        // tune test
+        ASSERT_TRUE(tuneFrontend(frontendArray[0]));
+        // broadcast data flow test
+        ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles));
+        ASSERT_TRUE(stopTuneFrontend());
+        ASSERT_TRUE(stopFilter(filterId));
+        ASSERT_TRUE(closeFilter(filterId));
+        ASSERT_TRUE(closeDemux());
+        ASSERT_TRUE(closeFrontend());
+        break;
+    }
 }
 
 /*
- * DATA FLOW TESTS
- *
  * TODO: re-enable the tests after finalizing the testing stream.
  */
 /*TEST_P(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) {
@@ -1407,36 +1498,6 @@
     ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles));
 }
 
-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(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
     description("Feed ts data from frontend to recording and test with ts record filter");
 
@@ -1474,7 +1535,8 @@
 
     ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles));
 }*/
-
+/*============================== End Data Flow Tests ==============================*/
+/******************************** End Test Entry **********************************/
 }  // namespace
 
 INSTANTIATE_TEST_SUITE_P(
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..55ca857
--- /dev/null
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
@@ -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 <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 <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <fstream>
+#include <iostream>
+#include <map>
+
+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::DemuxTpid;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+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::FrontendType;
+
+namespace {
+
+#define frontend_transponders_count 1
+#define channels_count 1
+#define frontend_scan_count 1
+#define filter_count 2
+
+struct FilterConfig {
+    DemuxFilterType type;
+    DemuxFilterSettings setting;
+};
+
+struct FrontendConfig {
+    FrontendType type;
+    FrontendSettings settings;
+};
+
+struct ChannelConfig {
+    int32_t frontendId;
+    int32_t channelId;
+    std::string channelName;
+    DemuxTpid videoPid;
+    DemuxTpid audioPid;
+};
+
+static FrontendConfig frontendArray[frontend_transponders_count];
+static FrontendConfig frontendScanArray[channels_count];
+static ChannelConfig channelArray[frontend_scan_count];
+static FilterConfig filterArray[filter_count];
+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[0].type = FrontendType::DVBT, frontendArray[0].settings.dvbt(dvbtSettings);
+};
+
+/** Configuration array for the frontend scan test */
+inline void initFrontendScanConfig() {
+    frontendScanArray[0].type = FrontendType::DVBT, frontendScanArray[0].settings.dvbt({
+                                                            .frequency = 577000,
+                                                    });
+};
+
+/** Configuration array for the filter test */
+inline void initFilterConfig() {
+    // TS Video filter setting
+    filterArray[0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
+    filterArray[0].setting.ts().tpid = 49;
+    filterArray[0].setting.ts().filterSettings.av({.isPassthrough = false});
+    // TS PES filter setting
+    filterArray[1].type.mainType = DemuxFilterMainType::TS;
+    filterArray[1].type.subType.tsFilterType(DemuxTsFilterType::PES);
+    filterArray[1].setting.ts().tpid = 256;
+    filterArray[1].setting.ts().filterSettings.pesData({
+            .isRaw = true,
+            .streamId = 0xbd,
+    });
+};
+
+}  // namespace
\ No newline at end of file
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/gadget/1.1/Android.bp b/usb/gadget/1.1/Android.bp
new file mode 100644
index 0000000..b41eb9c
--- /dev/null
+++ b/usb/gadget/1.1/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.usb.gadget@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 95bb59c..bf77503 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -39,7 +39,6 @@
     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",
@@ -53,14 +52,17 @@
         "android.hardware.wifi@1.3",
         "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
+// 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: [
@@ -68,5 +70,23 @@
         "android.hardware.wifi@1.0",
         "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
+}
+
+// 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: [
+        "VtsHalWifiV1_0TargetTest.cpp",
+        "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-core"],
 }
diff --git a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
index e7b8593..128dae5 100644
--- a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
+++ b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
@@ -14,37 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
+#include <VtsHalHidlTargetTestEnvBase.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;
-}
+// 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/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..c95f4d2
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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::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 {
+        // 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..f332001 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,21 +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;
+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;
 
 extern WifiHidlEnvironment* gEnv;
 
@@ -64,16 +65,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 +121,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 +142,9 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -162,15 +152,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 +167,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 +176,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 +195,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 +208,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 +218,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 +230,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 +245,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 +262,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 +281,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 +309,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 +335,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 +349,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 +367,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 =
@@ -605,7 +399,7 @@
  * 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;
@@ -631,7 +425,7 @@
  * 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;
@@ -652,7 +446,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 +460,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 =
@@ -698,7 +492,7 @@
  * 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;
@@ -724,7 +518,7 @@
  * 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;
@@ -743,7 +537,7 @@
 /*
  * CreateRttController
  */
-TEST_F(WifiChipHidlTest, CreateRttController) {
+TEST_P(WifiChipHidlTest, CreateRttController) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     sp<IWifiStaIface> iface;
@@ -752,6 +546,16 @@
 
     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_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..26e4821 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -209,23 +209,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) {
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..8660134 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -44,8 +44,6 @@
     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 = "");
 // Configure the chip in a mode to support the creation of the provided
 // iface type.
 bool configureChipToSupportIfaceType(
@@ -61,48 +59,4 @@
         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;
-    }
 };
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..47a1938 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,12 @@
 
 #include <android-base/logging.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 +31,31 @@
 
 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);
+        // 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 +444,8 @@
       NanFollowupReceivedInd nanFollowupReceivedInd;
       NanDataPathRequestInd nanDataPathRequestInd;
       NanDataPathConfirmInd nanDataPathConfirmInd;
+
+      std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -445,9 +453,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 +462,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..1eb9c99 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,36 @@
 
 #include <android-base/logging.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 {
+        // 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 +53,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);
+    EXPECT_NE(nullptr, wifi_chip.get());
+
+    sp<IWifiStaIface> wifi_sta_iface = getWifiStaIface(instance_name);
+    EXPECT_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..7db0526 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;
     }
@@ -257,7 +263,7 @@
  * Ensures that calls to set scanning MAC OUI will return a success status
  * code.
  */
-TEST_F(WifiStaIfaceHidlTest, SetScanningMacOui) {
+TEST_P(WifiStaIfaceHidlTest, SetScanningMacOui) {
     if (!isCapabilitySupported(
             IWifiStaIface::StaIfaceCapabilityMask::SCAN_RAND)) {
         // No-op if SetScanningMacOui is not supported.
@@ -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..775031e 100644
--- a/wifi/1.1/vts/functional/Android.bp
+++ b/wifi/1.1/vts/functional/Android.bp
@@ -28,5 +28,5 @@
         "android.hardware.wifi@1.3",
         "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
index a0f97f8..4b62b15 100644
--- a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
+++ b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
@@ -14,37 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.1/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.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;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+::testing::VtsHalHidlTargetTestEnvBase* gEnv = nullptr;
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..f43e49e 100644
--- a/wifi/1.2/vts/functional/Android.bp
+++ b/wifi/1.2/vts/functional/Android.bp
@@ -30,7 +30,8 @@
         "android.hardware.wifi@1.3",
         "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    disable_framework: true,
+    test_suites: ["general-tests", "vts-core"],
 }
 
 cc_test {
@@ -47,5 +48,6 @@
         "android.hardware.wifi@1.2",
         "libwifi-system-iface"
     ],
-    test_suites: ["general-tests"],
+    disable_framework: true,
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp b/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
index c765cdc..52c7a4a 100644
--- a/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
+++ b/wifi/1.2/vts/functional/VtsHalWifiV1_2TargetTest.cpp
@@ -14,35 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.2/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.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;
-}
+// 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/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..96656f3 100644
--- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -16,10 +16,12 @@
 
 #include <android-base/logging.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 +38,22 @@
 
 #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();
+        // 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 +61,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 +439,7 @@
     // synchronization objects
     std::mutex mtx_;
     std::condition_variable cv_;
-    int count_;
+    int count_ = 0;
 
    protected:
     android::sp<::android::hardware::wifi::V1_2::IWifiNanIface> iwifiNanIface;
@@ -458,6 +463,8 @@
     ::android::hardware::wifi::V1_2::NanDataPathConfirmInd
         nanDataPathConfirmInd_1_2;
     NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd;
+
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -465,76 +472,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/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 2f21819..0000000
--- a/wifi/1.3/default/wifi.cpp
+++ /dev/null
@@ -1,216 +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";
-    }
-    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";
-    }
-    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..fe9c791 100644
--- a/wifi/1.3/vts/functional/Android.bp
+++ b/wifi/1.3/vts/functional/Android.bp
@@ -30,4 +30,6 @@
         "android.hardware.wifi@1.3",
         "libwifi-system-iface"
     ],
+    disable_framework: true,
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
index faf426e..52c7a4a 100644
--- a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
+++ b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
@@ -14,37 +14,8 @@
  * limitations under the License.
  */
 
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.3/IWifi.h>
+#include <VtsHalHidlTargetTestEnvBase.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;
-}
+// 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/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..3b94619
--- /dev/null
+++ b/wifi/1.4/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi@1.4",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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..ab76ff6
--- /dev/null
+++ b/wifi/1.4/default/Android.mk
@@ -0,0 +1,174 @@
+# 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 \
+    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-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 \
+    android.hardware.wifi@1.4
+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.3/default/android.hardware.wifi@1.0-service.rc b/wifi/1.4/default/android.hardware.wifi@1.0-service.rc
similarity index 100%
rename from wifi/1.3/default/android.hardware.wifi@1.0-service.rc
rename to wifi/1.4/default/android.hardware.wifi@1.0-service.rc
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..6cc81e4
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_iface_util.h
@@ -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.
+ */
+
+#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&));
+};
+}  // 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..6942c1e
--- /dev/null
+++ b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h
@@ -0,0 +1,68 @@
+/*
+ * 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&));
+};
+}  // 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..d35adbc
--- /dev/null
+++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
@@ -0,0 +1,875 @@
+/*
+ * 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");
+    }
+};
+
+////////// 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);
+        });
+}
+
+////////// 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..9022792
--- /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, 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..4c9fad1
--- /dev/null
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -0,0 +1,1609 @@
+/*
+ * 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_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), {}};
+    }
+    // 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<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;
+            }
+            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<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() {
+    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_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..3323ade
--- /dev/null
+++ b/wifi/1.4/default/wifi_chip.h
@@ -0,0 +1,292 @@
+/*
+ * 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.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::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..2883b46
--- /dev/null
+++ b/wifi/1.4/default/wifi_iface_util.cpp
@@ -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.
+ */
+
+#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) {
+    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_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..35edff6
--- /dev/null
+++ b/wifi/1.4/default/wifi_iface_util.h
@@ -0,0 +1,75 @@
+/*
+ * 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);
+
+   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..f596195
--- /dev/null
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -0,0 +1,1506 @@
+/*
+ * 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::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);
+}
+
+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..c21563e
--- /dev/null
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -0,0 +1,417 @@
+/*
+ * 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);
+    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);
+    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.
+    wifi_error createVirtualInterface(const std::string& ifname,
+                                      wifi_interface_type iftype);
+    wifi_error deleteVirtualInterface(const std::string& ifname);
+
+   private:
+    // Retrieve interface handles for all the available interfaces.
+    wifi_error retrieveIfaceHandles();
+    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..073101c
--- /dev/null
+++ b/wifi/1.4/default/wifi_nan_iface.cpp
@@ -0,0 +1,917 @@
+/*
+ * 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,
+    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 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..c16628b
--- /dev/null
+++ b/wifi/1.4/default/wifi_nan_iface.h
@@ -0,0 +1,185 @@
+/*
+ * 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,
+                 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_;
+    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..e2ea6e4
--- /dev/null
+++ b/wifi/1.4/default/wifi_sta_iface.cpp
@@ -0,0 +1,647 @@
+/*
+ * 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) {
+    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_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..d857be1
--- /dev/null
+++ b/wifi/1.4/vts/functional/Android.bp
@@ -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.
+//
+
+// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest.
+cc_test {
+    name: "VtsHalWifiApV1_4TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalWifiV1_4TargetTest.cpp",
+        "wifi_ap_iface_hidl_test.cpp",
+        "wifi_chip_hidl_test.cpp",
+        "wifi_nan_iface_hidl_test.cpp",
+        "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-core",
+    ],
+}
diff --git a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp
new file mode 100644
index 0000000..7e0f3cd
--- /dev/null
+++ b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp
@@ -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.
+ */
+
+#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/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..3507d30
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+extern WifiHidlEnvironment* gEnv;
+
+/**
+ * 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..1c39550
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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;
+    }
+}
+
+/*
+ * createRttController_1_4
+ * Ensures that an instance of the IWifiRttController proxy object is
+ * successfully created.
+ */
+TEST_P(WifiChipHidlTest, createRttController_1_4) {
+    configureChipForIfaceType(IfaceType::STA, true);
+
+    const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createStaIface);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface.first.code);
+    sp<IWifiStaIface> iface = IWifiStaIface::castFrom(status_and_iface.second);
+    EXPECT_NE(nullptr, iface.get());
+
+    const auto& status_and_controller =
+        HIDL_INVOKE(wifi_chip_, createRttController_1_4, iface);
+    if (status_and_controller.first.code !=
+        WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code);
+        EXPECT_NE(nullptr, status_and_controller.second.get());
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_4::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
new file mode 100644
index 0000000..24daee6
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -0,0 +1,553 @@
+/*
+ * 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 <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 {
+        // 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..726470c
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+
+#undef NAN  // NAN is defined in bionic/libc/include/math.h:38
+
+#include <android/hardware/wifi/1.3/IWifiStaIface.h>
+#include <android/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifiChip.h>
+#include <android/hardware/wifi/1.4/IWifiRttController.h>
+#include <android/hardware/wifi/1.4/IWifiRttControllerEventCallback.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::V1_0::CommandId;
+using ::android::hardware::wifi::V1_0::RttBw;
+using ::android::hardware::wifi::V1_0::RttPeerType;
+using ::android::hardware::wifi::V1_0::RttType;
+using ::android::hardware::wifi::V1_0::WifiChannelInfo;
+using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_3::IWifiStaIface;
+using ::android::hardware::wifi::V1_4::IWifiChip;
+using ::android::hardware::wifi::V1_4::IWifiRttController;
+using ::android::hardware::wifi::V1_4::IWifiRttControllerEventCallback;
+using ::android::hardware::wifi::V1_4::RttCapabilities;
+using ::android::hardware::wifi::V1_4::RttConfig;
+using ::android::hardware::wifi::V1_4::RttPreamble;
+using ::android::hardware::wifi::V1_4::RttResponder;
+using ::android::hardware::wifi::V1_4::RttResult;
+
+/**
+ * Fixture to use for all RTT controller HIDL interface tests.
+ */
+class WifiRttControllerHidlTest : public ::testing::TestWithParam<std::string> {
+   public:
+    virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_rtt_controller_ = getWifiRttController();
+        ASSERT_NE(nullptr, wifi_rtt_controller_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+    // A simple test implementation of WifiChipEventCallback.
+    class WifiRttControllerEventCallback
+        : public ::testing::VtsHalHidlTargetCallbackBase<
+              WifiRttControllerHidlTest>,
+          public IWifiRttControllerEventCallback {
+       public:
+        WifiRttControllerEventCallback(){};
+
+        virtual ~WifiRttControllerEventCallback() = default;
+
+        Return<void> onResults(
+            CommandId cmdId __unused,
+            const hidl_vec<::android::hardware::wifi::V1_0::RttResult>& results
+                __unused) {
+            return Void();
+        };
+
+        Return<void> onResults_1_4(CommandId cmdId __unused,
+                                   const hidl_vec<RttResult>& results
+                                       __unused) {
+            return Void();
+        };
+    };
+
+   protected:
+    sp<IWifiRttController> wifi_rtt_controller_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
+
+    sp<IWifiRttController> getWifiRttController() {
+        const std::string& instance_name = GetInstanceName();
+
+        sp<IWifiChip> wifi_chip =
+            IWifiChip::castFrom(getWifiChip(instance_name));
+        EXPECT_NE(nullptr, wifi_chip.get());
+
+        sp<IWifiStaIface> wifi_sta_iface =
+            IWifiStaIface::castFrom(getWifiStaIface(instance_name));
+        EXPECT_NE(nullptr, wifi_sta_iface.get());
+
+        const auto& status_and_controller =
+            HIDL_INVOKE(wifi_chip, createRttController_1_4, wifi_sta_iface);
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code);
+        EXPECT_NE(nullptr, status_and_controller.second.get());
+
+        return status_and_controller.second.get();
+    }
+};
+
+/*
+ * registerEventCallback_1_4
+ * This test case tests the registerEventCallback_1_4() API which registers
+ * a call back function with the hal implementation
+ *
+ * Note: it is not feasible to test the invocation of the call back function
+ * since event is triggered internally in the HAL implementation, and can not be
+ * triggered from the test case
+ */
+TEST_P(WifiRttControllerHidlTest, RegisterEventCallback_1_4) {
+    sp<WifiRttControllerEventCallback> wifiRttControllerEventCallback =
+        new WifiRttControllerEventCallback();
+    const auto& status =
+        HIDL_INVOKE(wifi_rtt_controller_, registerEventCallback_1_4,
+                    wifiRttControllerEventCallback);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+
+/*
+ * rangeRequest_1_4
+ */
+TEST_P(WifiRttControllerHidlTest, RangeRequest_1_4) {
+    std::vector<RttConfig> configs;
+    RttConfig config;
+    int cmdId = 55;
+    // Set the config with test data
+    for (int i = 0; i < 6; i++) {
+        config.addr[i] = i;
+    }
+    config.type = RttType::ONE_SIDED;
+    config.peer = RttPeerType::STA;
+    config.channel.width = WifiChannelWidthInMhz::WIDTH_80;
+    config.channel.centerFreq = 5765;
+    config.channel.centerFreq0 = 5775;
+    config.channel.centerFreq1 = 0;
+    config.bw = RttBw::BW_80MHZ;
+    config.preamble = RttPreamble::HE;
+    config.mustRequestLci = false;
+    config.mustRequestLcr = false;
+    config.burstPeriod = 0;
+    config.numBurst = 0;
+    config.numFramesPerBurst = 8;
+    config.numRetriesPerRttFrame = 3;
+    config.numRetriesPerFtmr = 3;
+    config.burstDuration = 9;
+    // Insert config in the vector
+    configs.push_back(config);
+
+    // Invoke the call
+    const auto& status =
+        HIDL_INVOKE(wifi_rtt_controller_, rangeRequest_1_4, cmdId, configs);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+
+/*
+ * getCapabilities_1_4
+ */
+TEST_P(WifiRttControllerHidlTest, GetCapabilities_1_4) {
+    std::pair<WifiStatus, RttCapabilities> status_and_caps;
+
+    // Invoke the call
+    status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_4);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+}
+
+/*
+ * getResponderInfo_1_4
+ */
+TEST_P(WifiRttControllerHidlTest, GetResponderInfo_1_4) {
+    std::pair<WifiStatus, RttResponder> status_and_info;
+
+    // Invoke the call
+    status_and_info = HIDL_INVOKE(wifi_rtt_controller_, getResponderInfo_1_4);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_info.first.code);
+}
+
+/*
+ * enableResponder_1_4
+ */
+TEST_P(WifiRttControllerHidlTest, EnableResponder_1_4) {
+    std::pair<WifiStatus, RttResponder> status_and_info;
+    int cmdId = 55;
+    WifiChannelInfo channelInfo;
+    channelInfo.width = WifiChannelWidthInMhz::WIDTH_80;
+    channelInfo.centerFreq = 5690;
+    channelInfo.centerFreq0 = 5690;
+    channelInfo.centerFreq1 = 0;
+
+    // Get the responder first
+    status_and_info = HIDL_INVOKE(wifi_rtt_controller_, getResponderInfo_1_4);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_info.first.code);
+
+    // Invoke the call
+    const auto& status =
+        HIDL_INVOKE(wifi_rtt_controller_, enableResponder_1_4, cmdId,
+                    channelInfo, 10, status_and_info.second);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiRttControllerHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_4::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
diff --git a/wifi/hostapd/1.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..3dcad71
--- /dev/null
+++ b/wifi/hostapd/1.2/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi.hostapd@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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..50cfdee
--- /dev/null
+++ b/wifi/hostapd/1.2/vts/functional/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_test {
+    name: "VtsHalWifiHostapdV1_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalWifiHostapdV1_2TargetTest.cpp",
+        "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-core"],
+}
+
diff --git a/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp b/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp
new file mode 100644
index 0000000..7e0f3cd
--- /dev/null
+++ b/wifi/hostapd/1.2/vts/functional/VtsHalWifiHostapdV1_2TargetTest.cpp
@@ -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.
+ */
+
+#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.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 332ee4a..8013906 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -46,6 +46,8 @@
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi.supplicant@1.1",
+        "android.hardware.wifi.supplicant@1.2",
+        "android.hardware.wifi.supplicant@1.3",
         "android.hardware.wifi@1.0",
         "libgmock",
         "libwifi-system",
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index d47e42f..d0df4a4 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
@@ -57,6 +57,11 @@
 // 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) {
+    // Skip if wifi instance is not set.
+    if (wifi_instance_name == "") {
+        return;
+    }
+
     sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
     ChipModeId mode_id;
     EXPECT_TRUE(configureChipToSupportIfaceType(
@@ -66,6 +71,11 @@
 // Helper function to deinitialize the driver and firmware
 // using the vendor HAL HIDL interface.
 void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) {
+    // Skip if wifi instance is not set.
+    if (wifi_instance_name == "") {
+        return;
+    }
+
     stopWifi(wifi_instance_name);
 }
 
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..6bcfa8a 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",
@@ -54,5 +54,8 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
index 9063a3b..f582cc1 100644
--- a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
+++ b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
@@ -14,45 +14,8 @@
  * 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;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
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..22dec84 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",
@@ -51,20 +51,24 @@
         "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-core",
+    ],
 }
 
 cc_test {
     name: "VtsHalWifiSupplicantP2pV1_2TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiSupplicantV1_2TargetTest.cpp",
+        "VtsHalWifiSupplicantP2pV1_2TargetTest.cpp",
         "supplicant_p2p_iface_hidl_test.cpp",
     ],
     static_libs: [
@@ -81,5 +85,8 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
-
diff --git a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp
new file mode 100644
index 0000000..22bf1db
--- /dev/null
+++ b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantP2pV1_2TargetTest.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsCoreUtil.h>
+#include "supplicant_hidl_test_utils.h"
+
+// TODO(b/143892896): Remove this line after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
+
+int main(int argc, char** argv) {
+    if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct"))
+        return 0;
+
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp
index 267fa67..9dbeee1 100644
--- a/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp
+++ b/wifi/supplicant/1.2/vts/functional/VtsHalWifiSupplicantV1_2TargetTest.cpp
@@ -14,47 +14,8 @@
  * 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;
-}
+// TODO(b/143892896): Remove this file after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
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..480929a 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
@@ -26,18 +26,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..2b63ad0 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
@@ -18,7 +18,11 @@
 
 #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 +30,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 +40,15 @@
 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_));
+        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 +57,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 +76,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 +95,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 +114,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 +137,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 +160,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..f38dda4 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -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()) {
@@ -310,7 +325,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,6 +333,19 @@
         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"
         "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
@@ -361,7 +389,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,6 +397,21 @@
         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"
         "0DAQcDIgAD0edY4X3N//HhMFYsZfMbQJTiNFtNIWF/cIwMB/gzqOM=;;";
@@ -413,3 +456,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..15c72fe
--- /dev/null
+++ b/wifi/supplicant/1.3/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi.supplicant@1.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    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..3dabe7c
--- /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: [
+        "VtsHalWifiSupplicantV1_3TargetTest.cpp",
+        "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-core",
+    ],
+}
diff --git a/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp
new file mode 100644
index 0000000..9dbeee1
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp
@@ -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.
+ */
+
+#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.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..dbf2b91
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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 <VtsHalHidlTargetTestBase.h>
+#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..3754520
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -0,0 +1,581 @@
+/*
+ * 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");
+
+        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;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;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..9c40de1
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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");
+        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);
+            });
+    }
+}
+/*
+ * 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<>);