[automerger skipped] Merge "Stop location to avoid timing issue" am: 0291d3fcd3 am: bbc5a01d1b am: 9d27cbbd34 -s ours
am skip reason: Change-Id I04894426e8384d25f2b5e269961a9cf051cab40f with SHA-1 b983f10362 is in history

Change-Id: I4435123b979c1590ebbeedb779a859ba4d33efd6
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/IDevice.hal b/audio/6.0/IDevice.hal
index 122c550..c2e310c 100644
--- a/audio/6.0/IDevice.hal
+++ b/audio/6.0/IDevice.hal
@@ -168,6 +168,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.
@@ -295,4 +314,28 @@
      */
     @exit
     close() generates (Result retval);
+
+    /**
+     * Applies an audio effect to an audio device.
+     *
+     * @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
+     *                patch connecting that device was created.
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect to add.
+     * @return retval operation completion status.
+     */
+    addDeviceEffect(AudioPortHandle device, uint64_t effectId) generates (Result retval);
+
+    /**
+     * Stops applying an audio effect to an audio device.
+     *
+     * @param device identifies the sink or source device this effect was applied to.
+     *               "device" is the AudioPortHandle indicated for the device when the audio
+     *               patch is created at the audio HAL.
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect.
+     * @return retval operation completion status.
+     */
+    removeDeviceEffect(AudioPortHandle device, uint64_t effectId) generates (Result retval);
 };
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/config/api/current.txt b/audio/6.0/config/api/current.txt
index 431bc90..ddd4d1c 100644
--- a/audio/6.0/config/api/current.txt
+++ b/audio/6.0/config/api/current.txt
@@ -252,7 +252,9 @@
 
   public class GlobalConfiguration {
     ctor public GlobalConfiguration();
+    method public boolean getCall_screen_mode_supported();
     method public boolean getSpeaker_drc_enabled();
+    method public void setCall_screen_mode_supported(boolean);
     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 d0f80ea..3fab7dc 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:complexType>
     <xs:complexType name="modules">
         <xs:annotation>
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 132f86d..e69d969 100644
--- a/audio/common/6.0/types.hal
+++ b/audio/common/6.0/types.hal
@@ -156,6 +156,11 @@
 @export(name="audio_session_t", value_prefix="AUDIO_SESSION_")
 enum AudioSessionConsts : int32_t {
     /**
+     * Session for effects attached to a particular sink or source audio device
+     * (e.g an effect only applied to a speaker)
+     */
+    DEVICE = -2,
+    /**
      * Session for effects attached to a particular output stream
      * (value must be less than 0)
      */
@@ -556,6 +561,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_")
@@ -732,6 +739,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_")
@@ -752,6 +760,7 @@
     GAME                               = 14,
     VIRTUAL_SOURCE                     = 15,
     ASSISTANT                          = 16,
+    CALL_ASSISTANT                     = 17,
 };
 
 /** Type of audio generated by an application. */
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
index 4565730..f58a599 100644
--- a/audio/common/all-versions/default/service/Android.bp
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -41,6 +41,7 @@
         "android.hardware.soundtrigger@2.0",
         "android.hardware.soundtrigger@2.1",
         "android.hardware.soundtrigger@2.2",
+        "android.hardware.soundtrigger@2.3",
     ],
 }
 
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 2730f3b..00bcb19 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -29,6 +29,7 @@
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.3/ISoundTriggerHw.h>
 #include <binder/ProcessState.h>
 #include <cutils/properties.h>
 #include <hidl/HidlTransportSupport.h>
@@ -78,9 +79,9 @@
                         "Could not register audio effect API");
     // clang-format on
 
-    ALOGW_IF((registerPassthroughServiceImplementations<soundtrigger::V2_2::ISoundTriggerHw,
-                                                        soundtrigger::V2_1::ISoundTriggerHw,
-                                                        soundtrigger::V2_0::ISoundTriggerHw>()),
+    ALOGW_IF((registerPassthroughServiceImplementations<
+                     soundtrigger::V2_3::ISoundTriggerHw, soundtrigger::V2_2::ISoundTriggerHw,
+                     soundtrigger::V2_1::ISoundTriggerHw, soundtrigger::V2_0::ISoundTriggerHw>()),
              "Could not register soundtrigger API");
 
     ALOGW_IF(registerPassthroughServiceImplementations<
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 c6c9464..47e31c1 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -18,6 +18,7 @@
 
 #include "core/default/Device.h"
 #include <HidlUtils.h>
+#include "common/all-versions/default/EffectMap.h"
 #include "core/default/Conversions.h"
 #include "core/default/StreamIn.h"
 #include "core/default/StreamOut.h"
@@ -25,6 +26,7 @@
 
 //#define LOG_NDEBUG 0
 
+#include <inttypes.h>
 #include <memory.h>
 #include <string.h>
 #include <algorithm>
@@ -267,12 +269,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));
@@ -280,8 +291,7 @@
             patch = static_cast<AudioPatchHandle>(halPatch);
         }
     }
-    _hidl_cb(retval, patch);
-    return Void();
+    return {retval, patch};
 }
 
 Return<Result> Device::releaseAudioPatch(int32_t patch) {
@@ -403,6 +413,52 @@
 Return<Result> Device::close() {
     return doClose();
 }
+
+Return<Result> Device::addDeviceEffect(AudioPortHandle device, uint64_t effectId) {
+    if (version() < AUDIO_DEVICE_API_VERSION_3_1 || mDevice->add_device_effect == nullptr) {
+        return Result::NOT_SUPPORTED;
+    }
+
+    effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
+    if (halEffect != NULL) {
+        return analyzeStatus("add_device_effect",
+                             mDevice->add_device_effect(
+                                     mDevice, static_cast<audio_port_handle_t>(device), halEffect));
+    } else {
+        ALOGW("%s Invalid effect ID passed from client: %" PRIu64 "", __func__, effectId);
+        return Result::INVALID_ARGUMENTS;
+    }
+}
+
+Return<Result> Device::removeDeviceEffect(AudioPortHandle device, uint64_t effectId) {
+    if (version() < AUDIO_DEVICE_API_VERSION_3_1 || mDevice->remove_device_effect == nullptr) {
+        return Result::NOT_SUPPORTED;
+    }
+
+    effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
+    if (halEffect != NULL) {
+        return analyzeStatus("remove_device_effect",
+                             mDevice->remove_device_effect(
+                                     mDevice, static_cast<audio_port_handle_t>(device), halEffect));
+    } else {
+        ALOGW("%s Invalid effect ID passed from client: %" PRIu64 "", __func__, effectId);
+        return Result::INVALID_ARGUMENTS;
+    }
+}
+
+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 3cf0932..679f85d 100644
--- a/audio/core/all-versions/default/PrimaryDevice.cpp
+++ b/audio/core/all-versions/default/PrimaryDevice.cpp
@@ -168,6 +168,21 @@
 Return<Result> PrimaryDevice::close() {
     return mDevice->close();
 }
+
+Return<Result> PrimaryDevice::addDeviceEffect(AudioPortHandle device, uint64_t effectId) {
+    return mDevice->addDeviceEffect(device, effectId);
+}
+
+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.
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 11ab607..b0e72d9 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -116,8 +116,12 @@
 #endif
 #if MAJOR_VERSION >= 6
     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;
 
     // Utility methods for extending interfaces.
@@ -135,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 f5f3848..ccdb7b2 100644
--- a/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
+++ b/audio/core/all-versions/default/include/core/default/PrimaryDevice.h
@@ -98,6 +98,11 @@
 #endif
 #if MAJOR_VERSION >= 6
     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/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
index 2afbbb8..09ef330 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,12 @@
     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);
+}
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 73af7f4..1818e36 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/effect/6.0/IEffectsFactory.hal b/audio/effect/6.0/IEffectsFactory.hal
index e08b2de..4c37bad 100644
--- a/audio/effect/6.0/IEffectsFactory.hal
+++ b/audio/effect/6.0/IEffectsFactory.hal
@@ -48,11 +48,15 @@
      *                stream.
      * @param ioHandle identifies the output or input stream this effect is
      *                 directed to in audio HAL.
+     * @param device identifies the sink or source device this effect is directed to in the
+     *               audio HAL. Must be specified if session is AudioSessionConsts.DEVICE.
+     *               "device" is the AudioPortHandle used for the device when the audio
+     *               patch is created at the audio HAL.
      * @return retval operation completion status.
      * @return result the interface for the created effect.
      * @return effectId the unique ID of the effect to be used with
      *                  IStream::addEffect and IStream::removeEffect methods.
      */
-    createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle)
+    createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle, AudioPortHandle device)
         generates (Result retval, IEffect result, uint64_t effectId);
 };
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/effect/all-versions/default/EffectsFactory.cpp b/audio/effect/all-versions/default/EffectsFactory.cpp
index 6283e7b..acce7de 100644
--- a/audio/effect/all-versions/default/EffectsFactory.cpp
+++ b/audio/effect/all-versions/default/EffectsFactory.cpp
@@ -133,9 +133,9 @@
     return Void();
 }
 
-Return<void> EffectsFactory::getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) {
+Return<void> EffectsFactory::getDescriptor(const Uuid& uuid, getDescriptor_cb _hidl_cb) {
     effect_uuid_t halUuid;
-    HidlUtils::uuidToHal(uid, &halUuid);
+    HidlUtils::uuidToHal(uuid, &halUuid);
     effect_descriptor_t halDescriptor;
     status_t status = EffectGetDescriptor(&halUuid, &halDescriptor);
     EffectDescriptor descriptor;
@@ -154,13 +154,31 @@
     return Void();
 }
 
-Return<void> EffectsFactory::createEffect(const Uuid& uid, int32_t session, int32_t ioHandle,
-                                          createEffect_cb _hidl_cb) {
+#if MAJOR_VERSION <= 5
+Return<void> EffectsFactory::createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle,
+                                          EffectsFactory::createEffect_cb _hidl_cb) {
+    return createEffectImpl(uuid, session, ioHandle, AUDIO_PORT_HANDLE_NONE, _hidl_cb);
+}
+#else
+Return<void> EffectsFactory::createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle,
+                                          int32_t device,
+                                          EffectsFactory::createEffect_cb _hidl_cb) {
+    return createEffectImpl(uuid, session, ioHandle, device, _hidl_cb);
+}
+#endif
+
+Return<void> EffectsFactory::createEffectImpl(const Uuid& uuid, int32_t session, int32_t ioHandle,
+                                              int32_t device, createEffect_cb _hidl_cb) {
     effect_uuid_t halUuid;
-    HidlUtils::uuidToHal(uid, &halUuid);
+    HidlUtils::uuidToHal(uuid, &halUuid);
     effect_handle_t handle;
     Result retval(Result::OK);
-    status_t status = EffectCreate(&halUuid, session, ioHandle, &handle);
+    status_t status;
+    if (session == AUDIO_SESSION_DEVICE) {
+        status = EffectCreateOnDevice(&halUuid, device, ioHandle, &handle);
+    } else {
+        status = EffectCreate(&halUuid, session, ioHandle, &handle);
+    }
     sp<IEffect> effect;
     uint64_t effectId = EffectMap::INVALID_ID;
     if (status == OK) {
diff --git a/audio/effect/all-versions/default/EffectsFactory.h b/audio/effect/all-versions/default/EffectsFactory.h
index f0d09ec..0b86836 100644
--- a/audio/effect/all-versions/default/EffectsFactory.h
+++ b/audio/effect/all-versions/default/EffectsFactory.h
@@ -47,9 +47,15 @@
 struct EffectsFactory : public IEffectsFactory {
     // Methods from ::android::hardware::audio::effect::CPP_VERSION::IEffectsFactory follow.
     Return<void> getAllDescriptors(getAllDescriptors_cb _hidl_cb) override;
-    Return<void> getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) override;
-    Return<void> createEffect(const Uuid& uid, int32_t session, int32_t ioHandle,
+    Return<void> getDescriptor(const Uuid& uuid, getDescriptor_cb _hidl_cb) override;
+#if MAJOR_VERSION <= 5
+    Return<void> createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle,
                               createEffect_cb _hidl_cb) override;
+#else
+    Return<void> createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle, int32_t device,
+                              createEffect_cb _hidl_cb) override;
+#endif
+
     Return<void> debugDump(
         const hidl_handle& fd);  //< in CPP_VERSION::IEffectsFactory only, alias of debug
     Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
@@ -57,6 +63,8 @@
    private:
     static sp<IEffect> dispatchEffectInstanceCreation(const effect_descriptor_t& halDescriptor,
                                                       effect_handle_t handle);
+    Return<void> createEffectImpl(const Uuid& uuid, int32_t session, int32_t ioHandle,
+                                  int32_t device, createEffect_cb _hidl_cb);
 };
 
 extern "C" IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name);
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index 3c712b5..c151d3a 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -134,13 +134,16 @@
     Result retval = Result::NOT_INITIALIZED;
     sp<IEffect> effect;
     ret = effectsFactory->createEffect(
-        effectUuid, 1 /*session*/, 1 /*ioHandle*/,
-        [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
-            retval = r;
-            if (r == Result::OK) {
-                effect = result;
-            }
-        });
+            effectUuid, 1 /*session*/, 1 /*ioHandle*/,
+#if MAJOR_VERSION >= 6
+            0 /*device*/,
+#endif
+            [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
+                retval = r;
+                if (r == Result::OK) {
+                    effect = result;
+                }
+            });
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, retval);
     EXPECT_NE(nullptr, effect.get());
@@ -236,12 +239,15 @@
     Uuid effectUuid;
     findEffectInstance(type, &effectUuid);
     Return<void> ret = effectsFactory->createEffect(
-        effectUuid, 1 /*session*/, 1 /*ioHandle*/,
-        [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
-            if (r == Result::OK) {
-                effect = result;
-            }
-        });
+            effectUuid, 1 /*session*/, 1 /*ioHandle*/,
+#if MAJOR_VERSION >= 6
+            0 /*device*/,
+#endif
+            [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
+                if (r == Result::OK) {
+                    effect = result;
+                }
+            });
     ASSERT_TRUE(ret.isOk());
 }
 
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..3d04c89 100644
--- a/automotive/audiocontrol/1.0/default/Android.bp
+++ b/automotive/audiocontrol/1.0/default/Android.bp
@@ -29,7 +29,7 @@
         "liblog",
         "libutils",
     ],
-
+    vintf_fragments: ["audiocontrol_manifest.xml"],
     cflags: [
         "-DLOG_TAG=\"AudCntrlDrv\"",
         "-O0",
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/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..2c7494a
--- /dev/null
+++ b/automotive/can/1.0/ICanController.hal
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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, a mean to express the domain of device address.
+     */
+    enum InterfaceType : uint8_t {
+        /**
+         * Virtual SocketCAN interface.
+         *
+         * The address is an interface name, such as vcan0. If the interface
+         * doesn't exist, HAL server must create it.
+         *
+         * Valid InterfaceIdentifier types:
+         *  - address.
+         */
+        VIRTUAL,
+
+        /**
+         * Native SocketCAN interface.
+         *
+         * The address is an interface name, such as can0.
+         *
+         * Valid InterfaceIdentifier types:
+         *  - address;
+         *  - serialno.
+         */
+        SOCKETCAN,
+
+        /**
+         * Serial-based interface.
+         *
+         * The address is a patch to a device, such as /dev/ttyUSB0.
+         *
+         * Valid InterfaceIdentifier types:
+         *  - address;
+         *  - serialno.
+         */
+        SLCAN,
+
+        /**
+         * Proprietary interface, specific to the hardware system Android
+         * is running on. Instead of using address field, the interface is
+         * addressed with 0-based index.
+         *
+         * Valid InterfaceIdentifier types:
+         *  - index
+         */
+        INDEXED
+    };
+
+    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 address (interface name, device path) doesn't exist or there
+         * is no device with a given serial no.
+         */
+        BAD_ADDRESS,
+
+        /** Provided baud rate is not supported by the hardware. */
+        BAD_BAUDRATE,
+    };
+
+    /**
+     * Configuration of the (physical or virtual) CAN bus.
+     *
+     * ISO TP and CAN FD are currently not supported.
+     */
+    struct BusConfiguration {
+        /**
+         * 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.
+         */
+        string name;
+
+        /**
+         * Type of the hardware (or virtual) CAN interface.
+         */
+        InterfaceType iftype;
+
+        /**
+         * Identification of hardware interface to configure.
+         */
+        safe_union InterfaceIdentifier {
+            /**
+             * Interface name or other mean of identification of the specific
+             * interface port. Syntax depends on {@see iftype}, for details
+             * {@see InterfaceType}.
+             */
+            string address;
+
+            /**
+             * Numerical identifier of interface, used for InterfaceType#INDEXED.
+             */
+            uint8_t index;
+
+            /**
+             * Alternatively to providing {@see address}, one may provide a list
+             * of interface serial number suffixes. If there happens to be
+             * a device (like USB2CAN) with a matching serial number suffix,
+             * it gets selected.
+             *
+             * 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;
+        } interfaceId;
+
+        /**
+         * Baud rate for CAN communication.
+         *
+         * Typical baud rates are: 100000, 125000, 250000, 500000.
+         *
+         * For virtual interfaces this value is ignored.
+         */
+        uint32_t baudrate;
+    };
+
+    /**
+     * 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(BusConfiguration 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 BusConfiguration#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..86df5dc
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace 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;
+    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_ADDRESS;
+    }
+
+    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::REQUIRE) return flag;
+    if (filterFlag == FilterFlag::EXCLUDE) 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 isExtendedId,
+                  bool isRtr) {
+    if (filter.size() == 0) return true;
+
+    bool anyNonInvertedPresent = false;
+    bool anyNonInvertedSatisfied = false;
+    for (auto& rule : filter) {
+        const bool satisfied = ((id & rule.mask) == rule.id) == !rule.inverted &&
+                               satisfiesFilterFlag(rule.rtr, isRtr) &&
+                               satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
+        if (rule.inverted) {
+            // Any inverted (blacklist) rule not being satisfied invalidates the whole filter set.
+            if (!satisfied) return false;
+        } else {
+            anyNonInvertedPresent = true;
+            if (satisfied) anyNonInvertedSatisfied = true;
+        }
+    }
+    return !anyNonInvertedPresent || anyNonInvertedSatisfied;
+}
+
+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 implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h
new file mode 100644
index 0000000..da3fc5a
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.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.
+ */
+
+#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 {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace 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 implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanBusNative.cpp b/automotive/can/1.0/default/CanBusNative.cpp
new file mode 100644
index 0000000..365b749
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusNative.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 "CanBusNative.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+CanBusNative::CanBusNative(const std::string& ifname, uint32_t baudrate)
+    : CanBus(ifname), mBaudrate(baudrate) {}
+
+ICanController::Result CanBusNative::preUp() {
+    if (!netdevice::exists(mIfname)) {
+        LOG(ERROR) << "Interface " << mIfname << " doesn't exist";
+        return ICanController::Result::BAD_ADDRESS;
+    }
+
+    if (!netdevice::down(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    if (!netdevice::can::setBitrate(mIfname, mBaudrate)) {
+        LOG(ERROR) << "Can't set bitrate " << mBaudrate << " for " << mIfname;
+        return ICanController::Result::BAD_BAUDRATE;
+    }
+
+    return ICanController::Result::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.3/default/wifi_legacy_hal_stubs.h b/automotive/can/1.0/default/CanBusNative.h
similarity index 62%
copy from wifi/1.3/default/wifi_legacy_hal_stubs.h
copy to automotive/can/1.0/default/CanBusNative.h
index 64854e0..126f1cb 100644
--- a/wifi/1.3/default/wifi_legacy_hal_stubs.h
+++ b/automotive/can/1.0/default/CanBusNative.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,23 +14,30 @@
  * limitations under the License.
  */
 
-#ifndef WIFI_LEGACY_HAL_STUBS_H_
-#define WIFI_LEGACY_HAL_STUBS_H_
+#pragma once
+
+#include "CanBus.h"
 
 namespace android {
 namespace hardware {
-namespace wifi {
-namespace V1_3 {
+namespace automotive {
+namespace can {
+namespace V1_0 {
 namespace implementation {
-namespace legacy_hal {
-#include <hardware_legacy/wifi_hal.h>
 
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
-}  // namespace legacy_hal
+struct CanBusNative : public CanBus {
+    CanBusNative(const std::string& ifname, uint32_t baudrate);
+
+  protected:
+    virtual ICanController::Result preUp() override;
+
+  private:
+    const uint32_t mBaudrate;
+};
+
 }  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
 }  // namespace hardware
 }  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp
new file mode 100644
index 0000000..7dce838
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace 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) {}
+
+ICanController::Result CanBusSlcan::preUp() {
+    // verify valid bitrate and translate to serial command format
+    const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate);
+    if (lookupIt == slcanprotocol::kBitrateCommands.end()) {
+        return ICanController::Result::BAD_BAUDRATE;
+    }
+    const auto 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_ADDRESS;
+    }
+
+    // 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;
+    }
+
+    // get the name of the device we created
+    struct ifreq ifrequest = {};
+    if (ioctl(mFd.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;
+}
+
+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 implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanBusSlcan.h b/automotive/can/1.0/default/CanBusSlcan.h
new file mode 100644
index 0000000..2713da8
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.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 <linux/serial.h>
+#include <linux/tty.h>
+#include <net/if.h>
+#include <termios.h>
+#include "CanBus.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+struct CanBusSlcan : public CanBus {
+    CanBusSlcan(const std::string& uartName, uint32_t bitrate);
+
+  protected:
+    virtual ICanController::Result preUp() override;
+    virtual bool postDown() override;
+
+  private:
+    const std::string mUartName;
+    const uint32_t kBitrate;
+    base::unique_fd mFd;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanBusVirtual.cpp b/automotive/can/1.0/default/CanBusVirtual.cpp
new file mode 100644
index 0000000..cc59fa9
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusVirtual.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace 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 implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.3/default/wifi_legacy_hal_stubs.h b/automotive/can/1.0/default/CanBusVirtual.h
similarity index 61%
copy from wifi/1.3/default/wifi_legacy_hal_stubs.h
copy to automotive/can/1.0/default/CanBusVirtual.h
index 64854e0..c2d5794 100644
--- a/wifi/1.3/default/wifi_legacy_hal_stubs.h
+++ b/automotive/can/1.0/default/CanBusVirtual.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,23 +14,31 @@
  * limitations under the License.
  */
 
-#ifndef WIFI_LEGACY_HAL_STUBS_H_
-#define WIFI_LEGACY_HAL_STUBS_H_
+#pragma once
+
+#include "CanBus.h"
 
 namespace android {
 namespace hardware {
-namespace wifi {
-namespace V1_3 {
+namespace automotive {
+namespace can {
+namespace V1_0 {
 namespace implementation {
-namespace legacy_hal {
-#include <hardware_legacy/wifi_hal.h>
 
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
-}  // namespace legacy_hal
+struct CanBusVirtual : public CanBus {
+    CanBusVirtual(const std::string& ifname);
+
+  protected:
+    virtual ICanController::Result preUp() override;
+    virtual bool postDown() override;
+
+  private:
+    bool mWasCreated = false;
+};
+
 }  // namespace implementation
-}  // namespace V1_3
-}  // namespace wifi
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
 }  // namespace hardware
 }  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp
new file mode 100644
index 0000000..ffdc912
--- /dev/null
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::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::BusConfiguration& config) {
+    LOG(VERBOSE) << "Attempting to bring interface up: " << toString(config);
+
+    std::lock_guard<std::mutex> lck(mCanBusesGuard);
+
+    if (!isValidName(config.name)) {
+        LOG(ERROR) << "Bus name " << config.name << " is invalid";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    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.iftype == ICanController::InterfaceType::SOCKETCAN) {
+        // TODO(b/135918744): support serialno
+        if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
+            busService = new CanBusNative(config.interfaceId.address(), config.baudrate);
+        } else {
+            return ICanController::Result::BAD_ADDRESS;
+        }
+    } else if (config.iftype == ICanController::InterfaceType::VIRTUAL) {
+        if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
+            busService = new CanBusVirtual(config.interfaceId.address());
+        } else {
+            return ICanController::Result::BAD_ADDRESS;
+        }
+    } else if (config.iftype == ICanController::InterfaceType::SLCAN) {
+        if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
+            busService = new CanBusSlcan(config.interfaceId.address(), config.baudrate);
+        } else {
+            return ICanController::Result::BAD_ADDRESS;
+        }
+    } 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::UNKNOWN_ERROR;
+    }
+
+    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 implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanController.h b/automotive/can/1.0/default/CanController.h
new file mode 100644
index 0000000..0674d0e
--- /dev/null
+++ b/automotive/can/1.0/default/CanController.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 "CanBus.h"
+
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+struct CanController : public ICanController {
+    Return<void> getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) override;
+
+    Return<ICanController::Result> upInterface(
+            const ICanController::BusConfiguration& 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 implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp
new file mode 100644
index 0000000..86e12d1
--- /dev/null
+++ b/automotive/can/1.0/default/CanSocket.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace 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 implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h
new file mode 100644
index 0000000..c98330b
--- /dev/null
+++ b/automotive/can/1.0/default/CanSocket.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace 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 implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_iface_util.cpp b/automotive/can/1.0/default/CloseHandle.cpp
similarity index 61%
copy from wifi/1.3/default/tests/mock_wifi_iface_util.cpp
copy to automotive/can/1.0/default/CloseHandle.cpp
index 3d877c0..aba2c49 100644
--- a/wifi/1.3/default/tests/mock_wifi_iface_util.cpp
+++ b/automotive/can/1.0/default/CloseHandle.cpp
@@ -14,26 +14,32 @@
  * 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"
+#include "CloseHandle.h"
 
 namespace android {
 namespace hardware {
-namespace wifi {
-namespace V1_3 {
+namespace automotive {
+namespace can {
+namespace V1_0 {
 namespace implementation {
-namespace iface_util {
 
-MockWifiIfaceUtil::MockWifiIfaceUtil(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : WifiIfaceUtil(iface_tool) {}
-}  // namespace iface_util
+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 implementation
-}  // namespace V1_3
-}  // namespace wifi
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
 }  // namespace hardware
 }  // namespace android
diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h
new file mode 100644
index 0000000..eade109
--- /dev/null
+++ b/automotive/can/1.0/default/CloseHandle.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android/hardware/automotive/can/1.0/ICloseHandle.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace 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 implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
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..9845bc7
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NetlinkRequest.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace netdevice {
+namespace 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 impl
+}  // namespace netdevice
+}  // namespace android
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..ba9b65b
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <linux/rtnetlink.h>
+
+#include <string>
+
+namespace android {
+namespace 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 netdevice
+}  // namespace android
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..0514764
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+namespace 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 netdevice
+}  // namespace android
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..90e1f3f
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
@@ -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.
+ */
+
+#pragma once
+
+#include "NetlinkRequest.h"
+
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+
+#include <linux/netlink.h>
+
+namespace android {
+namespace 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 netdevice
+}  // namespace android
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..6452d9b
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+namespace netdevice {
+namespace 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 can
+}  // namespace netdevice
+}  // namespace android
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..3deac3e
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -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.
+ */
+
+#include "common.h"
+
+#include <android-base/logging.h>
+
+#include <net/if.h>
+
+namespace android {
+namespace 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 netdevice
+}  // namespace android
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..9bdff4d
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/common.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 <string>
+
+namespace android {
+namespace 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 netdevice
+}  // namespace android
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..d75361e
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+
+#include <string>
+
+namespace android {
+namespace netdevice {
+namespace 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 can
+}  // namespace netdevice
+}  // namespace android
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..e22eafb
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.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.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+
+namespace android {
+namespace 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 netdevice
+}  // namespace android
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..fc2b193
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+namespace 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 netdevice
+}  // namespace android
diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp
new file mode 100644
index 0000000..ebc2f8c
--- /dev/null
+++ b/automotive/can/1.0/default/service.cpp
@@ -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.
+ */
+
+#include "CanController.h"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace 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 implementation
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+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..039f971
--- /dev/null
+++ b/automotive/can/1.0/hidl-utils/include/hidl-utils/hidl-utils.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
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace 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 hidl_utils
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
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..fa1048d
--- /dev/null
+++ b/automotive/can/1.0/tools/canhalctrl.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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 {
+namespace hardware {
+namespace automotive {
+namespace 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> [baudrate]" << 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 << " baudrate - 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 baudrate) {
+    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::BusConfiguration config = {};
+        config.name = busName;
+        config.iftype = type;
+        config.baudrate = baudrate;
+
+        if (type == ICanController::InterfaceType::INDEXED) {
+            config.interfaceId.index(std::stol(interface));
+        } else {
+            config.interfaceId.address(interface);
+        }
+
+        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 baudrate = 0;
+        if (argc == 4) {
+            baudrate = std::stoll(argv[3]);
+        }
+
+        return up(busName, *type, interface, baudrate);
+    } 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 can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+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..55b2a34
--- /dev/null
+++ b/automotive/can/1.0/tools/canhaldump.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+namespace hardware {
+namespace automotive {
+namespace 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 can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+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..29330c9
--- /dev/null
+++ b/automotive/can/1.0/tools/canhalsend.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 <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 {
+namespace hardware {
+namespace automotive {
+namespace 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 can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+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..f09c940
--- /dev/null
+++ b/automotive/can/1.0/types.hal
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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)) == !inverted
+ *
+ * In order for set of filters to match, at least one non-inverted filters must match (if there is
+ * one) and all inverted filters must match. In other words:
+ *  - a single matching non-inverted filter makes the whole set matching;
+ *  - a single non-matching inverted filter makes the whole set non-matching.
+ *
+ * Additional less common options for filtering include:
+ * rtr - Remote Transmission Request; another ECU requests DLC bytes of data on this message ID
+ * extendedFormat - 29 bit message ID is used instead of 11 bits
+ */
+struct CanMessageFilter {
+    CanMessageId id;
+    uint32_t mask;
+    bool inverted;
+    FilterFlag rtr;
+    FilterFlag extendedFormat;
+};
+
+
+/**
+ * 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 */
+    REQUIRE,
+    /** This FilterFlag must NOT be present in received messages to pass though the filter */
+    EXCLUDE,
+};
+
+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..b4d9132
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/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_defaults {
+    name: "android.hardware.automotive.can@vts-defaults",
+    defaults: ["VtsHalTargetTestDefaults", "android.hardware.automotive.can@defaults"],
+    header_libs: [
+        "android.hardware.automotive.can@hidl-utils-lib",
+        "android.hardware.automotive.can@vts-utils-lib",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@1.0",
+        "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..250caf2
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <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 <can-vts-utils/environment-utils.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+
+using hardware::hidl_vec;
+
+static utils::SimpleHidlEnvironment<ICanBus>* gEnv = nullptr;
+
+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::VtsHalHidlTargetTestBase {
+  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() {
+    const auto serviceName = gEnv->getServiceName<ICanBus>();
+    mCanBus = getService<ICanBus>(serviceName);
+    ASSERT_TRUE(mCanBus) << "Couldn't open CAN Bus: " << serviceName;
+}
+
+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_F(CanBusHalTest, SendNoPayload) {
+    CanMessage msg = {};
+    msg.id = 0x123;
+
+    const auto result = mCanBus->send(msg);
+    ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(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_F(CanBusHalTest, SendZeroId) {
+    CanMessage msg = {};
+    msg.payload = {1, 2, 3};
+
+    const auto result = mCanBus->send(msg);
+    ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(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_F(CanBusHalTest, ListenNoFilter) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+
+    closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, ListenSomeFilter) {
+    hidl_vec<CanMessageFilter> filters = {
+            {0x123, 0x1FF, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+            {0x001, 0x00F, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+            {0x200, 0x100, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+    };
+
+    const auto [result, closeHandle] = listen(filters, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+
+    closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, ListenNull) {
+    const auto [result, closeHandle] = listen({}, nullptr);
+    ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
+}
+
+TEST_F(CanBusHalTest, DoubleCloseListener) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+
+    closeHandle->close().assertOk();
+    closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, DontCloseListener) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+}
+
+TEST_F(CanBusHalTest, DoubleCloseErrorListener) {
+    auto closeHandle = listenForErrors(new CanErrorListener());
+    ASSERT_NE(nullptr, closeHandle.get());
+
+    closeHandle->close().assertOk();
+    closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, DoubleCloseNullErrorListener) {
+    auto closeHandle = listenForErrors(nullptr);
+    ASSERT_NE(nullptr, closeHandle.get());
+
+    closeHandle->close().assertOk();
+    closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, DontCloseErrorListener) {
+    auto closeHandle = listenForErrors(new CanErrorListener());
+    ASSERT_NE(nullptr, closeHandle.get());
+}
+
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest \
+ *     --hal_service_instance=android.hardware.automotive.can@1.0::ICanBus/test
+ */
+int main(int argc, char** argv) {
+    using android::hardware::automotive::can::V1_0::ICanBus;
+    using android::hardware::automotive::can::V1_0::vts::gEnv;
+    using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+    android::base::SetDefaultTag("CanBusVts");
+    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+    gEnv = new SimpleHidlEnvironment<ICanBus>;
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnv->init(&argc, argv);
+    return RUN_ALL_TESTS();
+}
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..695b9fb
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <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/can-hal-printers.h>
+#include <can-vts-utils/environment-utils.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+#include <utils/Mutex.h>
+#include <utils/SystemClock.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+
+using namespace std::chrono_literals;
+
+using hardware::hidl_vec;
+using InterfaceType = ICanController::InterfaceType;
+
+static utils::SimpleHidlEnvironment<ICanController>* gEnv = nullptr;
+
+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::BusConfiguration& 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) {
+        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::VtsHalHidlTargetTestBase {
+  protected:
+    virtual void SetUp() override;
+
+    static void SetUpTestCase();
+    static void TearDownTestCase();
+
+    Bus makeBus();
+
+  private:
+    unsigned mLastIface = 0;
+    static sp<ICanController> mCanController;
+    static bool mVirtualSupported;
+};
+
+sp<ICanController> CanBusVirtualHalTest::mCanController = nullptr;
+bool CanBusVirtualHalTest::mVirtualSupported;
+
+static CanMessage makeMessage(CanMessageId id) {
+    CanMessage msg = {};
+    msg.id = id;
+    return msg;
+}
+
+static void clearTimestamps(std::vector<CanMessage>& messages) {
+    std::for_each(messages.begin(), messages.end(), [](auto& msg) { msg.timestamp = 0; });
+}
+
+void CanBusVirtualHalTest::SetUp() {
+    if (!mVirtualSupported) GTEST_SKIP();
+}
+
+void CanBusVirtualHalTest::SetUpTestCase() {
+    const auto serviceName = gEnv->getServiceName<ICanController>();
+    mCanController = getService<ICanController>(serviceName);
+    ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName;
+
+    hidl_vec<InterfaceType> supported;
+    mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&supported)).assertOk();
+    mVirtualSupported = supported.contains(InterfaceType::VIRTUAL);
+}
+
+void CanBusVirtualHalTest::TearDownTestCase() {
+    mCanController.clear();
+}
+
+Bus CanBusVirtualHalTest::makeBus() {
+    const auto idx = ++mLastIface;
+
+    ICanController::BusConfiguration config = {};
+    config.name = "test" + std::to_string(idx);
+    config.iftype = InterfaceType::VIRTUAL;
+    config.interfaceId.address("vcan50");
+
+    return Bus(mCanController, config);
+}
+
+TEST_F(CanBusVirtualHalTest, Send) {
+    auto bus = makeBus();
+
+    CanMessage msg = {};
+    msg.id = 0x123;
+    msg.payload = {1, 2, 3};
+
+    bus.send(msg);
+}
+
+TEST_F(CanBusVirtualHalTest, SendAfterClose) {
+    auto bus = makeBus();
+    auto zombie = bus.get();
+    bus.reset();
+
+    const auto result = zombie->send({});
+    ASSERT_EQ(Result::INTERFACE_DOWN, result);
+}
+
+TEST_F(CanBusVirtualHalTest, SendAndRecv) {
+    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_F(CanBusVirtualHalTest, DownOneOfTwo) {
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    bus2.reset();
+
+    bus1.send({});
+}
+
+TEST_F(CanBusVirtualHalTest, Filter) {
+    auto bus1 = makeBus();
+    auto bus2 = makeBus();
+
+    hidl_vec<CanMessageFilter> filterPositive = {
+            {0x101, 0x100, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+            {0x010, 0x0F0, false, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+    };
+    auto listenerPositive = bus2.listen(filterPositive);
+
+    hidl_vec<CanMessageFilter> filterNegative = {
+            {0x123, 0x0FF, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+            {0x004, 0x00F, true, FilterFlag::DONT_CARE, FilterFlag::DONT_CARE},
+    };
+    auto listenerNegative = bus2.listen(filterNegative);
+
+    bus1.send(makeMessage(0));
+    bus1.send(makeMessage(0x1A0));
+    bus1.send(makeMessage(0x1A1));
+    bus1.send(makeMessage(0x2A0));
+    bus1.send(makeMessage(0x3A0));
+    bus1.send(makeMessage(0x010));
+    bus1.send(makeMessage(0x123));
+    bus1.send(makeMessage(0x023));
+    bus1.send(makeMessage(0x124));
+
+    std::vector<can::V1_0::CanMessage> expectedPositive{
+            makeMessage(0x1A0),  //
+            makeMessage(0x1A1),  //
+            makeMessage(0x3A0),  //
+            makeMessage(0x010),  //
+            makeMessage(0x123),  //
+            makeMessage(0x124),  //
+    };
+    std::vector<can::V1_0::CanMessage> expectedNegative{
+            makeMessage(0),      //
+            makeMessage(0x1A0),  //
+            makeMessage(0x1A1),  //
+            makeMessage(0x2A0),  //
+            makeMessage(0x3A0),  //
+            makeMessage(0x010),  //
+    };
+
+    auto messagesNegative = listenerNegative->fetchMessages(100ms, expectedNegative.size());
+    auto messagesPositive = listenerPositive->fetchMessages(100ms, expectedPositive.size());
+    clearTimestamps(messagesNegative);
+    clearTimestamps(messagesPositive);
+    ASSERT_EQ(expectedNegative, messagesNegative);
+    ASSERT_EQ(expectedPositive, messagesPositive);
+}
+
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanBusVirtualV1_0TargetTest/VtsHalCanBusVirtualV1_0TargetTest\
+ *     --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan
+ */
+int main(int argc, char** argv) {
+    using android::hardware::automotive::can::V1_0::ICanController;
+    using android::hardware::automotive::can::V1_0::vts::gEnv;
+    using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+    android::base::SetDefaultTag("CanBusVirtualVts");
+    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+    gEnv = new SimpleHidlEnvironment<ICanController>;
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnv->init(&argc, argv);
+    return RUN_ALL_TESTS();
+}
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..64e7a96
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 <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/can-hal-printers.h>
+#include <can-vts-utils/environment-utils.h>
+#include <gmock/gmock.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+
+using hardware::hidl_vec;
+using InterfaceType = ICanController::InterfaceType;
+
+static utils::SimpleHidlEnvironment<ICanController>* gEnv = nullptr;
+
+class CanControllerHalTest : public ::testing::VtsHalHidlTargetTestBase {
+  protected:
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+
+    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;
+};
+
+void CanControllerHalTest::SetUp() {
+    const auto serviceName = gEnv->getServiceName<ICanController>();
+    mCanController = getService<ICanController>(serviceName);
+    ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << serviceName;
+}
+
+void CanControllerHalTest::TearDown() {
+    mCanController.clear();
+}
+
+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::BusConfiguration config = {};
+    config.name = srvname;
+    config.iftype = iftype;
+    config.interfaceId.address(ifname);
+
+    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_F(CanControllerHalTest, SupportsSomething) {
+    const auto supported = getSupportedInterfaceTypes();
+    ASSERT_GT(supported.size(), 0u);
+}
+
+TEST_F(CanControllerHalTest, BringUpDown) {
+    const std::string name = "dummy";
+
+    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_F(CanControllerHalTest, DownDummy) {
+    const auto result = mCanController->downInterface("imnotup");
+    ASSERT_FALSE(result);
+}
+
+TEST_F(CanControllerHalTest, UpTwice) {
+    const std::string name = "dummy";
+
+    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_F(CanControllerHalTest, IdentifierCompatibility) {
+    using IdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
+    static const std::map<InterfaceType, std::vector<IdDisc>> compatMatrix = {
+            {InterfaceType::VIRTUAL, {IdDisc::address}},
+            {InterfaceType::SOCKETCAN, {IdDisc::address, IdDisc::serialno}},
+            {InterfaceType::SLCAN, {IdDisc::address, IdDisc::serialno}},
+            {InterfaceType::INDEXED, {IdDisc::index}},
+    };
+    static const std::vector<IdDisc> allDisc = {IdDisc::address, IdDisc::index, IdDisc::serialno};
+
+    for (const auto [iftype, supported] : compatMatrix) {
+        for (const auto iddisc : allDisc) {
+            LOG(INFO) << "Compatibility testing: " << iftype << " / " << iddisc;
+
+            ICanController::BusConfiguration config = {};
+            config.name = "compattestsrv";
+            config.iftype = iftype;
+            config.baudrate = 125000;
+
+            // using random-ish addresses, which may not be valid - we can't test the success case
+            if (iddisc == IdDisc::address) {
+                config.interfaceId.address("can0");
+            } else if (iddisc == IdDisc::index) {
+                config.interfaceId.index(0);
+            } else if (iddisc == IdDisc::serialno) {
+                config.interfaceId.serialno({"dummy", "dummier"});
+            }
+
+            const auto upresult = mCanController->upInterface(config);
+
+            if (!isSupported(iftype)) {
+                ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
+                continue;
+            }
+            ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult);
+
+            bool isSupportedDisc =
+                    std::find(supported.begin(), supported.end(), iddisc) != supported.end();
+            if (!isSupportedDisc) {
+                ASSERT_EQ(ICanController::Result::BAD_ADDRESS, upresult);
+                continue;
+            }
+
+            if (upresult == ICanController::Result::OK) {
+                const auto dnresult = mCanController->downInterface(config.name);
+                ASSERT_TRUE(dnresult);
+                continue;
+            }
+        }
+    }
+}
+
+TEST_F(CanControllerHalTest, FailEmptyName) {
+    const std::string name = "";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "vcan57", ICanController::Result::UNKNOWN_ERROR)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, false);
+}
+
+TEST_F(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::UNKNOWN_ERROR)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadVirtualAddress) {
+    const std::string name = "dummy";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::VIRTUAL, name, "", ICanController::Result::BAD_ADDRESS)) GTEST_SKIP();
+    assertRegistered(name, false);
+}
+
+TEST_F(CanControllerHalTest, FailBadSocketcanAddress) {
+    const std::string name = "dummy";
+
+    assertRegistered(name, false);
+    if (!up(InterfaceType::SOCKETCAN, name, "can87", ICanController::Result::BAD_ADDRESS)) {
+        GTEST_SKIP();
+    }
+    assertRegistered(name, false);
+}
+
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+/**
+ * Example manual invocation:
+ * adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest\
+ *     --hal_service_instance=android.hardware.automotive.can@1.0::ICanController/socketcan
+ */
+int main(int argc, char** argv) {
+    using android::hardware::automotive::can::V1_0::ICanController;
+    using android::hardware::automotive::can::V1_0::vts::gEnv;
+    using android::hardware::automotive::can::V1_0::vts::utils::SimpleHidlEnvironment;
+    android::base::SetDefaultTag("CanControllerVts");
+    android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+    gEnv = new SimpleHidlEnvironment<ICanController>;
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnv->init(&argc, argv);
+    return RUN_ALL_TESTS();
+}
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..e925c8f
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/Android.bp
@@ -0,0 +1,20 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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@vts-utils-lib",
+    export_include_dirs: ["include"],
+}
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..0923998
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/can-hal-printers.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android/hardware/automotive/can/1.0/ICanController.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace 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_SIMPLE(
+        ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator, int)
+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 V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
new file mode 100644
index 0000000..a722dd0
--- /dev/null
+++ b/automotive/can/1.0/vts/utils/include/can-vts-utils/environment-utils.h
@@ -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.
+ */
+
+#pragma once
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace vts {
+namespace utils {
+
+/**
+ * Simple test environment.
+ *
+ * This is a helper class to instantiate a test environment without boilerplate code for cases where
+ * there is no need to pass more parameters than just HIDL service instance name.
+ *
+ * The class implements registerTestServices() by calling registerTestService() on every HIDL
+ * interface provided as parameter to this template.
+ *
+ * Example usage:
+ *     static utils::SimpleHidlEnvironment<IMyService>* gEnv = nullptr;
+ *
+ *     void CanBusHalTest::SetUp() {
+ *         const auto serviceName = gEnv->getServiceName<IMyService>();
+ *         (...)
+ *     }
+ *
+ *     int main(int argc, char** argv) {
+ *         gEnv = new SimpleHidlEnvironment<IMyService>;
+ *         ::testing::AddGlobalTestEnvironment(gEnv);
+ *         ::testing::InitGoogleTest(&argc, argv);
+ *         gEnv->init(&argc, argv);
+ *         return RUN_ALL_TESTS();
+ *     }
+ *
+ * \param T... HIDL interface names to register for a test service
+ */
+template <typename... T>
+class SimpleHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    virtual void registerTestServices() override {
+        // Call registerTestService() for every HIDL interface using this template.
+        using expander = int[];
+        (void)expander{0, (registerTestService<T>(), 0)...};
+    }
+};
+
+}  // namespace utils
+}  // namespace vts
+}  // namespace V1_0
+}  // namespace can
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
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 2ef33fd..8988bfd 100644
--- a/automotive/evs/1.0/vts/functional/Android.bp
+++ b/automotive/evs/1.0/vts/functional/Android.bp
@@ -19,13 +19,15 @@
     srcs: [
         "VtsHalEvsV1_0TargetTest.cpp",
         "FrameHandler.cpp",
-        "FormatConvert.cpp"
     ],
     defaults: ["VtsHalTargetTestDefaults"],
     shared_libs: [
         "libui",
     ],
-    static_libs: ["android.hardware.automotive.evs@1.0"],
+    static_libs: [
+        "android.hardware.automotive.evs@1.0",
+        "android.hardware.automotive.evs@common-default-lib",
+    ],
     test_suites: ["general-tests"],
     cflags: [
         "-O0",
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..c850c91
--- /dev/null
+++ b/automotive/evs/1.1/Android.bp
@@ -0,0 +1,24 @@
+// 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",
+        "IEvsEnumerator.hal",
+    ],
+    interfaces: [
+        "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..975b6c6
--- /dev/null
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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);
+
+    /**
+     * 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 a frame that was 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 A buffer to be returned.
+     * @return result Return EvsResult::OK if this call is successful.
+     */
+    doneWithFrame_1_1(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.
+     *
+     * @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 A programmed parameter value.  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, int32_t effectiveValue);
+
+    /**
+     * Retrieves a value 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  A value of requested camera parameter.
+     */
+    getIntParameter(CameraParam id) generates(EvsResult result, int32_t value);
+};
diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal
new file mode 100644
index 0000000..9e4ea19
--- /dev/null
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.evs@1.1;
+
+import @1.0::IEvsCameraStream;
+import @1.1::BufferDesc;
+import @1.1::EvsEvent;
+
+/**
+ * Implemented on client side to receive asynchronous streaming event deliveries.
+ */
+interface IEvsCameraStream extends @1.0::IEvsCameraStream {
+
+    /**
+     * Receives calls from the HAL each time a video frame 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.
+     *
+     * @param buffer a buffer descriptor of a delivered image frame.
+     */
+    oneway deliverFrame_1_1(BufferDesc buffer);
+
+    /**
+     * Receives calls from the HAL each time an event happens.
+     *
+     * @param  event EVS event with possible event information.
+     */
+    oneway notify(EvsEvent event);
+};
diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal
new file mode 100644
index 0000000..1695821
--- /dev/null
+++ b/automotive/evs/1.1/IEvsEnumerator.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.automotive.evs@1.1;
+
+import IEvsCamera;
+import @1.0::IEvsEnumerator;
+import @1.0::EvsResult;
+import android.hardware.camera.device@3.2::Stream;
+
+/**
+ * Provides the mechanism for EVS camera 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);
+};
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
new file mode 100644
index 0000000..41cb426
--- /dev/null
+++ b/automotive/evs/1.1/default/Android.bp
@@ -0,0 +1,47 @@
+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",
+    ],
+    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.2",
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libui",
+        "libutils",
+        "libcamera_metadata",
+        "libtinyxml2",
+    ],
+
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+
+    required: [
+        "evs_default_configuration.xml",
+    ],
+}
+
+prebuilt_etc {
+    name: "evs_default_configuration.xml",
+
+    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..96a2f98
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.cpp
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 *group_id = curElem->FindAttribute("group_id")->Value();
+
+            /* create CameraGroup */
+            unique_ptr<ConfigManager::CameraGroup> aCameraGroup(new ConfigManager::CameraGroup());
+
+            /* add a camera device to its group */
+            addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup);
+
+            /* a list of camera stream configurations */
+            const XMLElement *childElem =
+                curElem->FirstChildElement("caps")->FirstChildElement("stream");
+            while (childElem != nullptr) {
+                /* read 5 attributes */
+                const XMLAttribute *idAttr     = childElem->FindAttribute("id");
+                const XMLAttribute *widthAttr  = childElem->FindAttribute("width");
+                const XMLAttribute *heightAttr = childElem->FindAttribute("height");
+                const XMLAttribute *fmtAttr    = childElem->FindAttribute("format");
+                const XMLAttribute *fpsAttr    = childElem->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
+                    };
+                    aCameraGroup->streamConfigurations[id] = cfg;
+                }
+
+                childElem = childElem->NextSiblingElement("stream");
+            }
+
+            /* camera group synchronization */
+            const char *sync = curElem->FindAttribute("synchronized")->Value();
+            aCameraGroup->synchronized =
+                static_cast<bool>(strcmp(sync, "false"));
+
+            /* add a group to hash map */
+            mCameraGroups[group_id] = std::move(aCameraGroup);
+        } 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();
+
+            /* store read camera module information */
+            mCameraInfo[id] = readCameraDeviceInfo(curElem);
+
+            /* 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();
+    }
+}
+
+
+unique_ptr<ConfigManager::CameraInfo>
+ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) {
+    if (aDeviceElem == nullptr) {
+        return nullptr;
+    }
+
+    /* create a CameraInfo to be filled */
+    unique_ptr<ConfigManager::CameraInfo> aCamera(new ConfigManager::CameraInfo());
+
+    /* 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 aCamera;
+}
+
+
+size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+                                             unique_ptr<ConfigManager::CameraInfo> &aCamera,
+                                             size_t &dataSize) {
+    if (aCapElem == 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[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,
+                                       unique_ptr<ConfigManager::CameraInfo> &aCamera,
+                                       size_t &dataSize) {
+    if (aParamElem == 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[tag] =
+                        make_pair(make_unique<void *>(data), count);
+
+                    ++numEntries;
+                    dataSize += calculate_camera_metadata_entry_data_size(
+                                    get_camera_metadata_tag_type(tag), count
+                                );
+
+                    break;
+                }
+
+                default:
+                    ALOGW("Parameter %s is not supported",
+                          curElem->FindAttribute("name")->Value());
+                    break;
+            }
+        }
+
+        curElem = curElem->NextSiblingElement("parameter");
+    }
+
+    return numEntries;
+}
+
+
+bool ConfigManager::constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+                                            const size_t totalEntries,
+                                            const size_t totalDataSize) {
+    if (!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[id] = cfg;
+                }
+
+                curStream = curStream->NextSiblingElement("stream");
+            }
+        }
+
+        mDisplayInfo[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;
+}
+
+
+void ConfigManager::addCameraDevices(const char *devices,
+                                     unique_ptr<CameraGroup> &aGroup) {
+    stringstream device_list(devices);
+    string token;
+    while (getline(device_list, token, ',')) {
+        aGroup->devices.emplace(token);
+    }
+}
+
+
+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..0275f90
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 frame rates */
+        unordered_set<int32_t> frameRates;
+
+        /*
+         * 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 CameraGroup {
+    public:
+        CameraGroup() {}
+
+        /* ID of member camera devices */
+        unordered_set<string> devices;
+
+        /* The capture operation of member camera devices are synchronized */
+        bool synchronized = false;
+
+        /*
+         * List of stream configurations that are supposed by all camera devices
+         * in this group.
+         */
+        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+    };
+
+    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 CameraGroup
+     *         A pointer to a camera group identified by a given id.
+     */
+    unique_ptr<CameraGroup>& getCameraGroup(const string& gid) {
+        return mCameraGroups[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, CameraGroup> hash map */
+    unordered_map<string, unique_ptr<CameraGroup>> mCameraGroups;
+
+    /*
+     * 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  aDeviceElem
+     *         A pointer to "device" XML element that contains camera module
+     *         capability info and its characteristics.
+     *
+     * @return unique_ptr<CameraInfo>
+     *         A pointer to CameraInfo class that contains camera module
+     *         capability and characteristics.  Please note that this transfers
+     *         the ownership of created CameraInfo to the caller.
+     */
+    unique_ptr<CameraInfo> readCameraDeviceInfo(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,
+                                  unique_ptr<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,
+                              unique_ptr<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(unique_ptr<CameraInfo> &aCamera,
+                                 const size_t totalEntries,
+                                 const size_t totalDataSize);
+
+    /*
+     * parse a comma-separated list of camera devices and add them to
+     * CameraGroup.
+     *
+     * @param  devices
+     *         A comma-separated list of camera device identifiers.
+     * @param  aGroup
+     *         Camera group which cameras will be added to.
+     */
+    void addCameraDevices(const char *devices,
+                          unique_ptr<CameraGroup> &aGroup);
+};
+#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..8206daa
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+        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..8c89ae7
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.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.
+ */
+#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");
+};
+
+#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..5ba753d
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -0,0 +1,676 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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>
+
+
+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<EvsResult> EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc)  {
+    std::lock_guard <std::mutex> lock(mAccessLock);
+    returnBuffer(bufDesc.bufferId, bufDesc.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>& ) {
+    // 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();
+}
+
+
+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;
+
+            // Write test data into the image buffer
+            fillTestFrame(newBuffer);
+
+            // Issue the (asynchronous) callback to the client -- can't be holding the lock
+            auto result = mStream->deliverFrame_1_1(newBuffer);
+            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
+    EvsEvent 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..c15b4b1
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.0/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 ::android::hardware::automotive::evs::V1_0::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<EvsResult> pauseVideoStream() override;
+    Return<EvsResult> resumeVideoStream() override;
+    Return<EvsResult> doneWithFrame_1_1(const BufferDesc_1_1& buffer) override;
+    Return<EvsResult> setMaster() override;
+    Return<EvsResult> forceMaster(const sp<IEvsDisplay>& 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;
+
+    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..74c099a
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsDisplay.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+EvsDisplay::EvsDisplay() {
+    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);
+}
+
+
+} // 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..2a56535
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsDisplay.h
@@ -0,0 +1,72 @@
+/*
+ * 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.0/IEvsDisplay.h>
+#include <ui/GraphicBuffer.h>
+
+using ::android::hardware::automotive::evs::V1_0::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;
+
+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;
+
+
+    // Implementation details
+    EvsDisplay();
+    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;
+};
+
+} // 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..a010729
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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"
+
+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;
+
+
+EvsEnumerator::EvsEnumerator() {
+    ALOGD("EvsEnumerator created");
+
+    // Add sample camera data to our list of cameras
+    // In a real driver, this would be expected to can the available hardware
+    sConfigManager =
+        ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml");
+    for (auto v : sConfigManager->getCameraList()) {
+        sCameraList.emplace_back(v.c_str());
+    }
+}
+
+
+// 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>> 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::closeDisplay(const ::android::sp<IEvsDisplay>& 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;
+}
+
+} // 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..475ec76
--- /dev/null
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <list>
+
+#include "ConfigManager.h"
+
+using ::android::hardware::automotive::evs::V1_0::EvsResult;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
+using ::android::hardware::automotive::evs::V1_0::DisplayState;
+using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
+using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
+using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+
+class EvsCamera;    // from EvsCamera.h
+class EvsDisplay;   // from EvsDisplay.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>>     openDisplay()  override;
+    Return<void>                closeDisplay(const ::android::sp<IEvsDisplay>& 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;
+
+    // Implementation details
+    EvsEnumerator();
+
+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; }
+    };
+
+    static CameraRecord* findCameraById(const std::string& cameraId);
+
+    static std::list<CameraRecord>   sCameraList;
+
+    // Weak pointer. Object destructs if client dies.
+    static wp<EvsDisplay>            sActiveDisplay;
+
+    static unique_ptr<ConfigManager> sConfigManager;
+};
+
+} // 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/ServiceNames.h b/automotive/evs/1.1/default/ServiceNames.h
new file mode 100644
index 0000000..1178da5
--- /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[] = "EvsEnumeratorHw";
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..692102e
--- /dev/null
+++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
@@ -0,0 +1,68 @@
+<?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 device information -->
+    <camera>
+        <!-- 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..5135864
--- /dev/null
+++ b/automotive/evs/1.1/default/service.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+using android::hardware::automotive::evs::V1_0::IEvsDisplay;
+
+// The namespace in which all our implementation code lives
+using namespace android::hardware::automotive::evs::V1_1::implementation;
+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..dcb2abb
--- /dev/null
+++ b/automotive/evs/1.1/types.hal
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+};
+
+/**
+ * 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 EvsEvent {
+    /**
+     * Type of an informative event
+     */
+    EvsEventType aType;
+    /**
+     * 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,
+};
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..4753933
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/Android.bp
@@ -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.
+//
+
+cc_test {
+    name: "VtsHalEvsV1_1TargetTest",
+    srcs: [
+        "FrameHandler.cpp",
+        "VtsHalEvsV1_1TargetTest.cpp",
+    ],
+    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",
+    ],
+    test_suites: ["general-tests"],
+    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..6d53652
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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(mLock);
+    if (mRunning) {
+        mEventSignal.wait(lock, [this]() { return !mRunning; });
+    }
+}
+
+
+bool FrameHandler::returnHeldBuffer() {
+    std::unique_lock<std::mutex> lock(mLock);
+
+    // Return the oldest buffer we're holding
+    if (mHeldBuffers.empty()) {
+        // No buffers are currently held
+        return false;
+    }
+
+    BufferDesc_1_1 buffer = mHeldBuffers.front();
+    mHeldBuffers.pop();
+    mCamera->doneWithFrame_1_1(buffer);
+
+    return true;
+}
+
+
+bool FrameHandler::isRunning() {
+    std::unique_lock<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::unique_lock<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 BufferDesc_1_1& bufDesc) {
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
+    ALOGD("Received a frame from the camera (%p)",
+          bufDesc.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.
+    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, bufDesc);
+
+            // 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
+                mLock.lock();
+                mFramesDisplayed++;
+                mLock.unlock();
+            }
+        }
+    }
+
+
+    switch (mReturnMode) {
+    case eAutoReturn:
+        // Send the camera buffer back now that the client has seen it
+        ALOGD("Calling doneWithFrame");
+        mCamera->doneWithFrame_1_1(bufDesc);
+        break;
+    case eNoAutoReturn:
+        // Hang onto the buffer handle for now -- the client will return it explicitly later
+        mHeldBuffers.push(bufDesc);
+    }
+
+    mLock.lock();
+    ++mFramesReceived;
+    mLock.unlock();
+    mFrameSignal.notify_all();
+
+    ALOGD("Frame handling complete");
+
+    return Void();
+}
+
+
+Return<void> FrameHandler::notify(const EvsEvent& event) {
+    // Local flag we use to keep track of when the stream is stopping
+    mLock.lock();
+    mLatestEventDesc = event;
+    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));
+    }
+    mLock.unlock();
+    mEventSignal.notify_all();
+
+    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 EvsEventType aTargetEvent,
+                                EvsEvent &event) {
+    // Wait until we get an expected parameter change event.
+    std::unique_lock<std::mutex> lock(mLock);
+    auto now = std::chrono::system_clock::now();
+    bool result = mEventSignal.wait_until(lock, now + 5s,
+        [this, aTargetEvent, &event](){
+            bool flag = mLatestEventDesc.aType == aTargetEvent;
+            if (flag) {
+                event.aType = mLatestEventDesc.aType;
+                event.payload[0] = mLatestEventDesc.payload[0];
+                event.payload[1] = mLatestEventDesc.payload[1];
+            }
+
+            return flag;
+        }
+    );
+
+    return !result;
+}
+
+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..e5f1b8f
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 EvsEventType aTargetEvent,
+                            EvsEvent &eventDesc);
+    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 BufferDesc_1_1& buffer) override;
+    Return<void> notify(const EvsEvent& 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::condition_variable     mEventSignal;
+    std::condition_variable     mFrameSignal;
+
+    std::queue<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;
+    EvsEvent                    mLatestEventDesc;
+};
+
+
+#endif //EVS_VTS_FRAMEHANDLER_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..1d3fd87
--- /dev/null
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -0,0 +1,1516 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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"
+
+
+// Note:  We have't got a great way to indicate which target
+// should be tested, so we'll leave the interface served by the
+// default (mock) EVS driver here for easy reference.  All
+// actual EVS drivers should serve on the EvsEnumeratorHw name,
+// however, so the code is checked in that way.
+//const static char kEnumeratorName[]  = "EvsEnumeratorHw-Mock";
+const static char kEnumeratorName[]  = "EvsEnumeratorHw";
+
+
+// These values are called out in the EVS design doc (as of Mar 8, 2017)
+static const int kMaxStreamStartMilliseconds = 500;
+static const int kMinimumFramesPerSecond = 10;
+
+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 <cstdio>
+#include <cstring>
+#include <cstdlib>
+
+#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.0/IEvsDisplay.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <system/camera_metadata.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.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::hardware::hidl_string;
+using ::android::sp;
+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;
+
+/*
+ * 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;
+
+
+// Test environment for Evs HIDL HAL.
+class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static EvsHidlEnvironment* Instance() {
+        static EvsHidlEnvironment* instance = new EvsHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IEvsEnumerator>(); }
+
+   private:
+    EvsHidlEnvironment() {}
+};
+
+// The main test class for EVS
+class EvsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+public:
+    virtual void SetUp() override {
+        // Make sure we can connect to the enumerator
+        string service_name =
+            EvsHidlEnvironment::Instance()->getServiceName<IEvsEnumerator>(kEnumeratorName);
+        pEnumerator = getService<IEvsEnumerator>(service_name);
+        ASSERT_NE(pEnumerator.get(), nullptr);
+
+        mIsHwModule = !service_name.compare(kEnumeratorName);
+    }
+
+    virtual void TearDown() override {}
+
+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);
+                }
+            }
+        );
+
+        // We insist on at least one camera for EVS to pass any camera tests
+        ASSERT_GE(cameraInfo.size(), 1u);
+    }
+
+    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.
+};
+
+
+// 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_F(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) {
+        for (int pass = 0; pass < 2; pass++) {
+            sp<IEvsCamera_1_1> pCam =
+                IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+                .withDefault(nullptr);
+            ASSERT_NE(pCam, nullptr);
+
+            // 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);
+                                    }
+            );
+
+            // 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_F(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) {
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // 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(pCam, pCam2);
+        ASSERT_NE(pCam2, nullptr);
+
+        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_F(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) {
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // 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;
+        EXPECT_LE(nanoseconds_to_milliseconds(timeToFirstFrame), kMaxStreamStartMilliseconds);
+        printf("Measured time to first frame %0.2f ms\n", timeToFirstFrame * kNanoToMilliseconds);
+        ALOGI("Measured time to first frame %0.2f ms", 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);
+        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);
+
+        // 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);
+    }
+}
+
+
+/*
+ * 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_F(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) {
+
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // 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(2);   // 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_F(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 exclusive access to the EVS display
+    sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+    ASSERT_NE(pDisplay, nullptr);
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // 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_F(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) {
+        // 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);
+
+        sp<IEvsCamera_1_1> pCam1 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .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);
+    }
+}
+
+
+/*
+ * CameraParameter:
+ * Verify that a client can adjust a camera parameter.
+ */
+TEST_F(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) {
+        // 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);
+
+        // 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
+                int32_t val1 = 0;
+                pCam->getIntParameter(CameraParam::AUTO_FOCUS,
+                                   [&result, &val1](auto status, auto value) {
+                                       result = status;
+                                       if (status == EvsResult::OK) {
+                                          val1 = value;
+                                       }
+                                   });
+                if (val1 != 0) {
+                    pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                       [&result, &val1](auto status, auto effectiveValue) {
+                                           result = status;
+                                           val1 = effectiveValue;
+                                       });
+                    ASSERT_EQ(EvsResult::OK, result);
+                    ASSERT_EQ(val1, 0);
+                }
+            }
+
+            // Try to program a parameter with a random value [minVal, maxVal]
+            int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+            int32_t val1 = 0;
+
+            // Rounding down
+            val0 = val0 - (val0 % step);
+            pCam->setIntParameter(cmd, val0,
+                               [&result, &val1](auto status, auto effectiveValue) {
+                                   result = status;
+                                   val1 = effectiveValue;
+                               });
+
+            ASSERT_EQ(EvsResult::OK, result);
+
+            pCam->getIntParameter(cmd,
+                               [&result, &val1](auto status, auto value) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      val1 = value;
+                                   }
+                               });
+            ASSERT_EQ(EvsResult::OK, result);
+            ASSERT_EQ(val0, val1) << "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_F(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) {
+        // 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);
+        sp<IEvsCamera_1_1> pCamNonMaster =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCamNonMaster, nullptr);
+
+        // 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.
+        EvsEvent aNotification = {};
+
+        // Release a master role.
+        pCamMaster->unsetMaster();
+
+        // Verify a change notification.
+        frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+        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);
+
+        // Closing current master client.
+        frameHandlerNonMaster->shutdown();
+
+        // Verify a change notification.
+        frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+        ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+                  static_cast<EvsEventType>(aNotification.aType));
+
+        // Closing another stream.
+        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_F(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) {
+        // 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);
+        sp<IEvsCamera_1_1> pCamNonMaster =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCamNonMaster, nullptr);
+
+        // 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;
+        int32_t val1 = 0;
+        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
+                int32_t val1 = 1;
+                pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &val1](auto status, auto effectiveValue) {
+                                       result = status;
+                                       val1 = effectiveValue;
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                ASSERT_EQ(val1, 0);
+            }
+
+            // Try to program a parameter
+            val0 = minVal + (std::rand() % (maxVal - minVal));
+
+            // Rounding down
+            val0 = val0 - (val0 % step);
+            pCamMaster->setIntParameter(cmd, val0,
+                                     [&result, &val1](auto status, auto effectiveValue) {
+                                         result = status;
+                                         val1 = effectiveValue;
+                                     });
+            ASSERT_EQ(EvsResult::OK, result);
+
+            // Wait a moment
+            sleep(1);
+
+            // Non-master client expects to receive a parameter change notification
+            // whenever a master client adjusts it.
+            EvsEvent aNotification = {};
+
+            pCamMaster->getIntParameter(cmd,
+                                     [&result, &val1](auto status, auto value) {
+                                         result = status;
+                                         if (status == EvsResult::OK) {
+                                            val1 = value;
+                                         }
+                                     });
+            ASSERT_EQ(EvsResult::OK, result);
+            ASSERT_EQ(val0, val1) << "Values are not matched.";
+
+            // Verify a change notification
+            frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification.aType));
+            ASSERT_EQ(cmd,
+                      static_cast<CameraParam>(aNotification.payload[0]));
+            ASSERT_EQ(val1,
+                      static_cast<int32_t>(aNotification.payload[1]));
+        }
+
+        // Try to adjust a parameter via non-master client
+        pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
+                                    [&result, &val1](auto status, auto effectiveValue) {
+                                        result = status;
+                                        val1 = effectiveValue;
+                                    });
+        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
+        result = pCamMaster->unsetMaster();
+        ASSERT_EQ(EvsResult::OK, result);
+
+        // Try to adjust a parameter after being retired
+        pCamMaster->setIntParameter(camMasterCmds[0], val0,
+                                 [&result, &val1](auto status, auto effectiveValue) {
+                                     result = status;
+                                     val1 = effectiveValue;
+                                 });
+        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;
+            if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+                // Try to turn off auto-focus
+                int32_t val1 = 1;
+                pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &val1](auto status, auto effectiveValue) {
+                                       result = status;
+                                       val1 = effectiveValue;
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                ASSERT_EQ(val1, 0);
+            }
+
+            // Try to program a parameter
+            val0 = minVal + (std::rand() % (maxVal - minVal));
+
+            // Rounding down
+            val0 = val0 - (val0 % step);
+            pCamNonMaster->setIntParameter(cmd, val0,
+                                        [&result, &val1](auto status, auto effectiveValue) {
+                                            result = status;
+                                            val1 = effectiveValue;
+                                        });
+            ASSERT_EQ(EvsResult::OK, result);
+
+            // Wait a moment
+            sleep(1);
+
+            // Non-master client expects to receive a parameter change notification
+            // whenever a master client adjusts it.
+            EvsEvent aNotification = {};
+
+            pCamNonMaster->getIntParameter(cmd,
+                                        [&result, &val1](auto status, auto value) {
+                                            result = status;
+                                            if (status == EvsResult::OK) {
+                                               val1 = value;
+                                            }
+                                        });
+            ASSERT_EQ(EvsResult::OK, result);
+            ASSERT_EQ(val0, val1) << "Values are not matched.";
+
+            // Verify a change notification
+            frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification.aType));
+            ASSERT_EQ(cmd,
+                      static_cast<CameraParam>(aNotification.payload[0]));
+            ASSERT_EQ(val1,
+                      static_cast<int32_t>(aNotification.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_F(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> pDisplay = pEnumerator->openDisplay();
+    ASSERT_NE(pDisplay, nullptr);
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // Create two clients
+        sp<IEvsCamera_1_1> pCam0 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam0, nullptr);
+
+        sp<IEvsCamera_1_1> pCam1 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam1, nullptr);
+
+        // 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;
+            }
+        );
+
+        if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+            // Try to turn off auto-focus
+            int32_t val1 = 0;
+            pCam1->getIntParameter(CameraParam::AUTO_FOCUS,
+                               [&result, &val1](auto status, auto value) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      val1 = value;
+                                   }
+                               });
+            if (val1 != 0) {
+                pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &val1](auto status, auto effectiveValue) {
+                                       result = status;
+                                       val1 = effectiveValue;
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                ASSERT_EQ(val1, 0);
+            }
+        }
+
+        // Try to program a parameter with a random value [minVal, maxVal]
+        int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+        int32_t val1 = 0;
+
+        // Rounding down
+        val0 = val0 - (val0 % step);
+
+        result = pCam1->setMaster();
+        ASSERT_EQ(EvsResult::OK, result);
+
+        pCam1->setIntParameter(cam1Cmds[0], val0,
+                            [&result, &val1](auto status, auto effectiveValue) {
+                                result = status;
+                                val1 = effectiveValue;
+                            });
+        ASSERT_EQ(EvsResult::OK, result);
+
+        // Verify a change notification
+        EvsEvent aNotification = {};
+        bool timeout =
+            frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+        ASSERT_FALSE(timeout) << "Expected event does not arrive";
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                  EvsEventType::PARAMETER_CHANGED);
+        ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+                  cam1Cmds[0]);
+        ASSERT_EQ(val1,
+                  static_cast<int32_t>(aNotification.payload[1]));
+
+        // Client 0 steals a master role
+        ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
+
+        frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                  EvsEventType::MASTER_RELEASED);
+
+        // Client 0 programs a parameter
+        val0 = minVal + (std::rand() % (maxVal - minVal));
+        val1 = 0;
+
+        // Rounding down
+        val0 = val0 - (val0 % step);
+
+        if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+            // Try to turn off auto-focus
+            int32_t val1 = 0;
+            pCam0->getIntParameter(CameraParam::AUTO_FOCUS,
+                               [&result, &val1](auto status, auto value) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      val1 = value;
+                                   }
+                               });
+            if (val1 != 0) {
+                pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &val1](auto status, auto effectiveValue) {
+                                       result = status;
+                                       val1 = effectiveValue;
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                ASSERT_EQ(val1, 0);
+            }
+        }
+
+        pCam0->setIntParameter(cam0Cmds[0], val0,
+                            [&result, &val1](auto status, auto effectiveValue) {
+                                result = status;
+                                val1 = effectiveValue;
+                            });
+        ASSERT_EQ(EvsResult::OK, result);
+
+        // Verify a change notification
+        timeout =
+            frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+        ASSERT_FALSE(timeout) << "Expected event does not arrive";
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                  EvsEventType::PARAMETER_CHANGED);
+        ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+                  cam0Cmds[0]);
+        ASSERT_EQ(val1,
+                  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_F(EvsHidlTest, CameraUseStreamConfigToDisplay) {
+    ALOGI("Starting CameraUseStreamConfigToDisplay test");
+
+    // Get the camera list
+    loadCameraList();
+
+    // Request exclusive access to the EVS display
+    sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+    ASSERT_NE(pDisplay, nullptr);
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // choose a configuration that has a frame rate faster than minReqFps.
+        Stream targetCfg = {};
+        const int32_t minReqFps = 15;
+        int32_t maxArea = 0;
+        camera_metadata_entry_t streamCfgs;
+        bool foundCfg = false;
+        if (!find_camera_metadata_entry(
+                 reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+                 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                 &streamCfgs)) {
+            // Stream configurations are found in metadata
+            RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+            for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+                    if (ptr->width * ptr->height > maxArea &&
+                        ptr->framerate >= minReqFps) {
+                        targetCfg.width = ptr->width;
+                        targetCfg.height = ptr->height;
+
+                        maxArea = ptr->width * ptr->height;
+                        foundCfg = true;
+                    }
+                }
+                ++ptr;
+            }
+        }
+        targetCfg.format =
+            static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+        if (!foundCfg) {
+            // Current EVS camera does not provide stream configurations in the
+            // metadata.
+            continue;
+        }
+
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // 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_F(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) {
+        // 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);
+
+        // 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);
+
+        // 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);
+    }
+}
+
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    EvsHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
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/1.0/vts/functional/FormatConvert.cpp b/automotive/evs/common/utils/default/FormatConvert.cpp
similarity index 74%
rename from automotive/evs/1.0/vts/functional/FormatConvert.cpp
rename to automotive/evs/common/utils/default/FormatConvert.cpp
index 3d82d32..d4c7da0 100644
--- a/automotive/evs/1.0/vts/functional/FormatConvert.cpp
+++ b/automotive/evs/common/utils/default/FormatConvert.cpp
@@ -18,10 +18,15 @@
 
 #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 align(int value) {
+int Utils::align(int value) {
     static_assert((alignment && !(alignment & (alignment - 1))),
                   "alignment must be a power of 2");
 
@@ -31,15 +36,17 @@
 
 
 // Limit the given value to the provided range.  :)
-static inline float clamp(float v, float min, float max) {
+inline float Utils::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) {
+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
@@ -67,10 +74,10 @@
 }
 
 
-void copyNV21toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels,
-                     bool bgrxFormat)
+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
@@ -99,10 +106,10 @@
 }
 
 
-void copyYV12toRGB32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels,
-                     bool 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,
@@ -134,10 +141,10 @@
 }
 
 
-void copyYUYVtoRGB32(unsigned width, unsigned height,
-                     uint8_t* src, unsigned srcStridePixels,
-                     uint32_t* dst, unsigned dstStridePixels,
-                     bool 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;
 
@@ -167,34 +174,34 @@
 }
 
 
-void copyNV21toBGR32(unsigned width, unsigned height,
-                     uint8_t* src,
-                     uint32_t* dst, unsigned dstStridePixels)
+void Utils::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)
+void Utils::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)
+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 copyMatchedInterleavedFormats(unsigned width, unsigned height,
-                                   void* src, unsigned srcStridePixels,
-                                   void* dst, unsigned dstStridePixels,
-                                   unsigned pixelSize) {
+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);
@@ -204,3 +211,10 @@
         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..6e9e8aa
--- /dev/null
+++ b/automotive/occupant_awareness/aidl/Android.bp
@@ -0,0 +1,13 @@
+aidl_interface {
+    name: "android.hardware.automotive.occupant_awareness",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/automotive/occupant_awareness/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: false,
+        },
+    }
+}
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/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index ed09859..f9c25d1 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -58,6 +58,7 @@
     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/VehicleEmulator.cpp",
         "impl/vhal_v2_0/PipeComm.cpp",
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/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
new file mode 100644
index 0000000..56ecd67
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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>
+
+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.
+ */
+
+/**
+ *  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
+    virtual StatusCode setProperty(const VehiclePropValue& value) = 0;
+
+    // Receive a new property value from server
+    virtual void onPropertyValue(const VehiclePropValue& value) = 0;
+};
+
+/**
+ *  Server lives on the vehicle side to talk to Android HAL
+ */
+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
+    virtual StatusCode onSetProperty(const VehiclePropValue& value) = 0;
+
+    // Receive a new property value from car (via direct connection to the car bus or the emulator)
+    // and forward the value to HAL
+    virtual void onPropertyValueFromCar(const VehiclePropValue& value) = 0;
+};
+
+/**
+ *  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) override {
+        return this->onSetProperty(value);
+    }
+
+    void onPropertyValueFromCar(const VehiclePropValue& value) override {
+        return this->onPropertyValue(value);
+    }
+
+    // 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/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/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 8a89322..2dbcbba 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
@@ -85,6 +85,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 kSetPropertyFromVehcileForTest with an array of integer {HVAC_FAN_SPEED, value of
+ * fan speed} and a long value indicates the timestamp of the events .
+ * It only works with integer type properties.
+ */
+const int32_t kSetIntPropertyFromVehcileForTest =
+        0x1112 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * It only works with float type properties.
+ */
+const int32_t kSetFloatPropertyFromVehcileForTest =
+        0x1113 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * It only works with boolean type properties.
+ */
+const int32_t kSetBooleanPropertyFromVehcileForTest =
+        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 +195,6 @@
                          .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.floatValues = {15000.0f}}},
 
@@ -177,14 +204,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 +220,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 +235,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,7 +243,6 @@
                          .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::STATIC,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}},
 
@@ -234,7 +257,7 @@
                  {
                          .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
                          .access = VehiclePropertyAccess::READ,
-                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
                          .minSampleRate = 1.0f,
                          .maxSampleRate = 10.0f,
                  },
@@ -265,7 +288,9 @@
                  {
                          .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}}},
 
@@ -285,8 +310,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 +321,6 @@
                          .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
                          .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {0}}},
 
@@ -303,8 +328,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 +339,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 +347,6 @@
                          .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {0}}},
 
@@ -330,17 +354,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 +398,7 @@
                          .minSampleRate = 1.0f,
                          .maxSampleRate = 2.0f,
                  },
-         .initialValue = {.floatValues = {200}}},  // units in kPa
+         .initialValue = {.floatValues = {200.0f}}},  // units in kPa
 
         {.config =
                  {
@@ -397,7 +421,6 @@
                          .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {0}}},
 
@@ -430,6 +453,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 +592,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 +603,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 +626,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 +664,50 @@
                                 .prop = kGenerateFakeDataControllingProperty,
                                 .access = VehiclePropertyAccess::WRITE,
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {1, 0, 0, 2, 0, 0, 0, 0, 0},
+                        },
+        },
+
+        {
+                .config =
+                        {
+                                .prop = kSetIntPropertyFromVehcileForTest,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {0, 0, 0, 2, 1, 0, 0, 0, 0},
+                        },
+        },
+
+        {
+                .config =
+                        {
+                                .prop = kSetFloatPropertyFromVehcileForTest,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {0, 0, 1, 0, 1, 0, 1, 0, 0},
+                        },
+        },
+
+        {
+                .config =
+                        {
+                                .prop = kSetBooleanPropertyFromVehcileForTest,
+                                .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 +839,6 @@
                          .prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
                  },
          .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
 
@@ -766,7 +847,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 +855,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 +863,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 +871,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 +879,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 +887,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 +895,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 +948,24 @@
                     .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}}},
 };
 
 }  // 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..168999d
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 "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 {
+
+void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value) {
+    if (!mPropCallback) {
+        LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
+        return;
+    }
+    return mPropCallback(value);
+}
+
+void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
+    if (mPropCallback) {
+        LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!";
+        return;
+    }
+    mPropCallback = std::move(callback);
+}
+
+GeneratorHub* EmulatedVehicleServer::getGenerator() {
+    return &mGeneratorHub;
+}
+
+VehiclePropValuePool* EmulatedVehicleServer::getValuePool() const {
+    if (!mValuePool) {
+        LOG(WARNING) << __func__ << ": Value pool not set!";
+    }
+    return mValuePool;
+}
+
+void EmulatedVehicleServer::setValuePool(VehiclePropValuePool* valuePool) {
+    if (!valuePool) {
+        LOG(WARNING) <<  __func__ << ": Setting value pool to nullptr!";
+    }
+    mValuePool = valuePool;
+}
+
+void EmulatedVehicleServer::onFakeValueGenerated(const VehiclePropValue& value) {
+    LOG(DEBUG) << __func__ << ": " << toString(value);
+    auto updatedPropValue = getValuePool()->obtain(value);
+    if (updatedPropValue) {
+        updatedPropValue->timestamp = value.timestamp;
+        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
+        onPropertyValueFromCar(*updatedPropValue);
+    }
+}
+
+std::vector<VehiclePropConfig> EmulatedVehicleServer::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 EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
+    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));
+            onPropertyValueFromCar(
+                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
+            return StatusCode::INVALID_ARG;
+        }
+    }
+    return StatusCode::OK;
+}
+
+VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::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 EmulatedVehicleServer::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 EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value) {
+    // Some properties need to be treated non-trivially
+    switch (value.prop) {
+        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
+                    onPropertyValueFromCar(
+                            *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
+                    // Send back to HAL
+                    onPropertyValueFromCar(
+                            *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;
+        default:
+            break;
+    }
+
+    // In the real vhal, the value will be sent to Car ECU.
+    // We just pretend it is done here.
+    return StatusCode::OK;
+}
+
+StatusCode EmulatedVehicleServer::onSetPropertyFromVehicle(const VehiclePropValue& value) {
+    if (value.prop == kGenerateFakeDataControllingProperty) {
+        auto status = handleGenerateFakeDataRequest(value);
+        return status;
+    } else {
+        // Send back to HAL
+        onPropertyValueFromCar(value);
+        return StatusCode::OK;
+    }
+}
+
+EmulatedPassthroughConnectorPtr 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..d424cd8
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
@@ -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.
+ */
+
+#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 <vhal_v2_0/VehicleHal.h>
+
+#include "GeneratorHub.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+// Extension of the client/server interfaces for emulated vehicle
+
+class EmulatedVehicleClient : public IVehicleClient {
+  public:
+    // Type of callback function for handling the new property values
+    using PropertyCallBackType = std::function<void(const VehiclePropValue&)>;
+
+    // Method from IVehicleClient
+    void onPropertyValue(const VehiclePropValue& value) override;
+
+    // Request to change the value on the VEHICLE side (for testing)
+    virtual StatusCode setPropertyFromVehicle(const VehiclePropValue& value) = 0;
+
+    void registerPropertyValueCallback(PropertyCallBackType&& callback);
+
+  private:
+    PropertyCallBackType mPropCallback;
+};
+
+class EmulatedVehicleServer : public IVehicleServer {
+  public:
+    // Methods from IVehicleServer
+
+    std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
+
+    StatusCode onSetProperty(const VehiclePropValue& value) override;
+
+    // Process the request to change the value on the VEHICLE side (for testing)
+    StatusCode onSetPropertyFromVehicle(const VehiclePropValue& value);
+
+    // Set the Property Value Pool used in this server
+    void setValuePool(VehiclePropValuePool* valuePool);
+
+  private:
+    GeneratorHub* getGenerator();
+
+    VehiclePropValuePool* getValuePool() const;
+
+    void onFakeValueGenerated(const VehiclePropValue& value);
+
+    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
+
+    VehicleHal::VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
+
+    VehicleHal::VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action,
+                                                         int32_t keyCode, int32_t targetDisplay);
+
+    // private data members
+
+    GeneratorHub mGeneratorHub{
+            std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)};
+
+    VehiclePropValuePool* mValuePool{nullptr};
+};
+
+class EmulatedPassthroughConnector
+    : public IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer> {
+  public:
+    StatusCode setPropertyFromVehicle(const VehiclePropValue& value) override {
+        return this->onSetPropertyFromVehicle(value);
+    }
+};
+
+// Helper functions
+
+using EmulatedPassthroughConnectorPtr = std::unique_ptr<EmulatedPassthroughConnector>;
+
+EmulatedPassthroughConnectorPtr 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..6508efe 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,
+                                       EmulatedVehicleClient* 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)) {
+      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));
 }
 
 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
@@ -131,8 +133,39 @@
 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
     static constexpr bool shouldUpdateStatus = false;
 
+    // set the value from vehcile side, used in end to end test.
+    if (propValue.prop == kSetIntPropertyFromVehcileForTest) {
+        auto mockValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
+        mockValue->prop = propValue.value.int32Values[0];
+        mockValue->value.int32Values[0] = propValue.value.int32Values[1];
+        mockValue->timestamp = propValue.value.int64Values[0];
+        mockValue->areaId = propValue.areaId;
+        setPropertyFromVehicle(*mockValue);
+        return StatusCode::OK;
+    }
+
+    if (propValue.prop == kSetFloatPropertyFromVehcileForTest) {
+        auto mockValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
+        mockValue->prop = propValue.value.int32Values[0];
+        mockValue->value.floatValues[0] = propValue.value.floatValues[0];
+        mockValue->timestamp = propValue.value.int64Values[0];
+        mockValue->areaId = propValue.areaId;
+        setPropertyFromVehicle(*mockValue);
+        return StatusCode::OK;
+    }
+    if (propValue.prop == kSetBooleanPropertyFromVehcileForTest) {
+        auto mockValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
+        mockValue->prop = propValue.value.int32Values[1];
+        mockValue->value.int32Values[0] = propValue.value.int32Values[0];
+        mockValue->timestamp = propValue.value.int64Values[0];
+        mockValue->areaId = propValue.areaId;
+        setPropertyFromVehicle(*mockValue);
+        return StatusCode::OK;
+    }
+
     if (propValue.prop == kGenerateFakeDataControllingProperty) {
-        StatusCode status = handleGenerateFakeDataRequest(propValue);
+        // send the generator controlling request to the server
+        auto status = mVehicleClient->setPropertyFromVehicle(propValue);
         if (status != StatusCode::OK) {
             return status;
         }
@@ -156,29 +189,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 +208,25 @@
         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.
+     */
+    VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(propValue);
+    updatedPropValue->timestamp = elapsedRealtimeNano();
+
+    // Send the value to the vehicle server, the server will talk to the (real or emulated) car
+    auto setValueStatus = mVehicleClient->setProperty(*updatedPropValue);
+    if (setValueStatus != StatusCode::OK) {
+        return setValueStatus;
     }
 
-    getEmulatorOrDie()->doSetValueFromClient(propValue);
-    doHalEvent(getValuePool()->obtain(propValue));
+    if (!mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
+        return StatusCode::INTERNAL_ERROR;
+    }
+
+    getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
+    doHalEvent(std::move(updatedPropValue));
 
     return StatusCode::OK;
 }
@@ -324,144 +347,19 @@
 }
 
 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;
-    }
+    return mVehicleClient->setPropertyFromVehicle(propValue) == 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) {
+    static constexpr bool shouldUpdateStatus = true;
     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, shouldUpdateStatus)) {
+        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..98315ec 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,
+                       EmulatedVehicleClient* client);
     ~EmulatedVehicleHal() = default;
 
     //  Methods from VehicleHal
@@ -66,10 +68,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);
 
     void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
     bool isContinuousProperty(int32_t propId) const;
@@ -85,7 +84,7 @@
     VehiclePropertyStore* mPropStore;
     std::unordered_set<int32_t> mHvacPowerProps;
     RecurrentTimer mRecurrentTimer;
-    GeneratorHub mGeneratorHub;
+    EmulatedVehicleClient* mVehicleClient;
 };
 
 }  // impl
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..068333c 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
@@ -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/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..04df5a8 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,7 +15,6 @@
  */
 
 syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
 
 package emulator;
 
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..7ce3c32
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
@@ -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.
+ */
+
+syntax = "proto2";
+
+package emulator;
+
+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 {
+    required VehicleHalStatusCode status_code      = 1;
+}
+
+service VehicleServer {
+    rpc GetAllPropertyConfig(google.protobuf.Empty) returns (stream VehiclePropConfig) {}
+
+    // Change the property value of the vehicle
+    rpc SetProperty(VehiclePropValue) returns (VehicleHalCallStatus) {}
+
+    // Start a vehicle property value stream
+    rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValue) {}
+}
+
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 0f20dd1..24fcf76 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,
 
@@ -799,7 +814,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 +1091,7 @@
      *
      * @change_mode VehiclePropertyChangeMode:STATIC
      * @access VehiclePropertyAccess:READ
+     * @data_enum VehicleHvacFanDirection
      */
     HVAC_FAN_DIRECTION_AVAILABLE = (
         0x0511
@@ -1118,6 +1134,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
      *
@@ -2321,6 +2349,116 @@
         | 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),
+
+};
+
+/**
+ * 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 +2596,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 {
@@ -2499,7 +2647,7 @@
      * power controller must change power state to this state to shutdown
      * system.
      *
-     * int32Values[1] : one of enum_vehicle_ap_power_state_shutdown_param_type
+     * int32Values[1] : one of VehicleApPowerStateShutdownParam
      *
      * SHUTDOWN_PRPARE may be requested from either WAIT_FOR_VHAL or ON states.
      */
@@ -2531,6 +2679,11 @@
 
     /** 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 {
@@ -2723,6 +2876,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,
@@ -3541,4 +3696,3 @@
 enum VmsPublisherInformationIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex {
     PUBLISHER_ID = 1,
 };
-
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/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index b8c40e9..ac32c95 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,17 @@
     }
 
     Mutex::Autolock lock(mLock);
-    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;
     }
 
-    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 +240,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 +299,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 +319,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 +334,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.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/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/metadata/3.5/Android.bp b/camera/metadata/3.5/Android.bp
new file mode 100644
index 0000000..4ebd069
--- /dev/null
+++ b/camera/metadata/3.5/Android.bp
@@ -0,0 +1,19 @@
+// 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..b9451c8
--- /dev/null
+++ b/camera/metadata/3.5/types.hal
@@ -0,0 +1,74 @@
+/*
+ * 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.availableBokehCapabilities [static, int32[], public]
+     *
+     * <p>The list of bokeh modes that are supported by this camera device, and each bokeh mode's
+     * maximum streaming (non-stall) size with bokeh effect.</p>
+     */
+    ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+
+    /** android.control.bokehMode [dynamic, enum, public]
+     *
+     * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+     */
+    ANDROID_CONTROL_BOKEH_MODE,
+
+    ANDROID_CONTROL_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.request.availableCapabilities enumeration values added since v3.4
+ * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
+ */
+enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
+        @3.4::CameraMetadataEnumAndroidRequestAvailableCapabilities {
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,
+};
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index 95e27fd..9203b8d 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",
@@ -51,6 +52,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@3.3-impl",
@@ -93,6 +95,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 +141,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/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 2c3ed37..d14ccfa 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -41,14 +41,11 @@
 	"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.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..69ec0d9 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -26,45 +26,43 @@
 
 #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/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/hidl/manager/1.0/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
 #include <cutils/properties.h>
 #include <fmq/MessageQueue.h>
 #include <grallocusage/GrallocUsageConversion.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/BufferQueue.h>
 #include <gui/Surface.h>
+#include <gtest/gtest.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;
@@ -286,27 +284,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,12 +524,13 @@
 }
 
 // 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;
@@ -622,7 +600,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 +617,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>;
@@ -776,6 +754,7 @@
             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 verifyRecommendedConfigs(const CameraMetadata& metadata);
     void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
     void verifyMonochromeCameraResult(
@@ -799,7 +778,7 @@
 
     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 getJpegBufferSize(camera_metadata_t *staticMeta,
@@ -865,6 +844,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 +859,8 @@
         // return from HAL but framework.
         ::android::Vector<StreamBuffer> resultOutputBuffers;
 
+        std::unordered_set<std::string> expectedPhysicalResults;
+
         InFlightRequest() :
                 shutterTimestamp(0),
                 errorCodeValid(false),
@@ -907,6 +890,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
@@ -1124,6 +1125,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 +1259,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 +1301,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 +1308,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 +1401,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 +1425,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 +1434,17 @@
         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,
+            mParent->allocateGraphicBuffer(stream.v3_2.width, stream.v3_2.height,
                     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 +1470,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,6 +1490,10 @@
         ALOGE("%s: unknown buffer ID %" PRIu64, __FUNCTION__, buf.bufferId);
         ADD_FAILURE();
     }
+    if (!hasOutstandingBuffersLocked()) {
+        l.unlock();
+        mFlushedCondition.notify_one();
+    }
     return Void();
 }
 
@@ -1506,7 +1554,7 @@
 }
 
 // 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 +1579,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 +1596,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 +1609,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 +1627,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,
@@ -1607,7 +1655,7 @@
 }
 
 // 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) {
@@ -1649,7 +1697,7 @@
 
 // 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) {
@@ -1719,7 +1767,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 +1815,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 +1835,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 +1860,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 +1885,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 +1915,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 +1964,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 +1984,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 +2011,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 +2034,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 +2112,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 +2136,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 +2197,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 +2243,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 +2298,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 +2346,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,7 +2438,7 @@
 
 // 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) {
@@ -2456,7 +2504,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;
@@ -2594,7 +2642,7 @@
 }
 
 // Check dump functionality.
-TEST_F(CameraHidlTest, dumpState) {
+TEST_P(CameraHidlTest, dumpState) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     Return<void> ret;
 
@@ -2659,7 +2707,7 @@
 }
 
 // Open, dumpStates, then close
-TEST_F(CameraHidlTest, openClose) {
+TEST_P(CameraHidlTest, openClose) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     Return<void> ret;
 
@@ -2752,7 +2800,7 @@
 
 // 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) {
@@ -2842,7 +2890,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;
 
@@ -2950,7 +2998,7 @@
 }
 
 // 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;
 
@@ -3146,7 +3194,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;
@@ -3312,7 +3360,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,
@@ -3431,7 +3479,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;
@@ -3554,7 +3602,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) {
@@ -3759,7 +3807,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;
@@ -3880,7 +3928,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 +4096,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 +4165,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 +4205,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 +4284,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 +4343,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 +4501,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,
@@ -4528,7 +4576,7 @@
 
 // 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 +4641,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 +4784,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 +4829,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 +4837,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,
@@ -5315,10 +5363,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);
@@ -5493,9 +5541,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);
                     }
@@ -5772,6 +5820,101 @@
             ADD_FAILURE() << "Get Heic maxJpegAppSegmentsCount failed!";
         }
     }
+
+    verifyBokehCharacteristics(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 hasBokehCharacteristicsKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasBokehCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES) != entry.data.i32+entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
+    }
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES, &entry);
+    bool hasAvailableBokehCaps = (0 == retcode && entry.count > 0);
+
+    // Bokeh keys must all be available, or all be unavailable.
+    bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehCharacteristicsKey &&
+            !hasAvailableBokehCaps;
+    if (noBokeh) {
+        return;
+    }
+    bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehCharacteristicsKey &&
+            hasAvailableBokehCaps;
+    ASSERT_TRUE(hasBokeh);
+
+    // Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS.
+    ASSERT_TRUE(entry.count == 6 || entry.count == 9);
+    bool hasOffMode = false;
+    bool hasStillCaptureMode = false;
+    bool hasContinuousMode = false;
+    std::vector<AvailableStream> outputStreams;
+    ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams));
+    for (int i = 0; i < entry.count; i += 3) {
+        int32_t mode = entry.data.i32[i];
+        int32_t maxWidth = entry.data.i32[i+1];
+        int32_t maxHeight = entry.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;
+                break;
+            case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS:
+                hasContinuousMode = true;
+                break;
+            default:
+                ADD_FAILURE() << "Invalid bokehMode advertised: " << mode;
+                break;
+        }
+
+        if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) {
+            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);
+        }
+    }
+    ASSERT_TRUE(hasOffMode);
+    ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode);
 }
 
 void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars,
@@ -6144,68 +6287,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 +6415,7 @@
     }
 }
 
-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;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, CameraHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraProvider::descriptor)),
+        android::hardware::PrintInstanceNameToString);
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..7e5a61a 100644
--- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
+++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
@@ -27,8 +27,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 +254,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 +356,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 +443,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 +533,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 +551,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..6f2d292
--- /dev/null
+++ b/common/aidl/Android.bp
@@ -0,0 +1,21 @@
+aidl_interface {
+    name: "vintf-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 2bd2c93..f5acdd4 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -49,6 +49,13 @@
             <instance>default</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.vehicle</name>
         <version>2.0</version>
@@ -123,7 +130,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>
@@ -155,7 +162,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.drm</name>
-        <version>1.0-2</version>
+        <version>1.0-3</version>
         <interface>
             <name>ICryptoFactory</name>
             <regex-instance>.*</regex-instance>
@@ -189,7 +196,7 @@
          - test DeviceManifestTest#GnssHalVersionCompatibility.
         -->
         <version>1.1</version>
-        <version>2.0</version>
+        <version>2.0-1</version>
         <interface>
             <name>IGnss</name>
             <instance>default</instance>
@@ -197,8 +204,8 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.allocator</name>
-        <version>2.0</version>
         <version>3.0</version>
+        <version>4.0</version>
         <interface>
             <name>IAllocator</name>
             <instance>default</instance>
@@ -206,7 +213,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>
@@ -214,8 +221,8 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.mapper</name>
-        <version>2.1</version>
         <version>3.0</version>
+        <version>4.0</version>
         <interface>
             <name>IMapper</name>
             <instance>default</instance>
@@ -280,7 +287,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>
@@ -401,7 +408,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>
@@ -497,7 +504,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>
@@ -505,7 +512,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>
@@ -513,7 +520,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/current.txt b/current.txt
index 62153b1..1fe17d5 100644
--- a/current.txt
+++ b/current.txt
@@ -578,6 +578,13 @@
 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
 b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
 eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
 f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types
@@ -590,21 +597,60 @@
 fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
 
 # HALs released in Android R
+e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types
+dd3e9280be60a5e042331c1046d13938e2cc323dc4b267cc74d544bf62fc0314 android.hardware.audio@6.0::IDevice
+2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory
+bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice
+fd1f1b29f26b42e886220f04a08086c00e5ade9d7b53f095438e578ab9d42a93 android.hardware.audio@6.0::IStream
+2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn
+78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut
+997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback
+1349686814402fa10f711cc5763bc629aafc64a5f5843b4b21b8cd86ffb923e6 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
+461b1114cb35d89f87e5694e0792ba53c112a7fa9a14d9b95188cf9c4764be23 android.hardware.audio.effect@6.0::IBassBoostEffect
+8bc597d166e07e9eba633267fc2872c4c53d13d3f0025b778c98e13324a165de android.hardware.audio.effect@6.0::IDownmixEffect
+9ee022c81e79da6051fde0836c1c1c4d5414e0c9a6cccc0ce17a90346ceb1391 android.hardware.audio.effect@6.0::IEffect
+75c99a70577d543359910a0b378bcbf5a0d6076712e58e6864cd8803f76c8684 android.hardware.audio.effect@6.0::IEffectBufferProviderCallback
+b138d519696f23af2c7cb92c532178c35f4b3a5c1b689260b1c308fe00249f8b android.hardware.audio.effect@6.0::IEffectsFactory
+dd377f404a8e71f6191d295e10067db629b0f0c28e594af906f2bea5d87fe2cc android.hardware.audio.effect@6.0::IEnvironmentalReverbEffect
+455e085e136767302ec34d02b51a085c310e79bf500b76dda7c96a7f3637f11a android.hardware.audio.effect@6.0::IEqualizerEffect
+24b5e107a0cbd2b322f764a4d5f7fb8b5d8c337a060b9a4a26b9af050c57b5d0 android.hardware.audio.effect@6.0::ILoudnessEnhancerEffect
+4aae0a13f53a8ce20fad372de2d1d864a0bae194b0f1b1d2c090367af8615af2 android.hardware.audio.effect@6.0::INoiseSuppressionEffect
+5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect
+282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect
+0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect
 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
+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
+66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory
+994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory
+3dacec7801968e1e4479724dc0180442d9e915466bff051f80996266b1a51c2c android.hardware.gnss@2.1::IGnss
+ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback
+ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration
+5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement
+0bfb291708dd4a7c6ec6b9883e2b8592357edde8d7e962ef83918e4a2154ce69 android.hardware.gnss@2.1::IGnssMeasurementCallback
 ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
 26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
 db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types
 c228aaa27f66c48e147159a4f4996c5273191fece1b08de31bd171c61334855e android.hardware.keymaster@4.1::IKeymasterDevice
 adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
 7a04ea5595ed418ca3e91c28b8bd7353dd988be9be7b0c8c9e64fb4b77bd4523 android.hardware.keymaster@4.1::types
+df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
+a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice
-4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel
+258825966435b3ed08832055bb736d81516013e405f161d9ccde9a90cfcdde83 android.hardware.neuralnetworks@1.3::IPreparedModel
 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
 cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
+03d37dfebbc27b13adce1ed6389ac483bf7cf32488ca14037c5569bc3e903e4f android.hardware.wifi.hostapd@1.2::IHostapd
+2defa258951e25a132aaeb36e3febe6f41bf9c6dbb1b1ebdf0b41708ab4e107e 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
@@ -618,3 +664,5 @@
 b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
 7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse
+c411dc16855fcb786cd5e08fe2889acbd72fd54217bd27fe0373813de230ce5f android.hardware.soundtrigger@2.3::types
+5abad7b54d3400fab633cb7a36ffc1747e037bf805d3d9e3517cb6aabf26b002 android.hardware.soundtrigger@2.3::ISoundTriggerHw
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/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/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index 1a80ecf..6183a1a 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -22,6 +22,7 @@
 #include <log/log.h>
 
 #include <chrono>
+#include <cmath>
 #include <condition_variable>
 #include <mutex>
 
@@ -403,6 +404,34 @@
 }
 
 /*
+ * InjectSeedLocation:
+ * Injects a seed location and ensures the injected seed location is not fused in the resulting
+ * GNSS location.
+ */
+TEST_P(GnssHalTest, InjectSeedLocation) {
+    // An arbitrary position in North Pacific Ocean (where no VTS labs will ever likely be located).
+    const double seedLatDegrees = 32.312894;
+    const double seedLngDegrees = -172.954117;
+    const float seedAccuracyMeters = 150.0;
+
+    auto result = gnss_hal_->injectLocation(seedLatDegrees, seedLngDegrees, seedAccuracyMeters);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    StartAndGetSingleLocation(false);
+
+    // Ensure we don't get a location anywhere within 111km (1 degree of lat or lng) of the seed
+    // location.
+    EXPECT_TRUE(std::abs(last_location_.latitudeDegrees - seedLatDegrees) > 1.0 ||
+                std::abs(last_location_.longitudeDegrees - seedLngDegrees) > 1.0);
+
+    StopAndClearLocations();
+
+    auto resultVoid = gnss_hal_->deleteAidingData(IGnss::GnssAidingData::DELETE_POSITION);
+    ASSERT_TRUE(resultVoid.isOk());
+}
+
+/*
  * GetAllExtentions:
  * Tries getting all optional extensions, and ensures a valid return
  *   null or actual extension, no crash.
diff --git a/gnss/1.1/default/Android.bp b/gnss/1.1/default/Android.bp
index 95bd7f3..9c498d5 100644
--- a/gnss/1.1/default/Android.bp
+++ b/gnss/1.1/default/Android.bp
@@ -14,6 +14,8 @@
         "libhidlbase",
         "libutils",
         "liblog",
+        "android.hardware.gnss@2.1",
+        "android.hardware.gnss@2.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@1.0",
     ],
diff --git a/gnss/1.1/default/Gnss.cpp b/gnss/1.1/default/Gnss.cpp
index 4abe707..5043649 100644
--- a/gnss/1.1/default/Gnss.cpp
+++ b/gnss/1.1/default/Gnss.cpp
@@ -44,7 +44,7 @@
             auto svStatus = this->getMockSvStatus();
             this->reportSvStatus(svStatus);
 
-            auto location = Utils::getMockLocation();
+            auto location = Utils::getMockLocationV1_0();
             this->reportLocation(location);
 
             std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
@@ -197,14 +197,14 @@
 Return<GnssSvStatus> Gnss::getMockSvStatus() const {
     std::unique_lock<std::recursive_mutex> lock(mGnssConfiguration->getMutex());
     GnssSvInfo mockGnssSvInfoList[] = {
-            Utils::getSvInfo(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5),
-            Utils::getSvInfo(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5),
-            Utils::getSvInfo(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0),
-            Utils::getSvInfo(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0),
-            Utils::getSvInfo(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0),
-            Utils::getSvInfo(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0),
-            Utils::getSvInfo(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0),
-            Utils::getSvInfo(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)};
+            Utils::getMockSvInfoV1_0(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5),
+            Utils::getMockSvInfoV1_0(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5),
+            Utils::getMockSvInfoV1_0(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0),
+            Utils::getMockSvInfoV1_0(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0),
+            Utils::getMockSvInfoV1_0(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0),
+            Utils::getMockSvInfoV1_0(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0),
+            Utils::getMockSvInfoV1_0(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0),
+            Utils::getMockSvInfoV1_0(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)};
 
     GnssSvStatus svStatus = {.numSvs = sizeof(mockGnssSvInfoList) / sizeof(GnssSvInfo)};
     for (uint32_t i = 0; i < svStatus.numSvs; i++) {
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index cc34290..bdd02d2 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -30,5 +30,5 @@
     shared_libs: [
         "android.hardware.gnss.measurement_corrections@1.0",
     ],
-    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..24de37d 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);
         }
     }
 }
@@ -177,19 +175,23 @@
     return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
 }
 
-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 +209,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..e0d8b54 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,8 @@
 
 #include <gnss_hal_test.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 #include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+#include <gtest/gtest.h>
 
 using android::hardware::hidl_vec;
 
@@ -39,18 +38,18 @@
  *
  * Empty test fixture to verify basic Setup & Teardown
  */
-TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
 
 /*
  * TestGnssMeasurementCallback:
  * Gets the GnssMeasurementExtension and verify that it returns an actual extension.
  */
-TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
+TEST_P(GnssHalTest, TestGnssMeasurementCallback) {
     auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
     ASSERT_TRUE(gnssMeasurement_1_1.isOk());
     auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
     ASSERT_TRUE(gnssMeasurement_1_0.isOk());
-    if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
+    if (gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
         sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
         sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
         // At least one interface must be non-null.
@@ -65,7 +64,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 +77,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 +94,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 +130,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 +217,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 +226,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 +242,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 +273,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 +313,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 +361,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 +390,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 +429,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 +460,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 +469,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 +502,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 +521,10 @@
  * 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 (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..8ca3f68 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -20,12 +20,13 @@
 #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_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(
-        GnssHidlEnvironment::Instance()->getServiceName<IGnss>());
+    gnss_hal_ = IGnss::getService(GetParam());
     ASSERT_NE(gnss_hal_, nullptr);
 
     SetUpGnssCallback();
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 90a7866..4f7b87a 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;
@@ -252,61 +190,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..c442cc6 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,7 @@
  * 2. constellation is valid.
  * 3. state is valid.
  */
-TEST_F(GnssHalTest, TestGnssMeasurementFields) {
+TEST_P(GnssHalTest, TestGnssMeasurementFields) {
     const int kFirstGnssMeasurementTimeoutSeconds = 10;
 
     auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -234,7 +235,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 +259,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 +270,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 +291,7 @@
  * 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 (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) {
         return;
     }
@@ -318,7 +319,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 +349,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 +384,7 @@
     iGnssMeasurement->close();
 }
 
-TEST_F(GnssHalTest, TestGnssLocationElapsedRealtime) {
+TEST_P(GnssHalTest, TestGnssLocationElapsedRealtime) {
     StartAndCheckFirstLocation();
 
     ASSERT_TRUE((int)gnss_cb_->last_location_.elapsedRealtime.flags <=
@@ -399,7 +400,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 +411,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 +423,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 +454,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) {
+        EXPECT_LE(location_called_count, i);
+        if (location_called_count != i) {
             ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
-                  locationCalledCount, i);
+                  location_called_count, i);
         }
 
         if (!gnss_cb_->location_cbq_.retrieve(
@@ -513,7 +514,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 +600,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 (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
         ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
               " not supported.");
@@ -626,7 +627,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 +745,7 @@
  * 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 (!(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..8b0c374
--- /dev/null
+++ b/gnss/2.1/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.gnss@2.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IGnss.hal",
+        "IGnssCallback.hal",
+        "IGnssMeasurement.hal",
+        "IGnssMeasurementCallback.hal",
+        "IGnssConfiguration.hal",
+    ],
+    interfaces: [
+        "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..2d63392
--- /dev/null
+++ b/gnss/2.1/IGnss.hal
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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::IGnss;
+
+import IGnssCallback;
+import IGnssMeasurement;
+import IGnssConfiguration;
+
+/**
+ * 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.
+     *
+     * At least one of getExtensionGnssMeasurement(), getExtensionGnssMeasurement_1_1(),
+     * getExtensionGnssMeasurement_2_0(), and getExtensionGnssMeasurement_2_1() methods must return
+     * a non-null handle, and the other methods must return nullptr.
+     *
+     * @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
+     */
+    getExtensionGnssMeasurement_2_1() generates (IGnssMeasurement gnssMeasurementIface);
+
+    /**
+     * This method returns the IGnssConfiguration interface.
+     *
+     * At least one of getExtensionGnssConfiguration(), getExtensionGnssConfiguration_1_1(),
+     * getExtensionGnssConfiguration_2_0(), and getExtensionGnssConfiguration_2_1() methods must
+     * return a non-null handle, and the other methods must return nullptr.
+     *
+     * @return gnssConfigurationIface Handle to the IGnssConfiguration interface.
+     */
+    getExtensionGnssConfiguration_2_1() generates (IGnssConfiguration gnssConfigurationIface);
+};
\ No newline at end of file
diff --git a/gnss/2.1/IGnssCallback.hal b/gnss/2.1/IGnssCallback.hal
new file mode 100644
index 0000000..da70742
--- /dev/null
+++ b/gnss/2.1/IGnssCallback.hal
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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 {
+
+    /** 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..8360ba9
--- /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);
+};
\ No newline at end of file
diff --git a/gnss/2.1/IGnssMeasurement.hal b/gnss/2.1/IGnssMeasurement.hal
new file mode 100644
index 0000000..d2c76e6
--- /dev/null
+++ b/gnss/2.1/IGnssMeasurement.hal
@@ -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.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..ca6175f
--- /dev/null
+++ b/gnss/2.1/IGnssMeasurementCallback.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 @1.0::IGnssMeasurementCallback;
+import @1.1::IGnssMeasurementCallback;
+import @2.0::IGnssMeasurementCallback;
+import @2.0::ElapsedRealtime;
+
+/** The callback interface to report measurements from the HAL. */
+interface IGnssMeasurementCallback extends @2.0::IGnssMeasurementCallback {
+
+    /**
+     * Extends a GNSS Measurement, adding a basebandCN0DbHz.
+     */
+    struct GnssMeasurement {
+        /**
+         * GNSS measurement information for a single satellite and frequency, as in the 2.0 version
+         * of the HAL.
+         */
+        @2.0::IGnssMeasurementCallback.GnssMeasurement 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.
+         */
+        double basebandCN0DbHz;
+    };
+
+    /**
+     * Complete set of GNSS Measurement data, same as 2.0 with additional double (i.e.,
+     * basebandCN0DbHz) 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..57233aa
--- /dev/null
+++ b/gnss/2.1/default/Android.bp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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",
+        "GnssMeasurement.cpp",
+        "GnssConfiguration.cpp",
+        "service.cpp"
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libutils",
+        "liblog",
+        "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..fd7a9df
--- /dev/null
+++ b/gnss/2.1/default/Gnss.cpp
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "GnssMeasurement.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<V2_1::IGnssCallback> Gnss::sGnssCallback_2_1 = nullptr;
+sp<V2_0::IGnssCallback> Gnss::sGnssCallback_2_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);
+
+            const auto location = Utils::getMockLocationV2_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>&) {
+    // TODO implement
+    return bool{};
+}
+
+Return<void> Gnss::cleanup() {
+    // TODO implement
+    return Void();
+}
+
+Return<bool> Gnss::injectTime(int64_t, int64_t, int32_t) {
+    // TODO implement
+    return bool{};
+}
+
+Return<bool> Gnss::injectLocation(double, double, float) {
+    // TODO implement
+    return bool{};
+}
+
+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, uint32_t,
+                                   uint32_t) {
+    // TODO implement
+    return bool{};
+}
+
+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() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssMeasurement>{};
+}
+
+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() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssDebug>{};
+}
+
+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>&) {
+    // TODO implement
+    return bool{};
+}
+
+Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode,
+                                       V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t,
+                                       uint32_t, bool) {
+    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&) {
+    // TODO implement
+    return bool{};
+}
+
+// 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.0";
+    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() {
+    // TODO implement
+    return ::android::sp<measurement_corrections::V1_0::IMeasurementCorrections>{};
+}
+
+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 implement
+    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_0::IGnssCallback::Capabilities;
+    const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
+                              Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST;
+    auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_0(capabilities);
+    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;
+}
+
+void Gnss::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    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 V2_0::GnssLocation& location) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sGnssCallback_2_1 == nullptr) {
+        ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
+        return;
+    }
+    auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
+    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/Gnss.h b/gnss/2.1/default/Gnss.h
new file mode 100644
index 0000000..7917bbd
--- /dev/null
+++ b/gnss/2.1/default/Gnss.h
@@ -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.
+ */
+
+#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 "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;
+
+  private:
+    void reportLocation(const V2_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;
+    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/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/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp
new file mode 100644
index 0000000..ebfa7dd
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurement.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 = 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 = 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>&, bool) {
+    // TODO implement
+    return V1_0::IGnssMeasurement::GnssMeasurementStatus{};
+}
+
+// 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 = 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) {
+            auto measurement = Utils::getMockMeasurementV2_1();
+            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_1& data) {
+    ALOGD("reportMeasurement()");
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sCallback == nullptr) {
+        ALOGE("%s: GnssMeasurement::sCallback is null.", __func__);
+        return;
+    }
+    auto ret = sCallback->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..ee32903
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurement.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 ::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_1&);
+
+    static sp<IGnssMeasurementCallback> 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
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/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..8340499
--- /dev/null
+++ b/gnss/2.1/vts/functional/Android.bp
@@ -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.
+//
+
+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.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..22268f6
--- /dev/null
+++ b/gnss/2.1/vts/functional/gnss_hal_test.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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::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();
+}
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..6b67e13
--- /dev/null
+++ b/gnss/2.1/vts/functional/gnss_hal_test.h
@@ -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.
+ */
+
+#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::V1_0::GnssLocationFlags;
+using android::hardware::gnss::V2_0::GnssConstellationType;
+using android::hardware::gnss::V2_1::IGnss;
+
+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;
+
+      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;
+    };
+
+    /*
+     * 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..2c51717
--- /dev/null
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "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;
+
+/*
+ * 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
+ */
+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);
+    }
+
+    iGnssMeasurement->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);
+}
\ 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..ccb91b1 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,31 +24,193 @@
 namespace common {
 
 using GnssSvFlags = V1_0::IGnssCallback::GnssSvFlags;
+using GnssMeasurementFlags = V1_0::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;
 
-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],
+            .basebandCN0DbHz = 25.0,
+    };
+    hidl_vec<V2_1::IGnssMeasurementCallback::GnssMeasurement> measurements(1);
+    measurements[0] = gnssMeasurementV2_1;
+    GnssDataV2_1 gnssDataV2_1 = {
+            .measurements = measurements,
+            .clock = gnssDataV2_0.clock,
+            .elapsedRealtime = gnssDataV2_0.elapsedRealtime,
+    };
+    return gnssDataV2_1;
+}
+
+GnssDataV2_0 Utils::getMockMeasurementV2_0() {
+    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 = 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;
 }
 
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index 47c8812..e0c61a4 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -18,20 +18,34 @@
 #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;
+
 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);
 };
 
 }  // namespace common
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/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..fcd4efc
--- /dev/null
+++ b/graphics/common/aidl/Android.bp
@@ -0,0 +1,24 @@
+aidl_interface {
+    name: "vintf-graphics-common",
+    host_supported: true,
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "android/hardware/graphics/common/*.aidl",
+    ],
+    stability: "vintf",
+    imports: [
+        "vintf-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/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
new file mode 100644
index 0000000..81a21ab
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
@@ -0,0 +1,682 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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, // deprecated, use V0_SRGB_LINEAR
+
+    V0_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.
+     */
+    V0_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, // deprecated, use V0_SRGB
+
+    V0_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.
+     */
+    V0_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, BT.601 transfer and BT.601_625 standard.
+     */
+    JFIF = 2 << 16 | 3 << 22 | 1 << 27, // deprecated, use V0_JFIF
+
+    V0_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, BT.601 transfer and BT.601_625 standard.
+     */
+    BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_625
+
+    V0_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, BT.601 transfer and BT.601_525 standard.
+     */
+    BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_525
+
+    V0_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, BT.709 transfer and BT.709 standard.
+     */
+    BT709 = 1 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT709
+
+    V0_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, BT.709 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, BT.709 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,
+}
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..168028d
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+    /**
+     * Some buffer producers require extra padding to their output buffer; therefore the
+     * physical size of the native buffer will be larger than its logical size.
+     * The crop rectangle determines the offset and logical size of the buffer that should be
+     * read by consumers.
+     *
+     * The crop rectangle is measured in samples and is relative to the offset of the
+     * plane. Valid crop rectangles are within the boundaries of the plane:
+     * [0, 0, widthInSamples, heightInSamples].
+     *
+     * The default crop rectangle is a rectangle the same size as the plane:
+     * [0, 0, widthInSamples, heightInSamples].
+     */
+    Rect crop;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/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..18c4a2e
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponentType.aidl
@@ -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.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,
+
+    /* 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/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
new file mode 100644
index 0000000..060d12c
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -0,0 +1,282 @@
+/**
+ * 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.
+ */
+@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 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 = 16,
+
+    /**
+     * 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
+     * dataspaces. 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 = 17,
+}
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/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..53b9202 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>
@@ -195,7 +195,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) {
@@ -226,7 +226,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) {
@@ -369,7 +369,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) {
@@ -489,7 +489,7 @@
         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) {
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..cdc0f35 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -27,10 +27,21 @@
         "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",
+    ],
+    export_static_lib_headers: [
+        "VtsHalHidlTargetTestBase",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@3.0-vts",
+        "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..a8e1480 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -317,11 +317,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 +334,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 +363,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 +391,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 +401,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/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/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..35162a6 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
@@ -93,17 +93,18 @@
     }
 
    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);
         writeFloat(color.b);
         writeFloat(color.a);
     }
+
+  private:
+    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);
+    }
 };
 
 // This class helps parse a command queue.  Note that all sizes/lengths are in
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..d9f6226 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 {
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/hal/include/composer-hal/2.2/ComposerResources.h b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
similarity index 90%
rename from graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
rename to graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
index 85b6651..33012e9 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
+++ b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
@@ -20,7 +20,7 @@
 #warning "ComposerResources.h included without LOG_TAG"
 #endif
 
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
 
 namespace android {
 namespace hardware {
@@ -33,7 +33,7 @@
 using V2_1::hal::ComposerHandleImporter;
 
 class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource {
-   public:
+  public:
     ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
                             uint32_t outputBufferCacheSize)
         : V2_1::hal::ComposerDisplayResource(type, importer, outputBufferCacheSize),
@@ -47,12 +47,12 @@
                                               outReplacedHandle);
     }
 
-   protected:
+  protected:
     ComposerHandleCache mReadbackBufferCache;
 };
 
 class ComposerResources : public V2_1::hal::ComposerResources {
-   public:
+  public:
     static std::unique_ptr<ComposerResources> create() {
         auto resources = std::make_unique<ComposerResources>();
         return resources->init() ? std::move(resources) : nullptr;
@@ -60,7 +60,7 @@
 
     Error getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
                                    const native_handle_t** outHandle,
-                                   ReplacedBufferHandle* outReplacedHandle) {
+                                   ReplacedHandle* outReplacedHandle) {
         // import buffer
         const native_handle_t* importedHandle;
         Error error = mImporter.importBuffer(rawHandle, &importedHandle);
@@ -76,7 +76,7 @@
             return Error::BAD_DISPLAY;
         }
         ComposerDisplayResource& displayResource =
-            *static_cast<ComposerDisplayResource*>(iter->second.get());
+                *static_cast<ComposerDisplayResource*>(iter->second.get());
 
         // update cache
         const native_handle_t* replacedHandle;
@@ -90,9 +90,9 @@
         return Error::NONE;
     }
 
-   protected:
+  protected:
     std::unique_ptr<V2_1::hal::ComposerDisplayResource> createDisplayResource(
-        ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
+            ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
         return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
     }
 };
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index dd979cb..5432882 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -19,26 +19,36 @@
     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",
+        "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: [
+        "VtsHalHidlTargetTestBase",
         "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..93b67f0 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -182,17 +182,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 +207,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..e2f2670
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.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.
+ */
+
+#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);
+}
+
+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;
+    mRenderEngine->drawLayers(mDisplaySettings, mCompositionLayers,
+                              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..5d22305 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
@@ -44,9 +44,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..7519a64
--- /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 ::testing::VtsHalHidlTargetTestBase {
+  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..b936cab
--- /dev/null
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
@@ -0,0 +1,70 @@
+/*
+ * 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>
+
+#include <VtsHalHidlTargetTestBase.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() = default;
+
+    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..f987516 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -19,18 +19,25 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
-        "VtsHalGraphicsComposerV2_2TargetTest.cpp",
+        "VtsHalGraphicsComposerV2_2TargetTest.cpp"
     ],
 
     // 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,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",
+        "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..044bd96 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<string, 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..3dfda19 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
@@ -120,17 +120,18 @@
     }
 
    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;
         mDataWritten += numElements;
         mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0;
     }
+
+  private:
+    void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
+        V2_1::CommandWriterBase::beginCommand(
+                static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
+    }
 };
 
 // This class helps parse a command queue.  Note that all sizes/lengths are in
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..329dbed 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 {
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index 2fe6cd6..f65a9c4 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -21,22 +21,17 @@
         "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",
+    ],
+    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/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
index 0d4e5b8..e5ac842 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
@@ -49,12 +49,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..fea24a1
--- /dev/null
+++ b/graphics/composer/2.4/IComposerCallback.hal
@@ -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.
+ */
+
+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);
+};
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
new file mode 100644
index 0000000..f23536c
--- /dev/null
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -0,0 +1,175 @@
+/*
+ * 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 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,
+    };
+
+    /**
+     * 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,
+    };
+
+    /**
+     * 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;
+    };
+
+    /**
+     * 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.
+     * @return timeline is the timeline for the vsync period change.
+     */
+    setActiveConfigWithConstraints(Display display, Config config,
+        VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints)
+        generates (Error error, VsyncPeriodChangeTimeline timeline);
+};
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..cb391be
--- /dev/null
+++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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:
+    CommandWriterBase(uint32_t initialMaxSize) : V2_3::CommandWriterBase(initialMaxSize) {}
+};
+
+// 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..3ee4e19
--- /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.3-command-buffer",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.3-hal",
+        "android.hardware.graphics.composer@2.3-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..4160ed9
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -0,0 +1,164 @@
+/*
+ * 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/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());
+        }
+
+      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();
+    }
+
+    static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
+        auto client = std::make_unique<ComposerClientImpl>(hal);
+        return client->init() ? std::move(client) : nullptr;
+    }
+
+  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;
+    std::unique_ptr<HalEventCallback> mHalEventCallback_2_4;
+    using BaseType2_1::mResources;
+};
+
+}  // 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/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
new file mode 100644
index 0000000..89dbe66
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -0,0 +1,77 @@
+/*
+ * 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 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;
+};
+
+}  // 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..d59d0d5
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -0,0 +1,243 @@
+/*
+ * 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_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, this,
+                reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
+        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));
+    }
+
+    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, 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);
+
+        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;
+    }
+
+  protected:
+    bool initDispatch() override {
+        if (!BaseType2_3::initDispatch()) {
+            return false;
+        }
+
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CONNECTION_TYPE,
+                                   &mDispatch.getDisplayConnectionType);
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD,
+                                   &mDispatch.getDisplayVsyncPeriod);
+        this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS,
+                                   &mDispatch.setActiveConfigWithConstraints);
+        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);
+    }
+
+  private:
+    struct {
+        HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType;
+        HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod;
+        HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS setActiveConfigWithConstraints;
+    } 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..b87a116
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -0,0 +1,42 @@
+//
+// 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",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetTestBase",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3-vts",
+        "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.4",
+    ],
+    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",
+    ],
+    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..35ac23f
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -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.
+ */
+
+#include <composer-vts/2.4/ComposerVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+
+using V2_4::Error;
+
+Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
+
+Composer::Composer(const std::string& name)
+    : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
+
+Composer::Composer(const sp<IComposer>& composer)
+    : V2_3::vts::Composer(composer), mComposer(composer) {}
+
+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;
+}
+
+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;
+}
+
+}  // 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/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
new file mode 100644
index 0000000..83e74ed
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-vts/2.3/ComposerVts.h>
+#include <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);
+
+    Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriods);
+
+    Error setActiveConfigWithConstraints(
+            Display display, Config config,
+            const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+            VsyncPeriodChangeTimeline* timeline);
+
+  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/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..f038f55
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -0,0 +1,391 @@
+/*
+ * 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 <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.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.4/ComposerVts.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <mapper-vts/2.0/MapperVts.h>
+#include <utils/Timers.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+namespace {
+
+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 mapper::V2_0::vts::Gralloc;
+
+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 V2_1::vts::GraphicsComposerCallback;
+        mComposerClient->registerCallback(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<V2_1::vts::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());
+        }
+    }
+
+    // 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 Test_setActiveConfigWithConstraints(
+            const IComposerClient::VsyncPeriodChangeConstraints& constraints);
+
+    std::unique_ptr<Composer> mComposer;
+    std::unique_ptr<ComposerClient> mComposerClient;
+    sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
+    // the first display and is assumed never to be removed
+    Display mPrimaryDisplay;
+    Display mInvalidDisplayId;
+    std::unique_ptr<CommandWriterBase> mWriter;
+    std::unique_ptr<V2_1::vts::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>());
+
+        mWriter = std::make_unique<CommandWriterBase>(1024);
+        mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+    }
+
+    void TearDown() override {
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
+    }
+
+    const native_handle_t* allocate() {
+        IMapper::BufferDescriptorInfo info{};
+        info.width = 64;
+        info.height = 64;
+        info.layerCount = 1;
+        info.format = static_cast<common::V1_0::PixelFormat>(PixelFormat::RGBA_8888);
+        info.usage =
+                static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+        return mGralloc->allocate(info);
+    }
+
+    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+    std::unique_ptr<CommandWriterBase> mWriter;
+    std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+
+  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, 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->getDisplayAttribute_2_4(mPrimaryDisplay, config, attribute);
+        }
+
+        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(GraphicsComposerHidlTest, getDisplayVsyncPeriod) {
+    for (Display display : mComposerCallback->getDisplays()) {
+        for (Config config : mComposerClient->getDisplayConfigs(display)) {
+            mComposerClient->setActiveConfig(display, config);
+
+            VsyncPeriodNanos vsyncPeriodNanos;
+            VsyncPeriodNanos expectedvsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4(
+                    display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+            int retryCount = 100;
+            do {
+                std::this_thread::sleep_for(10ms);
+                EXPECT_EQ(Error::NONE,
+                          mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+                --retryCount;
+            } while (retryCount > 0);
+
+            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()) {
+        for (Config config : mComposerClient->getDisplayConfigs(display)) {
+            int32_t configGroup = mComposerClient->getDisplayAttribute_2_4(
+                    display, config, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
+
+            for (Config otherConfig : mComposerClient->getDisplayConfigs(display)) {
+                int32_t otherConfigGroup = mComposerClient->getDisplayAttribute_2_4(
+                        display, otherConfig,
+                        IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
+                if (configGroup != otherConfigGroup) {
+                    mComposerClient->setActiveConfig(display, config);
+                    EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED,
+                              mComposerClient->setActiveConfigWithConstraints(
+                                      display, otherConfig, constraints, &timeline));
+                }
+            }
+        }
+    }
+}
+
+void GraphicsComposerHidlTest::Test_setActiveConfigWithConstraints(
+        const IComposerClient::VsyncPeriodChangeConstraints& constraints) {
+    VsyncPeriodChangeTimeline timeline = {};
+
+    for (Display display : mComposerCallback->getDisplays()) {
+        for (Config config : mComposerClient->getDisplayConfigs(display)) {
+            mComposerClient->setActiveConfig(display, config);
+
+            int32_t configVsyncPeriod = mComposerClient->getDisplayAttribute_2_4(
+                    display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+            for (Config otherConfig : mComposerClient->getDisplayConfigs(display)) {
+                if (config == otherConfig) {
+                    continue;
+                }
+
+                int32_t otherVsyncPeriod = mComposerClient->getDisplayAttribute_2_4(
+                        display, otherConfig,
+                        IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
+
+                if (configVsyncPeriod == otherVsyncPeriod) {
+                    continue;
+                }
+
+                EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints(
+                                               display, otherConfig, constraints, &timeline));
+
+                if (timeline.refreshRequired) {
+                    // TODO(b/143775556): handle this case;
+                    continue;
+                }
+
+                EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos);
+
+                // Refresh rate should change within a reasonable time
+                constexpr nsecs_t kReasonableTimeForChange = 1'000'000'000;  // 1 second
+                EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <=
+                            kReasonableTimeForChange);
+
+                while (systemTime() <= timeline.newVsyncAppliedTimeNanos) {
+                    VsyncPeriodNanos vsyncPeriodNanos;
+                    EXPECT_EQ(Error::NONE,
+                              mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+
+                    if (systemTime() <= constraints.desiredTimeNanos) {
+                        EXPECT_NE(vsyncPeriodNanos, otherVsyncPeriod);
+                    }
+
+                    if (vsyncPeriodNanos == otherVsyncPeriod) {
+                        break;
+                    }
+                    std::this_thread::sleep_for(10ms);
+                }
+                VsyncPeriodNanos vsyncPeriodNanos;
+                EXPECT_EQ(Error::NONE,
+                          mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+                EXPECT_EQ(vsyncPeriodNanos, otherVsyncPeriod);
+            }
+        }
+    }
+}
+
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints) {
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime();
+    Test_setActiveConfigWithConstraints(constraints);
+}
+
+TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_delayed) {
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constexpr auto kDelayForChange = 300ms;
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime() + kDelayForChange.count();
+    Test_setActiveConfigWithConstraints(constraints);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GraphicsComposerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+}  // 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..03dfef1
--- /dev/null
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -0,0 +1,645 @@
+/*
+ * 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.
+     *
+     * 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, PER_FRAME_METADATA, PER_FRAME_METADATA_BLOB 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..926cf31
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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.mapper@4.0-vts",
+        "libgralloctypes",
+        "libsync",
+        "vintf-graphics-common-ndk_platform",
+    ],
+    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..4a0aabf
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -0,0 +1,2010 @@
+/*
+ * 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::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::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";
+        }
+        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(8, 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);
+
+        EXPECT_EQ(0, planeLayout.crop.left);
+        EXPECT_EQ(0, planeLayout.crop.top);
+        EXPECT_EQ(planeLayout.widthInSamples, planeLayout.crop.right);
+        EXPECT_EQ(planeLayout.heightInSamples, planeLayout.crop.bottom);
+    }
+
+    void verifyBufferDump(const IMapper::BufferDump& bufferDump,
+                          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(8, planeLayout.sampleIncrementInBits);
+                        outYCbCr->y = tmpData;
+                        outYCbCr->ystride = planeLayout.strideInBytes;
+                        break;
+
+                    case PlaneLayoutComponentType::CB:
+                    case PlaneLayoutComponentType::CR:
+                        ASSERT_EQ(0, planeLayout.sampleIncrementInBits % 8);
+
+                        sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
+                        ASSERT_TRUE(sampleIncrementInBytes == 1 || sampleIncrementInBytes == 2);
+
+                        if (outYCbCr->cstride == 0 && outYCbCr->chroma_step == 0) {
+                            outYCbCr->cstride = planeLayout.strideInBytes;
+                            outYCbCr->chroma_step = sampleIncrementInBytes;
+                        } else {
+                            ASSERT_EQ(outYCbCr->cstride, planeLayout.strideInBytes);
+                            ASSERT_EQ(outYCbCr->chroma_step, sampleIncrementInBytes);
+                        }
+
+                        if (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;
+        }
+    }
+
+    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));
+    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";
+    }
+
+    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(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(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_Dataspace, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &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(Usage) remove flag
+ */
+TEST_P(GraphicsMapperHidlTest, SetUsageRemoveBit) {
+    uint64_t usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN);
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint64_t realUsage = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
+                EXPECT_EQ(usage, realUsage);
+            });
+}
+/**
+ * Test IMapper::set(Usage) add flag
+ */
+TEST_P(GraphicsMapperHidlTest, SetUsageAddBit) {
+    uint64_t usage = mDummyDescriptorInfo.usage | static_cast<uint64_t>(BufferUsage::GPU_TEXTURE);
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Usage, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                uint64_t realUsage = 0;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
+                EXPECT_EQ(usage, realUsage);
+            });
+}
+
+/**
+ * Test IMapper::set(Usage) to test protected content
+ */
+TEST_P(GraphicsMapperHidlTest, SetUsageProtected) {
+    const native_handle_t* bufferHandle = nullptr;
+    auto info = mDummyDescriptorInfo;
+    info.usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY;
+
+    bufferHandle = mGralloc->allocate(info, true, true);
+    if (bufferHandle) {
+        GTEST_SUCCEED() << "unable to allocate protected content";
+    }
+
+    uint64_t usage = static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY);
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeUsage(usage, &vec));
+
+    Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec);
+    ASSERT_EQ(err, Error::UNSUPPORTED);
+    vec.resize(0);
+
+    uint64_t realUsage = 0;
+    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_Usage, &vec));
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeUsage(vec, &realUsage));
+    EXPECT_EQ(info.usage, realUsage);
+}
+
+/**
+ * Test IMapper::set(AllocationSize)
+ */
+TEST_P(GraphicsMapperHidlTest, SetAllocationSize) {
+    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";
+    }
+
+    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;
+    planeLayoutA.crop.left = 0;
+    planeLayoutA.crop.top = 0;
+    planeLayoutA.crop.right = info.width;
+    planeLayoutA.crop.bottom = info.height;
+
+    component.type = gralloc4::PlaneLayoutComponentType_A;
+    component.offsetInBits = 0;
+    component.sizeInBits = 8;
+    planeLayoutA.components.push_back(component);
+
+    planeLayouts.push_back(planeLayoutA);
+
+    planeLayoutRGB.offsetInBytes = 0;
+    planeLayoutRGB.sampleIncrementInBits = 32;
+    planeLayoutRGB.strideInBytes = info.width + 20;
+    planeLayoutRGB.widthInSamples = info.width;
+    planeLayoutRGB.heightInSamples = info.height;
+    planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * info.height;
+    planeLayoutRGB.horizontalSubsampling = 1;
+    planeLayoutRGB.verticalSubsampling = 1;
+    planeLayoutRGB.crop.left = 0;
+    planeLayoutRGB.crop.top = 0;
+    planeLayoutRGB.crop.right = info.width;
+    planeLayoutRGB.crop.bottom = info.height;
+
+    component.type = gralloc4::PlaneLayoutComponentType_R;
+    planeLayoutRGB.components.push_back(component);
+    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";
+    }
+    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);
+
+        EXPECT_EQ(planeLayout.crop.left, realPlaneLayout.crop.left);
+        EXPECT_EQ(planeLayout.crop.top, realPlaneLayout.crop.top);
+        EXPECT_EQ(planeLayout.crop.right, realPlaneLayout.crop.right);
+        EXPECT_EQ(planeLayout.crop.bottom, realPlaneLayout.crop.bottom);
+
+        ASSERT_EQ(planeLayout.components.size(), realPlaneLayout.components.size());
+
+        for (int j = 0; j < realPlaneLayout.components.size(); j++) {
+            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(Dataspace)
+ */
+TEST_P(GraphicsMapperHidlTest, SetDataspace) {
+    Dataspace dataspace = Dataspace::V0_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(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_Dataspace, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, 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));
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_BufferId, vec));
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
+    ASSERT_EQ(Error::BAD_VALUE,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
+    ASSERT_EQ(Error::BAD_VALUE,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec));
+    ASSERT_EQ(Error::BAD_VALUE, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec));
+}
+
+/**
+ * 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_BufferId, vec));
+    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Name, vec));
+    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Width, vec));
+    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Height, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_LayerCount, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatRequested, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_PixelFormatModifier, vec));
+    ASSERT_EQ(Error::UNSUPPORTED, mGralloc->set(bufferHandle, gralloc4::MetadataType_Usage, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_AllocationSize, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              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_Dataspace, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, 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";
+    }
+    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";
+    }
+    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";
+    }
+    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(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(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(0, description.description.size());
+            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(0, pageSize);
+    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(0, pageSize);
+    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(0, pageSize);
+    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.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp
index 1eb9a68..f20f951 100644
--- a/keymaster/4.0/support/Keymaster.cpp
+++ b/keymaster/4.0/support/Keymaster.cpp
@@ -80,8 +80,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;
@@ -92,7 +91,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));
         }
     });
 
@@ -100,7 +99,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.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
index 43a34b0..ad83f17 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
@@ -39,8 +39,8 @@
  * while still having to use only the latest interface.
  */
 class Keymaster : public IKeymasterDevice {
-   public:
-    using KeymasterSet = std::vector<std::unique_ptr<Keymaster>>;
+  public:
+    using KeymasterSet = std::vector<android::sp<Keymaster>>;
 
     Keymaster(const hidl_string& descriptor, const hidl_string& instanceName)
         : descriptor_(descriptor), instanceName_(instanceName) {}
@@ -86,7 +86,7 @@
      */
     static void performHmacKeyAgreement(const KeymasterSet& keymasters);
 
-   private:
+  private:
     hidl_string descriptor_;
     hidl_string 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/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
index c04809f..7aea416 100644
--- a/neuralnetworks/1.3/IPreparedModel.hal
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -18,9 +18,11 @@
 
 import @1.0::ErrorStatus;
 import @1.0::Request;
-import @1.2::MeasureTiming;
 import @1.2::IExecutionCallback;
 import @1.2::IPreparedModel;
+import @1.2::MeasureTiming;
+import @1.2::OutputShape;
+import @1.2::Timing;
 
 /**
  * IPreparedModel describes a model that has been prepared for execution and
@@ -62,8 +64,8 @@
      *   values, the execution should complete successfully (ErrorStatus::NONE):
      *   There must be no failure unless the device itself is in a bad state.
      *
-     * Any number of calls to the execute, execute_1_2, execute_1_3, and executeSynchronously
-     * functions, in any combination, may be made concurrently, even on the same
+     * Any number of calls to the execute* and executeSynchronously* functions,
+     * in any combination, may be made concurrently, even on the same
      * IPreparedModel object.
      *
      * @param request The input and output information on which the prepared
@@ -87,4 +89,60 @@
      */
     execute_1_3(Request request, MeasureTiming measure, IExecutionCallback callback)
         generates (ErrorStatus status);
+
+    /**
+     * Performs a synchronous execution on a prepared model.
+     *
+     * The execution is performed synchronously with respect to the caller.
+     * executeSynchronously_1_3 must verify the inputs to the function are
+     * correct. If there is an error, executeSynchronously_1_3 must immediately
+     * return with the appropriate ErrorStatus value. If the inputs to the
+     * function are valid and there is no error, executeSynchronously_1_3 must
+     * perform the execution, and must not return until the execution is
+     * complete.
+     *
+     * The caller must not change the content of any data object referenced by
+     * 'request' (described by the {@link @1.0::DataLocation} of a
+     * {@link @1.0::RequestArgument}) until executeSynchronously_1_3
+     * returns. executeSynchronously_1_3 must not change the content of any of the
+     * data objects corresponding to 'request' inputs.
+     *
+     * If the prepared model was prepared from a model wherein all tensor
+     * operands have fully specified dimensions, and the inputs to the function
+     * are valid, and at execution time every operation's input operands have
+     * legal values, then the execution should complete successfully
+     * (ErrorStatus::NONE): There must be no failure unless the device itself is
+     * in a bad state.
+     *
+     * Any number of calls to the execute* and executeSynchronously* functions,
+     * in any combination, may be made concurrently, even on the same
+     * IPreparedModel object.
+     *
+     * @param request The input and output information on which the prepared
+     *                model is to be executed.
+     * @param measure Specifies whether or not to measure duration of the execution.
+     *                The duration runs from the time the driver sees the call
+     *                to the executeSynchronously_1_3 function to the time the driver
+     *                returns from the function.
+     * @return status Error status of the execution, must be:
+     *                - NONE if execution is performed successfully
+     *                - DEVICE_UNAVAILABLE if driver is offline or busy
+     *                - GENERAL_FAILURE if there is an unspecified error
+     *                - OUTPUT_INSUFFICIENT_SIZE if at least one output
+     *                  operand buffer is not large enough to store the
+     *                  corresponding output
+     *                - INVALID_ARGUMENT if one of the input arguments is
+     *                  invalid
+     * @return outputShapes A list of shape information of model output operands.
+     *                      The index into "outputShapes" corresponds to the index
+     *                      of the output operand in the Request outputs vector.
+     *                      outputShapes must be empty unless the status is either
+     *                      NONE or OUTPUT_INSUFFICIENT_SIZE.
+     * @return Timing Duration of execution. Unless measure is YES and status is
+     *                NONE, all times must be reported as UINT64_MAX. A driver may
+     *                choose to report any time as UINT64_MAX, indicating that
+     *                measurement is not available.
+     */
+    executeSynchronously_1_3(Request request, MeasureTiming measure)
+            generates (ErrorStatus status, vec<OutputShape> outputShapes, Timing timing);
 };
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index f61240e..be894f2 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -215,7 +215,7 @@
                                                 hidl_vec<OutputShape>* outputShapes,
                                                 Timing* timing) {
     ErrorStatus result;
-    Return<void> ret = preparedModel->executeSynchronously(
+    Return<void> ret = preparedModel->executeSynchronously_1_3(
             request, measure,
             [&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
                                             const Timing& time) {
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 242e12e..65880b7 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -323,8 +323,8 @@
         // - CAST's argument can be any of TENSOR_(FLOAT16|FLOAT32|INT32|QUANT8_ASYMM).
         // - RANDOM_MULTINOMIAL's argument can be either TENSOR_FLOAT16 or TENSOR_FLOAT32.
         // - DEQUANTIZE input can be any of
-        // TENSOR_(QUANT8_ASYMM|QUANT8_SYMM|QUANT8_SYMM_PER_CHANNEL), output can
-        // be of either TENSOR_FLOAT16 or TENSOR_FLOAT32.
+        // TENSOR_(QUANT8_ASYMM|QUANT8_ASYMM_SIGNED|QUANT8_SYMM|QUANT8_SYMM_PER_CHANNEL),
+        // output can be of either TENSOR_FLOAT16 or TENSOR_FLOAT32.
         // - QUANTIZE input can be either TENSOR_FLOAT16 or TENSOR_FLOAT32
         // - CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
         // - DEPTHWISE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
@@ -340,7 +340,8 @@
             case OperationType::ARGMAX:
             case OperationType::ARGMIN: {
                 if (type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32 ||
-                    type == OperandType::TENSOR_INT32 || type == OperandType::TENSOR_QUANT8_ASYMM) {
+                    type == OperandType::TENSOR_INT32 || type == OperandType::TENSOR_QUANT8_ASYMM ||
+                    type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED) {
                     return true;
                 }
             } break;
@@ -364,6 +365,7 @@
             case OperationType::DEQUANTIZE: {
                 if (operand == operation.inputs[0] &&
                     (type == OperandType::TENSOR_QUANT8_ASYMM ||
+                     type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED ||
                      type == OperandType::TENSOR_QUANT8_SYMM ||
                      type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL)) {
                     return true;
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 2cf30d5..8092d04 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -79,9 +79,9 @@
 
     // synchronous
     {
-        SCOPED_TRACE(message + " [executeSynchronously]");
+        SCOPED_TRACE(message + " [executeSynchronously_1_3]");
 
-        Return<void> executeStatus = preparedModel->executeSynchronously(
+        Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
                 request, measure,
                 [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
                    const Timing& timing) {
@@ -158,8 +158,8 @@
 }
 
 void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request) {
-    SCOPED_TRACE("Expecting request to fail [executeSynchronously]");
-    Return<void> executeStatus = preparedModel->executeSynchronously(
+    SCOPED_TRACE("Expecting request to fail [executeSynchronously_1_3]");
+    Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
             request, MeasureTiming::NO,
             [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
                 ASSERT_NE(ErrorStatus::NONE, error);
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/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/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/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
index 2071c5a..81db5a0 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
@@ -129,8 +129,8 @@
 
 void SensorsHidlEnvironmentV2_0::startPollingThread() {
     mStopThread = false;
-    mPollThread = std::thread(pollingThread, this);
     mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
+    mPollThread = std::thread(pollingThread, this);
 }
 
 void SensorsHidlEnvironmentV2_0::readEvents() {
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/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/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..207b9b7
--- /dev/null
+++ b/soundtrigger/2.3/ISoundTriggerHw.hal
@@ -0,0 +1,87 @@
+/*
+ * 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.2::ISoundTriggerHw;
+
+/**
+ * SoundTrigger HAL interface. Used for hardware recognition of hotwords
+ * and other sounds.
+ */
+interface ISoundTriggerHw extends @2.2::ISoundTriggerHw {
+
+    /**
+     * 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 ModelParameter structure indicating supported attributes
+     *                of the parameter for the given model handle
+     */
+    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..4a39ab5
--- /dev/null
+++ b/soundtrigger/2.3/default/SoundTriggerHw.cpp
@@ -0,0 +1,804 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+    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(
+        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::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;
+}
+
+// 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<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) {
+        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..c82c9ea
--- /dev/null
+++ b/soundtrigger/2.3/default/SoundTriggerHw.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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<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);
+    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);
+
+    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..c3a522b
--- /dev/null
+++ b/soundtrigger/2.3/types.hal
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+/**
+ * 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..202eb6c
--- /dev/null
+++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.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.
+ */
+
+#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_3::ISoundTriggerHw;
+
+/**
+ * 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) {}
+
+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/default/service.cpp b/tv/tuner/1.0/default/service.cpp
index 581d269..7bbc09e 100644
--- a/tv/tuner/1.0/default/service.cpp
+++ b/tv/tuner/1.0/default/service.cpp
@@ -21,7 +21,6 @@
 #define LOG_TAG "android.hardware.tv.tuner@1.0-service"
 #endif
 
-#include <binder/ProcessState.h>
 #include <hidl/HidlTransportSupport.h>
 #include <hidl/LegacySupport.h>
 
@@ -46,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 ef33952..707f5df 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 {
     /**
@@ -868,7 +868,7 @@
 };
 
 /**
- *  Modulaltion Type for ISDBS.
+ *  Modulation Type for ISDBS.
  */
 @export
 enum FrontendIsdbsModulation : uint32_t {
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/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..8be8a0c 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,37 @@
 
 #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();
+        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 +54,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 +73,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 +84,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);
\ No newline at end of file
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..33817d5
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 {
+        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);
\ No newline at end of file
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..95f223d
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <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 {
+        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);
\ No newline at end of file
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..ec96fcf 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,19 @@
 }  // 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();
+        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 +118,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 +139,9 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -162,15 +149,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 +164,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 +173,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 +192,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 +205,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 +215,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 +227,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 +242,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 +259,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 +278,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 +306,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 +332,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 +346,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 +364,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 +396,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 +422,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 +443,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 +457,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 +489,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 +515,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 +534,7 @@
 /*
  * CreateRttController
  */
-TEST_F(WifiChipHidlTest, CreateRttController) {
+TEST_P(WifiChipHidlTest, CreateRttController) {
     configureChipForIfaceType(IfaceType::STA, true);
 
     sp<IWifiStaIface> iface;
@@ -755,3 +546,9 @@
     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);
\ No newline at end of file
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
index b8e501c..512701a 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,14 @@
 /**
  * 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 TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -42,7 +45,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);
\ No newline at end of file
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..bdee2ec 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -61,48 +61,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..422e3f6 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,28 @@
 
 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);
+        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 +441,8 @@
       NanFollowupReceivedInd nanFollowupReceivedInd;
       NanDataPathRequestInd nanDataPathRequestInd;
       NanDataPathConfirmInd nanDataPathConfirmInd;
+
+      std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -445,9 +450,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 +459,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);
\ No newline at end of file
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..8f33271 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,29 @@
 
 #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 TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -42,7 +46,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);
\ No newline at end of file
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..e1ee34f 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,29 @@
 
 #include <android-base/logging.h>
 
+#include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiRttController.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::IWifiRttController;
 using ::android::sp;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiRttController;
 
 /**
  * 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 TearDown() override { stopWifi(); }
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
    protected:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -42,7 +46,13 @@
  * 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());
+    EXPECT_NE(nullptr, getWifiRttController(GetInstanceName()).get());
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiRttControllerHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
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..30b6fba 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,14 @@
 /**
  * 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();
+        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 +62,7 @@
     }
 
     sp<IWifiStaIface> wifi_sta_iface_;
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -66,15 +70,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 +87,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 +97,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 +112,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 +128,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 +140,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 +175,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 +200,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 +245,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 +260,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 +277,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 +294,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);
\ No newline at end of file
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..08de240 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,14 @@
 /**
  * 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());
+        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 +78,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 +100,7 @@
 /*
  * ResetTxPowerScenario
  */
-TEST_F(WifiChipHidlTest, ResetTxPowerScenario) {
+TEST_P(WifiChipHidlTest, ResetTxPowerScenario) {
     uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
     const auto& status =
         HIDL_INVOKE(wifi_chip_, resetTxPowerScenario);
@@ -106,3 +110,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);
\ No newline at end of file
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..47faec8 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,14 @@
 /**
  * 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());
+    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 +125,9 @@
   }
 
   sp<IWifiChip> wifi_chip_;
+
+ private:
+  std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -130,7 +135,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 +152,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 +172,15 @@
  * 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);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiChipHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_2::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
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..f3f76e1 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,19 @@
 
 #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();
+        iwifiNanIface = getWifiNanIface_1_2(GetInstanceName());
         ASSERT_NE(nullptr, iwifiNanIface.get());
         ASSERT_EQ(WifiStatusCode::SUCCESS,
                   HIDL_INVOKE(iwifiNanIface, registerEventCallback_1_2,
@@ -56,7 +58,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() {
@@ -458,6 +460,8 @@
     ::android::hardware::wifi::V1_2::NanDataPathConfirmInd
         nanDataPathConfirmInd_1_2;
     NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd;
+
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -465,15 +469,14 @@
  * 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 = {};
@@ -493,7 +496,7 @@
  * 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 =
@@ -508,7 +511,7 @@
 /*
  * 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 = {};
@@ -528,7 +531,7 @@
  * 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
@@ -538,3 +541,9 @@
                           nanConfigRequest, nanConfigRequestSupp)
                   .code);
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiNanIfaceHidlTest,
+    testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+        ::android::hardware::wifi::V1_2::IWifi::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
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..1b907b2 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,15 @@
 /**
  * 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());
+        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 +55,9 @@
     }
 
     sp<IWifiStaIface> wifi_sta_iface_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -59,7 +65,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 +82,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 +113,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);
\ No newline at end of file
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/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..db93967 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,14 @@
 /**
  * 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());
+        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 +72,9 @@
     }
 
     sp<IWifiChip> wifi_chip_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -77,7 +82,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 +97,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 +111,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 +121,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);
\ No newline at end of file
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..c5acc3c 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,33 @@
 
 #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());
+        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 +56,9 @@
     }
 
     sp<IWifiStaIface> wifi_sta_iface_;
+
+   private:
+    std::string GetInstanceName() { return GetParam(); }
 };
 
 /*
@@ -58,15 +66,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 +79,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 +100,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);
\ No newline at end of file
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.3/default/Android.mk b/wifi/1.4/default/Android.mk
similarity index 92%
rename from wifi/1.3/default/Android.mk
rename to wifi/1.4/default/Android.mk
index 29f1c42..ab76ff6 100644
--- a/wifi/1.3/default/Android.mk
+++ b/wifi/1.4/default/Android.mk
@@ -67,7 +67,8 @@
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
     android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3
+    android.hardware.wifi@1.3 \
+    android.hardware.wifi@1.4
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
 include $(BUILD_STATIC_LIBRARY)
 
@@ -76,6 +77,7 @@
 ###
 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
@@ -93,7 +95,8 @@
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
     android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3
+    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
@@ -104,6 +107,7 @@
 ###
 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
@@ -123,7 +127,8 @@
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
     android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3
+    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
@@ -145,7 +150,6 @@
     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
@@ -165,5 +169,6 @@
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
     android.hardware.wifi@1.2 \
-    android.hardware.wifi@1.3
+    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.3/default/hidl_callback_util.h b/wifi/1.4/default/hidl_callback_util.h
similarity index 98%
rename from wifi/1.3/default/hidl_callback_util.h
rename to wifi/1.4/default/hidl_callback_util.h
index a44af79..fc601b8 100644
--- a/wifi/1.3/default/hidl_callback_util.h
+++ b/wifi/1.4/default/hidl_callback_util.h
@@ -52,7 +52,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace hidl_callback_util {
 template <typename CallbackType>
@@ -117,7 +117,7 @@
 
 }  // namespace hidl_callback_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/hidl_return_util.h b/wifi/1.4/default/hidl_return_util.h
similarity index 98%
rename from wifi/1.3/default/hidl_return_util.h
rename to wifi/1.4/default/hidl_return_util.h
index 9707444..99c7092 100644
--- a/wifi/1.3/default/hidl_return_util.h
+++ b/wifi/1.4/default/hidl_return_util.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace hidl_return_util {
 using namespace android::hardware::wifi::V1_0;
@@ -113,7 +113,7 @@
 
 }  // namespace hidl_return_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp
similarity index 96%
rename from wifi/1.3/default/hidl_struct_util.cpp
rename to wifi/1.4/default/hidl_struct_util.cpp
index 2e4db70..4996e35 100644
--- a/wifi/1.3/default/hidl_struct_util.cpp
+++ b/wifi/1.4/default/hidl_struct_util.cpp
@@ -22,7 +22,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace hidl_struct_util {
 
@@ -91,7 +91,7 @@
 }
 
 IWifiStaIface::StaIfaceCapabilityMask
-convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) {
+convertLegacyFeatureToHidlStaIfaceCapability(uint64_t feature) {
     using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
     switch (feature) {
         case WIFI_FEATURE_GSCAN:
@@ -302,11 +302,11 @@
 }
 
 legacy_hal::wifi_latency_mode convertHidlLatencyModeToLegacy(
-    IWifiChip::LatencyMode hidl_latency_mode) {
+    V1_3::IWifiChip::LatencyMode hidl_latency_mode) {
     switch (hidl_latency_mode) {
-        case IWifiChip::LatencyMode::NORMAL:
+        case V1_3::IWifiChip::LatencyMode::NORMAL:
             return legacy_hal::WIFI_LATENCY_MODE_NORMAL;
-        case IWifiChip::LatencyMode::LOW:
+        case V1_3::IWifiChip::LatencyMode::LOW:
             return legacy_hal::WIFI_LATENCY_MODE_LOW;
     }
     CHECK(false);
@@ -314,7 +314,7 @@
 
 bool convertLegacyWifiMacInfoToHidl(
     const legacy_hal::WifiMacInfo& legacy_mac_info,
-    V1_2::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
+    IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
     if (!hidl_radio_mode_info) {
         return false;
     }
@@ -323,8 +323,17 @@
     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) {
+    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;
@@ -346,15 +355,14 @@
 
 bool convertLegacyWifiMacInfosToHidl(
     const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-    std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>*
-        hidl_radio_mode_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) {
-        V1_2::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
+        IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
         if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
                                             &hidl_radio_mode_info)) {
             return false;
@@ -365,7 +373,7 @@
 }
 
 bool convertLegacyFeaturesToHidlStaCapabilities(
-    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
     uint32_t* hidl_caps) {
     if (!hidl_caps) {
         return false;
@@ -446,21 +454,21 @@
     return true;
 }
 
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band) {
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(V1_0::WifiBand band) {
     switch (band) {
-        case WifiBand::BAND_UNSPECIFIED:
+        case V1_0::WifiBand::BAND_UNSPECIFIED:
             return legacy_hal::WIFI_BAND_UNSPECIFIED;
-        case WifiBand::BAND_24GHZ:
+        case V1_0::WifiBand::BAND_24GHZ:
             return legacy_hal::WIFI_BAND_BG;
-        case WifiBand::BAND_5GHZ:
+        case V1_0::WifiBand::BAND_5GHZ:
             return legacy_hal::WIFI_BAND_A;
-        case WifiBand::BAND_5GHZ_DFS:
+        case V1_0::WifiBand::BAND_5GHZ_DFS:
             return legacy_hal::WIFI_BAND_A_DFS;
-        case WifiBand::BAND_5GHZ_WITH_DFS:
+        case V1_0::WifiBand::BAND_5GHZ_WITH_DFS:
             return legacy_hal::WIFI_BAND_A_WITH_DFS;
-        case WifiBand::BAND_24GHZ_5GHZ:
+        case V1_0::WifiBand::BAND_24GHZ_5GHZ:
             return legacy_hal::WIFI_BAND_ABG;
-        case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
+        case V1_0::WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
             return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
     };
     CHECK(false);
@@ -1124,9 +1132,9 @@
     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) {
+    if (hidl_request.configParams.bandSpecificConfig.size() != 3) {
         LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
-                      "bandSpecificConfig.size() != 2";
+                      "bandSpecificConfig.size() != 3";
         return false;
     }
     legacy_request->rssi_close_2dot4g_val =
@@ -1259,16 +1267,20 @@
         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_2ToLegacy(
+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_2ToLegacy: null legacy_request";
+            << "convertHidlNanEnableRequest_1_4ToLegacy: null legacy_request";
         return false;
     }
 
@@ -1769,16 +1781,19 @@
     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_2ToLegacy(
+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_2ToLegacy: legacy_request "
+        LOG(ERROR) << "convertHidlNanConfigRequest_1_4ToLegacy: legacy_request "
                       "is null";
         return false;
     }
@@ -1819,7 +1834,13 @@
         convertHidlNanDataPathChannelCfgToLegacy(
             hidl_request.channelRequestType);
     legacy_request->channel = hidl_request.channel;
-    strcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str());
+    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)
@@ -1900,7 +1921,13 @@
                                    ? legacy_hal::NAN_DP_REQUEST_ACCEPT
                                    : legacy_hal::NAN_DP_REQUEST_REJECT;
     legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
-    strcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str());
+    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)
@@ -2279,6 +2306,8 @@
             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);
 }
@@ -2291,6 +2320,8 @@
             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;
 }
@@ -2354,6 +2385,8 @@
             return WifiRatePreamble::HT;
         case 3:
             return WifiRatePreamble::VHT;
+        case 4:
+            return WifiRatePreamble::HE;
         default:
             return WifiRatePreamble::RESERVED;
     };
@@ -2579,9 +2612,10 @@
     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}) {
+    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>(
@@ -2683,7 +2717,7 @@
 }
 }  // namespace hidl_struct_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h
similarity index 94%
rename from wifi/1.3/default/hidl_struct_util.h
rename to wifi/1.4/default/hidl_struct_util.h
index 3eefd95..d040c1f 100644
--- a/wifi/1.3/default/hidl_struct_util.h
+++ b/wifi/1.4/default/hidl_struct_util.h
@@ -21,10 +21,11 @@
 
 #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 <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
+#include <android/hardware/wifi/1.4/types.h>
 
 #include "wifi_legacy_hal.h"
 
@@ -37,7 +38,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace hidl_struct_util {
 using namespace android::hardware::wifi::V1_0;
@@ -63,12 +64,11 @@
     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);
+    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
 
 // STA iface conversion methods.
 bool convertLegacyFeaturesToHidlStaCapabilities(
-    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
     uint32_t* hidl_caps);
 bool convertLegacyApfCapabilitiesToHidl(
     const legacy_hal::PacketFilterCapabilities& legacy_caps,
@@ -76,7 +76,7 @@
 bool convertLegacyGscanCapabilitiesToHidl(
     const legacy_hal::wifi_gscan_capabilities& legacy_caps,
     StaBackgroundScanCapabilities* hidl_caps);
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band);
+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);
@@ -117,11 +117,11 @@
 bool convertHidlNanConfigRequestToLegacy(
     const NanConfigRequest& hidl_request,
     legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanEnableRequest_1_2ToLegacy(
+bool convertHidlNanEnableRequest_1_4ToLegacy(
     const NanEnableRequest& hidl_request1,
     const V1_2::NanConfigRequestSupplemental& hidl_request2,
     legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequest_1_2ToLegacy(
+bool convertHidlNanConfigRequest_1_4ToLegacy(
     const NanConfigRequest& hidl_request1,
     const V1_2::NanConfigRequestSupplemental& hidl_request2,
     legacy_hal::NanConfigRequest* legacy_request);
@@ -188,7 +188,7 @@
     std::vector<RttResult>* hidl_results);
 }  // namespace hidl_struct_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/hidl_sync_util.cpp b/wifi/1.4/default/hidl_sync_util.cpp
similarity index 96%
rename from wifi/1.3/default/hidl_sync_util.cpp
rename to wifi/1.4/default/hidl_sync_util.cpp
index 160727f..593a3bc 100644
--- a/wifi/1.3/default/hidl_sync_util.cpp
+++ b/wifi/1.4/default/hidl_sync_util.cpp
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace hidl_sync_util {
 
@@ -33,7 +33,7 @@
 
 }  // namespace hidl_sync_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/hidl_sync_util.h b/wifi/1.4/default/hidl_sync_util.h
similarity index 96%
rename from wifi/1.3/default/hidl_sync_util.h
rename to wifi/1.4/default/hidl_sync_util.h
index ebfb051..0244421 100644
--- a/wifi/1.3/default/hidl_sync_util.h
+++ b/wifi/1.4/default/hidl_sync_util.h
@@ -24,13 +24,13 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace hidl_sync_util {
 std::unique_lock<std::recursive_mutex> acquireGlobalLock();
 }  // namespace hidl_sync_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/ringbuffer.cpp b/wifi/1.4/default/ringbuffer.cpp
similarity index 97%
rename from wifi/1.3/default/ringbuffer.cpp
rename to wifi/1.4/default/ringbuffer.cpp
index 1294c52..0fe8ef4 100644
--- a/wifi/1.3/default/ringbuffer.cpp
+++ b/wifi/1.4/default/ringbuffer.cpp
@@ -21,7 +21,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 
 Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
@@ -48,7 +48,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/ringbuffer.h b/wifi/1.4/default/ringbuffer.h
similarity index 97%
rename from wifi/1.3/default/ringbuffer.h
rename to wifi/1.4/default/ringbuffer.h
index d9f8df6..ddce648 100644
--- a/wifi/1.3/default/ringbuffer.h
+++ b/wifi/1.4/default/ringbuffer.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 
 /**
@@ -45,7 +45,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/service.cpp b/wifi/1.4/default/service.cpp
similarity index 85%
rename from wifi/1.3/default/service.cpp
rename to wifi/1.4/default/service.cpp
index 0b41d28..3f7f609 100644
--- a/wifi/1.3/default/service.cpp
+++ b/wifi/1.4/default/service.cpp
@@ -28,11 +28,11 @@
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::LazyServiceRegistrar;
-using android::hardware::wifi::V1_3::implementation::feature_flags::
+using android::hardware::wifi::V1_4::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::
+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
@@ -51,8 +51,8 @@
     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(
+    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),
diff --git a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
similarity index 92%
rename from wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
rename to wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
index 4e9ebde..b71d549 100644
--- a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
@@ -34,7 +34,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
@@ -55,8 +55,7 @@
     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;
+    std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
     ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
         legacy_mac_infos, &hidl_radio_mode_infos));
 
@@ -90,20 +89,18 @@
     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;
+    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 V1_2::IWifiChipEventCallback::RadioModeInfo& x) {
-                         return x.radioId == legacy_mac_info1.wlan_mac_id;
-                     });
+    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());
@@ -113,12 +110,11 @@
               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;
-                     });
+    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());
@@ -277,9 +273,9 @@
     uint32_t hidle_caps;
 
     uint32_t legacy_feature_set =
-            WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
+        WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
     uint32_t legacy_logger_feature_set =
-            legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
+        legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
 
     ASSERT_TRUE(hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
         legacy_feature_set, legacy_logger_feature_set, &hidle_caps));
@@ -292,7 +288,7 @@
               hidle_caps);
 }
 }  // namespace implementation
-}  // namespace V1_3
+}  // 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.3/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
similarity index 96%
rename from wifi/1.3/default/tests/mock_wifi_feature_flags.cpp
rename to wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
index a393fdc..b1fa432 100644
--- a/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp
+++ b/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
@@ -21,7 +21,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace feature_flags {
 
@@ -29,7 +29,7 @@
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_feature_flags.h b/wifi/1.4/default/tests/mock_wifi_feature_flags.h
similarity index 96%
rename from wifi/1.3/default/tests/mock_wifi_feature_flags.h
rename to wifi/1.4/default/tests/mock_wifi_feature_flags.h
index ee12b54..72d2304 100644
--- a/wifi/1.3/default/tests/mock_wifi_feature_flags.h
+++ b/wifi/1.4/default/tests/mock_wifi_feature_flags.h
@@ -25,7 +25,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace feature_flags {
 
@@ -39,7 +39,7 @@
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_iface_util.cpp b/wifi/1.4/default/tests/mock_wifi_iface_util.cpp
similarity index 96%
rename from wifi/1.3/default/tests/mock_wifi_iface_util.cpp
rename to wifi/1.4/default/tests/mock_wifi_iface_util.cpp
index 3d877c0..0968569 100644
--- a/wifi/1.3/default/tests/mock_wifi_iface_util.cpp
+++ b/wifi/1.4/default/tests/mock_wifi_iface_util.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace iface_util {
 
@@ -33,7 +33,7 @@
     : WifiIfaceUtil(iface_tool) {}
 }  // namespace iface_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_iface_util.h b/wifi/1.4/default/tests/mock_wifi_iface_util.h
similarity index 97%
rename from wifi/1.3/default/tests/mock_wifi_iface_util.h
rename to wifi/1.4/default/tests/mock_wifi_iface_util.h
index 8ec93eb..6cc81e4 100644
--- a/wifi/1.3/default/tests/mock_wifi_iface_util.h
+++ b/wifi/1.4/default/tests/mock_wifi_iface_util.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace iface_util {
 
@@ -43,7 +43,7 @@
 };
 }  // namespace iface_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
similarity index 96%
rename from wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp
rename to wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
index 0a202c4..8d65c59 100644
--- a/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace legacy_hal {
 
@@ -33,7 +33,7 @@
     : WifiLegacyHal(iface_tool) {}
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_legacy_hal.h b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h
similarity index 92%
rename from wifi/1.3/default/tests/mock_wifi_legacy_hal.h
rename to wifi/1.4/default/tests/mock_wifi_legacy_hal.h
index 81cb1de..6942c1e 100644
--- a/wifi/1.3/default/tests/mock_wifi_legacy_hal.h
+++ b/wifi/1.4/default/tests/mock_wifi_legacy_hal.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace legacy_hal {
 
@@ -41,9 +41,9 @@
                  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));
+                                         const std::string& iface_name));
     MOCK_METHOD1(getDriverVersion, std::pair<wifi_error, std::string>(
-                 const std::string& iface_name));
+                                       const std::string& iface_name));
 
     MOCK_METHOD2(selectTxPowerScenario,
                  wifi_error(const std::string& iface_name,
@@ -60,7 +60,7 @@
 };
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
similarity index 96%
rename from wifi/1.3/default/tests/mock_wifi_mode_controller.cpp
rename to wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
index 2b0ea36..ee09029 100644
--- a/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp
+++ b/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
@@ -24,14 +24,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace mode_controller {
 
 MockWifiModeController::MockWifiModeController() : WifiModeController() {}
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/mock_wifi_mode_controller.h b/wifi/1.4/default/tests/mock_wifi_mode_controller.h
similarity index 97%
rename from wifi/1.3/default/tests/mock_wifi_mode_controller.h
rename to wifi/1.4/default/tests/mock_wifi_mode_controller.h
index c204059..1e1ce69 100644
--- a/wifi/1.3/default/tests/mock_wifi_mode_controller.h
+++ b/wifi/1.4/default/tests/mock_wifi_mode_controller.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace mode_controller {
 
@@ -38,7 +38,7 @@
 };
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
similarity index 98%
rename from wifi/1.3/default/tests/ringbuffer_unit_tests.cpp
rename to wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
index 0cf1e4f..a65347f 100644
--- a/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp
+++ b/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 
 class RingbufferTest : public Test {
@@ -91,7 +91,7 @@
     EXPECT_EQ(input, buffer_.getData().front());
 }
 }  // namespace implementation
-}  // namespace V1_3
+}  // 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.3/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
similarity index 97%
rename from wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
rename to wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
index d8ce278..d35adbc 100644
--- a/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
@@ -41,7 +41,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 
 class WifiChipTest : public Test {
@@ -173,8 +173,9 @@
     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) {
+            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,
@@ -251,7 +252,7 @@
 
     bool createRttController() {
         bool success = false;
-        chip_->createRttController(
+        chip_->createRttController_1_4(
             NULL, [&success](const WifiStatus& status,
                              const sp<IWifiRttController>& rtt) {
                 if (WifiStatusCode::SUCCESS == status.code) {
@@ -719,13 +720,16 @@
             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;
-    });
+    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");
@@ -749,7 +753,7 @@
 
     // Create RTT controller
     sp<IWifiRttController> rtt_controller;
-    chip_->createRttController(
+    chip_->createRttController_1_4(
         NULL, [&rtt_controller](const WifiStatus& status,
                                 const sp<IWifiRttController>& rtt) {
             if (WifiStatusCode::SUCCESS == status.code) {
@@ -865,7 +869,7 @@
     ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
 }
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
similarity index 98%
rename from wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp
rename to wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
index 28d23ff..03394bc 100644
--- a/wifi/1.3/default/tests/wifi_iface_util_unit_tests.cpp
+++ b/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
@@ -41,7 +41,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace iface_util {
 class WifiIfaceUtilTest : public Test {
@@ -90,7 +90,7 @@
 }
 }  // namespace iface_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
similarity index 92%
rename from wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp
rename to wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
index eb6c610..9022792 100644
--- a/wifi/1.3/default/tests/wifi_nan_iface_unit_tests.cpp
+++ b/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -38,9 +38,12 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+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,
@@ -96,9 +99,15 @@
                  Return<void>(uint16_t, const WifiNanStatus&));
     MOCK_METHOD1(eventDataPathRequest,
                  Return<void>(const NanDataPathRequestInd&));
-    MOCK_METHOD1(eventDataPathConfirm,
-                 Return<void>(const NanDataPathConfirmInd&));
+    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 {
@@ -142,7 +151,7 @@
     captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
 }
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi.cpp b/wifi/1.4/default/wifi.cpp
similarity index 99%
rename from wifi/1.3/default/wifi.cpp
rename to wifi/1.4/default/wifi.cpp
index 2f21819..4f48d7e 100644
--- a/wifi/1.3/default/wifi.cpp
+++ b/wifi/1.4/default/wifi.cpp
@@ -28,7 +28,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using hidl_return_util::validateAndCallWithLock;
@@ -210,7 +210,7 @@
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi.h b/wifi/1.4/default/wifi.h
similarity index 96%
rename from wifi/1.3/default/wifi.h
rename to wifi/1.4/default/wifi.h
index 1c2a154..087d6f7 100644
--- a/wifi/1.3/default/wifi.h
+++ b/wifi/1.4/default/wifi.h
@@ -20,7 +20,7 @@
 #include <functional>
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.3/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifi.h>
 #include <utils/Looper.h>
 
 #include "hidl_callback_util.h"
@@ -32,13 +32,13 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 
 /**
  * Root HIDL interface object used to control the Wifi HAL.
  */
-class Wifi : public V1_3::IWifi {
+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,
@@ -92,7 +92,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_ap_iface.cpp b/wifi/1.4/default/wifi_ap_iface.cpp
similarity index 68%
rename from wifi/1.3/default/wifi_ap_iface.cpp
rename to wifi/1.4/default/wifi_ap_iface.cpp
index 9a8681a..8777a4c 100644
--- a/wifi/1.3/default/wifi_ap_iface.cpp
+++ b/wifi/1.4/default/wifi_ap_iface.cpp
@@ -24,33 +24,18 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+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,
-    const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+    const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
     : 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";
-    }
-}
+      is_valid_(true) {}
 
 void WifiApIface::invalidate() {
     legacy_hal_.reset();
@@ -79,12 +64,26 @@
 }
 
 Return<void> WifiApIface::getValidFrequenciesForBand(
-    WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
+    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_};
 }
@@ -101,7 +100,7 @@
 }
 
 std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiApIface::getValidFrequenciesForBandInternal(WifiBand band) {
+WifiApIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
     static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
                   "Size mismatch");
     legacy_hal::wifi_error legacy_status;
@@ -111,8 +110,28 @@
             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_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_ap_iface.h b/wifi/1.4/default/wifi_ap_iface.h
similarity index 70%
rename from wifi/1.3/default/wifi_ap_iface.h
rename to wifi/1.4/default/wifi_ap_iface.h
index 98c5c9c..bf16d5e 100644
--- a/wifi/1.3/default/wifi_ap_iface.h
+++ b/wifi/1.4/default/wifi_ap_iface.h
@@ -18,29 +18,26 @@
 #define WIFI_AP_IFACE_H_
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiApIface.h>
+#include <android/hardware/wifi/1.4/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 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_0::IWifiApIface {
+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,
-        const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+    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();
@@ -52,7 +49,12 @@
     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;
+        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.
@@ -60,19 +62,21 @@
     std::pair<WifiStatus, IfaceType> getTypeInternal();
     WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
     std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-    getValidFrequenciesForBandInternal(WifiBand band);
+    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_;
-    std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
     bool is_valid_;
 
     DISALLOW_COPY_AND_ASSIGN(WifiApIface);
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
similarity index 96%
rename from wifi/1.3/default/wifi_chip.cpp
rename to wifi/1.4/default/wifi_chip.cpp
index e9991dc..a70457b 100644
--- a/wifi/1.3/default/wifi_chip.cpp
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -307,7 +307,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using hidl_return_util::validateAndCallWithLock;
@@ -321,7 +321,6 @@
       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()),
@@ -342,7 +341,7 @@
 
 bool WifiChip::isValid() { return is_valid_; }
 
-std::set<sp<V1_2::IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+std::set<sp<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
     return event_cb_handler_.getCallbacks();
 }
 
@@ -621,6 +620,22 @@
     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_);
@@ -670,30 +685,6 @@
     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_};
@@ -806,8 +797,7 @@
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
     std::string ifname = allocateApIfaceName();
-    sp<WifiApIface> iface =
-        new WifiApIface(ifname, legacy_hal_, iface_util_, feature_flags_);
+    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()) {
@@ -948,7 +938,8 @@
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
-std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {
+std::pair<WifiStatus, sp<V1_3::IWifiStaIface>>
+WifiChip::createStaIfaceInternal() {
     if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::STA)) {
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
@@ -972,7 +963,7 @@
     return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
 }
 
-std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::getStaIfaceInternal(
+std::pair<WifiStatus, sp<V1_3::IWifiStaIface>> WifiChip::getStaIfaceInternal(
     const std::string& ifname) {
     const auto iface = findUsingName(sta_ifaces_, ifname);
     if (!iface.get()) {
@@ -998,18 +989,10 @@
     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, 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_AVAILABLE), {}};
 }
 
 std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
@@ -1047,6 +1030,12 @@
             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);
 }
 
@@ -1145,11 +1134,9 @@
 }
 
 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);
+    const sp<V1_2::IWifiChipEventCallback>& /* event_callback */) {
+    // Deprecated support for this callback.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
 }
 
 WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(
@@ -1160,6 +1147,53 @@
     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) {
@@ -1262,7 +1296,7 @@
                 LOG(ERROR) << "Callback invoked on an invalid object";
                 return;
             }
-            std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>
+            std::vector<IWifiChipEventCallback::RadioModeInfo>
                 hidl_radio_mode_infos;
             if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
                     mac_infos, &hidl_radio_mode_infos)) {
@@ -1270,9 +1304,9 @@
                 return;
             }
             for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->onRadioModeChange(hidl_radio_mode_infos)
+                if (!callback->onRadioModeChange_1_4(hidl_radio_mode_infos)
                          .isOk()) {
-                    LOG(ERROR) << "Failed to invoke onRadioModeChange"
+                    LOG(ERROR) << "Failed to invoke onRadioModeChange_1_4"
                                << " callback on: " << toString(callback);
                 }
             }
@@ -1539,7 +1573,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_chip.h b/wifi/1.4/default/wifi_chip.h
similarity index 91%
rename from wifi/1.3/default/wifi_chip.h
rename to wifi/1.4/default/wifi_chip.h
index 153ca6a..3323ade 100644
--- a/wifi/1.3/default/wifi_chip.h
+++ b/wifi/1.4/default/wifi_chip.h
@@ -21,7 +21,8 @@
 #include <map>
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.3/IWifiChip.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"
@@ -37,7 +38,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -46,7 +47,7 @@
  * Since there is only a single chip instance used today, there is no
  * identifying handle information stored here.
  */
-class WifiChip : public V1_3::IWifiChip {
+class WifiChip : public V1_4::IWifiChip {
    public:
     WifiChip(
         ChipId chip_id,
@@ -70,7 +71,7 @@
     // marked valid before processing them.
     void invalidate();
     bool isValid();
-    std::set<sp<V1_2::IWifiChipEventCallback>> getEventCallbacks();
+    std::set<sp<IWifiChipEventCallback>> getEventCallbacks();
 
     // HIDL methods exposed.
     Return<void> getId(getId_cb hidl_status_cb) override;
@@ -152,6 +153,12 @@
         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();
@@ -190,13 +197,13 @@
     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, sp<V1_3::IWifiStaIface>> createStaIfaceInternal();
     std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
-    std::pair<WifiStatus, sp<IWifiStaIface>> getStaIfaceInternal(
+    std::pair<WifiStatus, sp<V1_3::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, sp<V1_0::IWifiRttController>>
+    createRttControllerInternal(const sp<IWifiIface>& bound_iface);
     std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
     getDebugRingBuffersStatusInternal();
     WifiStatus startLoggingToDebugRingBufferInternal(
@@ -217,6 +224,11 @@
         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();
@@ -251,7 +263,6 @@
     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_;
@@ -266,14 +277,14 @@
     // 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>
+    hidl_callback_util::HidlCallbackHandler<IWifiChipEventCallback>
         event_cb_handler_;
 
     DISALLOW_COPY_AND_ASSIGN(WifiChip);
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_feature_flags.cpp b/wifi/1.4/default/wifi_feature_flags.cpp
similarity index 92%
rename from wifi/1.3/default/wifi_feature_flags.cpp
rename to wifi/1.4/default/wifi_feature_flags.cpp
index 7212cfa..195b460 100644
--- a/wifi/1.3/default/wifi_feature_flags.cpp
+++ b/wifi/1.4/default/wifi_feature_flags.cpp
@@ -19,7 +19,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace feature_flags {
 
@@ -145,10 +145,12 @@
 #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
+#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() {}
 
@@ -156,13 +158,9 @@
     return kChipModes;
 }
 
-bool WifiFeatureFlags::isApMacRandomizationDisabled() {
-    return wifiHidlFeatureDisableApMacRandomization;
-}
-
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_feature_flags.h b/wifi/1.4/default/wifi_feature_flags.h
similarity index 94%
rename from wifi/1.3/default/wifi_feature_flags.h
rename to wifi/1.4/default/wifi_feature_flags.h
index 3ae6920..292dedf 100644
--- a/wifi/1.3/default/wifi_feature_flags.h
+++ b/wifi/1.4/default/wifi_feature_flags.h
@@ -22,7 +22,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace feature_flags {
 
@@ -43,12 +43,11 @@
     virtual ~WifiFeatureFlags() = default;
 
     virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
-    virtual bool isApMacRandomizationDisabled();
 };
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_iface_util.cpp b/wifi/1.4/default/wifi_iface_util.cpp
similarity index 98%
rename from wifi/1.3/default/wifi_iface_util.cpp
rename to wifi/1.4/default/wifi_iface_util.cpp
index 34bc02d..2883b46 100644
--- a/wifi/1.3/default/wifi_iface_util.cpp
+++ b/wifi/1.4/default/wifi_iface_util.cpp
@@ -35,7 +35,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace iface_util {
 
@@ -112,7 +112,7 @@
 }
 }  // namespace iface_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_iface_util.h b/wifi/1.4/default/wifi_iface_util.h
similarity index 98%
rename from wifi/1.3/default/wifi_iface_util.h
rename to wifi/1.4/default/wifi_iface_util.h
index 98073e0..35edff6 100644
--- a/wifi/1.3/default/wifi_iface_util.h
+++ b/wifi/1.4/default/wifi_iface_util.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace iface_util {
 
@@ -67,7 +67,7 @@
 
 }  // namespace iface_util
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
similarity index 99%
rename from wifi/1.3/default/wifi_legacy_hal.cpp
rename to wifi/1.4/default/wifi_legacy_hal.cpp
index 485bd16..ae3c447 100644
--- a/wifi/1.3/default/wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -50,7 +50,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace legacy_hal {
 // Legacy HAL functions accept "C" style function pointers, so use global
@@ -479,7 +479,7 @@
 std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet(
     const std::string& iface_name) {
     feature_set set;
-    static_assert(sizeof(set) == sizeof(uint32_t),
+    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);
@@ -1449,7 +1449,7 @@
 
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h
similarity index 99%
rename from wifi/1.3/default/wifi_legacy_hal.h
rename to wifi/1.4/default/wifi_legacy_hal.h
index 9cfa172..7f16c30 100644
--- a/wifi/1.3/default/wifi_legacy_hal.h
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -35,7 +35,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+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.
@@ -396,7 +396,7 @@
 
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
similarity index 99%
rename from wifi/1.3/default/wifi_legacy_hal_stubs.cpp
rename to wifi/1.4/default/wifi_legacy_hal_stubs.cpp
index dedd2d4..27afa1f 100644
--- a/wifi/1.3/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
@@ -20,7 +20,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace legacy_hal {
 template <typename>
@@ -142,7 +142,7 @@
 }
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_legacy_hal_stubs.h b/wifi/1.4/default/wifi_legacy_hal_stubs.h
similarity index 96%
rename from wifi/1.3/default/wifi_legacy_hal_stubs.h
rename to wifi/1.4/default/wifi_legacy_hal_stubs.h
index 64854e0..577a545 100644
--- a/wifi/1.3/default/wifi_legacy_hal_stubs.h
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.h
@@ -20,7 +20,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace legacy_hal {
 #include <hardware_legacy/wifi_hal.h>
@@ -28,7 +28,7 @@
 bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_mode_controller.cpp b/wifi/1.4/default/wifi_mode_controller.cpp
similarity index 98%
rename from wifi/1.3/default/wifi_mode_controller.cpp
rename to wifi/1.4/default/wifi_mode_controller.cpp
index c392486..252121a 100644
--- a/wifi/1.3/default/wifi_mode_controller.cpp
+++ b/wifi/1.4/default/wifi_mode_controller.cpp
@@ -48,7 +48,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace mode_controller {
 
@@ -85,7 +85,7 @@
 }
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_mode_controller.h b/wifi/1.4/default/wifi_mode_controller.h
similarity index 97%
rename from wifi/1.3/default/wifi_mode_controller.h
rename to wifi/1.4/default/wifi_mode_controller.h
index ace5a52..45fa999 100644
--- a/wifi/1.3/default/wifi_mode_controller.h
+++ b/wifi/1.4/default/wifi_mode_controller.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 namespace mode_controller {
 using namespace android::hardware::wifi::V1_0;
@@ -55,7 +55,7 @@
 
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_nan_iface.cpp b/wifi/1.4/default/wifi_nan_iface.cpp
similarity index 95%
rename from wifi/1.3/default/wifi_nan_iface.cpp
rename to wifi/1.4/default/wifi_nan_iface.cpp
index ff9f422..073101c 100644
--- a/wifi/1.3/default/wifi_nan_iface.cpp
+++ b/wifi/1.4/default/wifi_nan_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -576,7 +576,7 @@
 }
 
 Return<void> WifiNanIface::enableRequest(uint16_t cmd_id,
-                                         const NanEnableRequest& msg,
+                                         const V1_0::NanEnableRequest& msg,
                                          enableRequest_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
                            &WifiNanIface::enableRequestInternal, hidl_status_cb,
@@ -584,7 +584,7 @@
 }
 
 Return<void> WifiNanIface::configRequest(uint16_t cmd_id,
-                                         const NanConfigRequest& msg,
+                                         const V1_0::NanConfigRequest& msg,
                                          configRequest_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
                            &WifiNanIface::configRequestInternal, hidl_status_cb,
@@ -687,7 +687,7 @@
 }
 
 Return<void> WifiNanIface::enableRequest_1_2(
-    uint16_t cmd_id, const NanEnableRequest& msg1,
+    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,
@@ -696,7 +696,7 @@
 }
 
 Return<void> WifiNanIface::configRequest_1_2(
-    uint16_t cmd_id, const NanConfigRequest& msg1,
+    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,
@@ -704,6 +704,24 @@
                            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_};
 }
@@ -727,12 +745,12 @@
 }
 
 WifiStatus WifiNanIface::enableRequestInternal(
-    uint16_t /* cmd_id */, const NanEnableRequest& /* msg */) {
+    uint16_t /* cmd_id */, const V1_0::NanEnableRequest& /* msg */) {
     return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
 }
 
 WifiStatus WifiNanIface::configRequestInternal(
-    uint16_t /* cmd_id */, const NanConfigRequest& /* msg */) {
+    uint16_t /* cmd_id */, const V1_0::NanConfigRequest& /* msg */) {
     return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
 }
 
@@ -855,10 +873,22 @@
 }
 
 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_2ToLegacy(
+    if (!hidl_struct_util::convertHidlNanEnableRequest_1_4ToLegacy(
             msg1, msg2, &legacy_msg)) {
         return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
     }
@@ -867,11 +897,11 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-WifiStatus WifiNanIface::configRequest_1_2Internal(
+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_2ToLegacy(
+    if (!hidl_struct_util::convertHidlNanConfigRequest_1_4ToLegacy(
             msg1, msg2, &legacy_msg)) {
         return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
     }
@@ -881,7 +911,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_nan_iface.h b/wifi/1.4/default/wifi_nan_iface.h
similarity index 84%
rename from wifi/1.3/default/wifi_nan_iface.h
rename to wifi/1.4/default/wifi_nan_iface.h
index 737be93..c16628b 100644
--- a/wifi/1.3/default/wifi_nan_iface.h
+++ b/wifi/1.4/default/wifi_nan_iface.h
@@ -19,7 +19,7 @@
 
 #include <android-base/macros.h>
 #include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
-#include <android/hardware/wifi/1.2/IWifiNanIface.h>
+#include <android/hardware/wifi/1.4/IWifiNanIface.h>
 
 #include "hidl_callback_util.h"
 #include "wifi_iface_util.h"
@@ -28,14 +28,15 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+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_2::IWifiNanIface {
+class WifiNanIface : public V1_4::IWifiNanIface {
    public:
     WifiNanIface(const std::string& ifname,
                  const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
@@ -53,9 +54,11 @@
         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,
+    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 NanConfigRequest& msg,
+    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;
@@ -94,10 +97,18 @@
         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,
+        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;
@@ -110,9 +121,9 @@
         const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
     WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
     WifiStatus enableRequestInternal(uint16_t cmd_id,
-                                     const NanEnableRequest& msg);
+                                     const V1_0::NanEnableRequest& msg);
     WifiStatus configRequestInternal(uint16_t cmd_id,
-                                     const NanConfigRequest& msg);
+                                     const V1_0::NanConfigRequest& msg);
     WifiStatus disableRequestInternal(uint16_t cmd_id);
     WifiStatus startPublishRequestInternal(uint16_t cmd_id,
                                            const NanPublishRequest& msg);
@@ -136,9 +147,15 @@
     WifiStatus registerEventCallback_1_2Internal(
         const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
     WifiStatus enableRequest_1_2Internal(
-        uint16_t cmd_id, const NanEnableRequest& msg1,
+        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);
 
@@ -160,7 +177,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_p2p_iface.cpp b/wifi/1.4/default/wifi_p2p_iface.cpp
similarity index 97%
rename from wifi/1.3/default/wifi_p2p_iface.cpp
rename to wifi/1.4/default/wifi_p2p_iface.cpp
index b5d5886..9e7341f 100644
--- a/wifi/1.3/default/wifi_p2p_iface.cpp
+++ b/wifi/1.4/default/wifi_p2p_iface.cpp
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -60,7 +60,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_p2p_iface.h b/wifi/1.4/default/wifi_p2p_iface.h
similarity index 97%
rename from wifi/1.3/default/wifi_p2p_iface.h
rename to wifi/1.4/default/wifi_p2p_iface.h
index 8a7207a..a6fc59d 100644
--- a/wifi/1.3/default/wifi_p2p_iface.h
+++ b/wifi/1.4/default/wifi_p2p_iface.h
@@ -25,7 +25,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -58,7 +58,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_rtt_controller.cpp b/wifi/1.4/default/wifi_rtt_controller.cpp
similarity index 78%
rename from wifi/1.3/default/wifi_rtt_controller.cpp
rename to wifi/1.4/default/wifi_rtt_controller.cpp
index 3dcbee6..594a116 100644
--- a/wifi/1.3/default/wifi_rtt_controller.cpp
+++ b/wifi/1.4/default/wifi_rtt_controller.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -58,7 +58,7 @@
 }
 
 Return<void> WifiRttController::registerEventCallback(
-    const sp<IWifiRttControllerEventCallback>& callback,
+    const sp<V1_0::IWifiRttControllerEventCallback>& callback,
     registerEventCallback_cb hidl_status_cb) {
     return validateAndCall(this,
                            WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
@@ -67,7 +67,7 @@
 }
 
 Return<void> WifiRttController::rangeRequest(
-    uint32_t cmd_id, const hidl_vec<RttConfig>& rtt_configs,
+    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,
@@ -115,7 +115,7 @@
 
 Return<void> WifiRttController::enableResponder(
     uint32_t cmd_id, const WifiChannelInfo& channel_hint,
-    uint32_t max_duration_seconds, const RttResponder& info,
+    uint32_t max_duration_seconds, const V1_0::RttResponder& info,
     enableResponder_cb hidl_status_cb) {
     return validateAndCall(
         this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
@@ -130,49 +130,64 @@
         &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<IWifiRttControllerEventCallback>& callback) {
-    // TODO(b/31632518): remove the callback when the client is destroyed
-    event_callbacks_.emplace_back(callback);
-    return createWifiStatus(WifiStatusCode::SUCCESS);
+    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<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);
+    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(
@@ -187,21 +202,10 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-std::pair<WifiStatus, RttCapabilities>
+std::pair<WifiStatus, V1_0::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};
+    // Deprecated support for this api
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
 }
 
 WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id,
@@ -228,8 +232,84 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-std::pair<WifiStatus, RttResponder>
+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) =
@@ -245,7 +325,7 @@
     return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
 }
 
-WifiStatus WifiRttController::enableResponderInternal(
+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;
@@ -264,14 +344,8 @@
             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 V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_rtt_controller.h b/wifi/1.4/default/wifi_rtt_controller.h
similarity index 66%
rename from wifi/1.3/default/wifi_rtt_controller.h
rename to wifi/1.4/default/wifi_rtt_controller.h
index eedd22a..1f12555 100644
--- a/wifi/1.3/default/wifi_rtt_controller.h
+++ b/wifi/1.4/default/wifi_rtt_controller.h
@@ -19,21 +19,21 @@
 
 #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 <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_3 {
+namespace V1_4 {
 namespace implementation {
 
 /**
  * HIDL interface object used to control all RTT operations.
  */
-class WifiRttController : public V1_0::IWifiRttController {
+class WifiRttController : public V1_4::IWifiRttController {
    public:
     WifiRttController(
         const std::string& iface_name, const sp<IWifiIface>& bound_iface,
@@ -47,10 +47,10 @@
     // HIDL methods exposed.
     Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
     Return<void> registerEventCallback(
-        const sp<IWifiRttControllerEventCallback>& callback,
+        const sp<V1_0::IWifiRttControllerEventCallback>& callback,
         registerEventCallback_cb hidl_status_cb) override;
     Return<void> rangeRequest(uint32_t cmd_id,
-                              const hidl_vec<RttConfig>& rtt_configs,
+                              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,
@@ -64,29 +64,53 @@
     Return<void> enableResponder(uint32_t cmd_id,
                                  const WifiChannelInfo& channel_hint,
                                  uint32_t max_duration_seconds,
-                                 const RttResponder& info,
+                                 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<IWifiRttControllerEventCallback>& callback);
-    WifiStatus rangeRequestInternal(uint32_t cmd_id,
-                                    const std::vector<RttConfig>& rtt_configs);
+        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, RttCapabilities> getCapabilitiesInternal();
+    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, RttResponder> getResponderInfoInternal();
+    std::pair<WifiStatus, V1_0::RttResponder> getResponderInfoInternal();
     WifiStatus enableResponderInternal(uint32_t cmd_id,
                                        const WifiChannelInfo& channel_hint,
                                        uint32_t max_duration_seconds,
-                                       const RttResponder& info);
+                                       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_;
@@ -98,7 +122,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_sta_iface.cpp b/wifi/1.4/default/wifi_sta_iface.cpp
similarity index 98%
rename from wifi/1.3/default/wifi_sta_iface.cpp
rename to wifi/1.4/default/wifi_sta_iface.cpp
index a6539e5..e2ea6e4 100644
--- a/wifi/1.3/default/wifi_sta_iface.cpp
+++ b/wifi/1.4/default/wifi_sta_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -113,7 +113,7 @@
 }
 
 Return<void> WifiStaIface::getValidFrequenciesForBand(
-    WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
+    V1_0::WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
                            &WifiStaIface::getValidFrequenciesForBandInternal,
                            hidl_status_cb, band);
@@ -284,7 +284,7 @@
 
 std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
     legacy_hal::wifi_error legacy_status;
-    uint32_t legacy_feature_set;
+    uint64_t legacy_feature_set;
     std::tie(legacy_status, legacy_feature_set) =
         legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
@@ -356,7 +356,7 @@
 }
 
 std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiStaIface::getValidFrequenciesForBandInternal(WifiBand band) {
+WifiStaIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
     static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
                   "Size mismatch");
     legacy_hal::wifi_error legacy_status;
@@ -641,7 +641,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_sta_iface.h b/wifi/1.4/default/wifi_sta_iface.h
similarity index 97%
rename from wifi/1.3/default/wifi_sta_iface.h
rename to wifi/1.4/default/wifi_sta_iface.h
index 9224939..dee04f2 100644
--- a/wifi/1.3/default/wifi_sta_iface.h
+++ b/wifi/1.4/default/wifi_sta_iface.h
@@ -28,7 +28,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -63,7 +63,8 @@
     Return<void> getBackgroundScanCapabilities(
         getBackgroundScanCapabilities_cb hidl_status_cb) override;
     Return<void> getValidFrequenciesForBand(
-        WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override;
+        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;
@@ -128,7 +129,7 @@
     std::pair<WifiStatus, StaBackgroundScanCapabilities>
     getBackgroundScanCapabilitiesInternal();
     std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-    getValidFrequenciesForBandInternal(WifiBand band);
+    getValidFrequenciesForBandInternal(V1_0::WifiBand band);
     WifiStatus startBackgroundScanInternal(
         uint32_t cmd_id, const StaBackgroundScanParameters& params);
     WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
@@ -171,7 +172,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_status_util.cpp b/wifi/1.4/default/wifi_status_util.cpp
similarity index 94%
rename from wifi/1.3/default/wifi_status_util.cpp
rename to wifi/1.4/default/wifi_status_util.cpp
index 0a5bb13..8ceb926 100644
--- a/wifi/1.3/default/wifi_status_util.cpp
+++ b/wifi/1.4/default/wifi_status_util.cpp
@@ -19,7 +19,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 
 std::string legacyErrorToString(legacy_hal::wifi_error error) {
@@ -46,6 +46,8 @@
             return "BUSY";
         case legacy_hal::WIFI_ERROR_UNKNOWN:
             return "UNKNOWN";
+        default:
+            return "UNKNOWN ERROR";
     }
 }
 
@@ -92,6 +94,10 @@
 
         case legacy_hal::WIFI_ERROR_UNKNOWN:
             return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
+
+        default:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+                                    "unknown error");
     }
 }
 
@@ -100,7 +106,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/wifi_status_util.h b/wifi/1.4/default/wifi_status_util.h
similarity index 94%
rename from wifi/1.3/default/wifi_status_util.h
rename to wifi/1.4/default/wifi_status_util.h
index bc8baa9..3ff58f0 100644
--- a/wifi/1.3/default/wifi_status_util.h
+++ b/wifi/1.4/default/wifi_status_util.h
@@ -17,14 +17,14 @@
 #ifndef WIFI_STATUS_UTIL_H_
 #define WIFI_STATUS_UTIL_H_
 
-#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifi.h>
 
 #include "wifi_legacy_hal.h"
 
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -37,7 +37,7 @@
 WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
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..46ac3ee
--- /dev/null
+++ b/wifi/1.4/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.
+//
+
+// 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"
+    ],
+    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..017ecb6
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 {
+        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);
\ No newline at end of file
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..8ca5214
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+
+#undef NAN  // NAN is defined in bionic/libc/include/math.h:38
+
+#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::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_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 {
+        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:
+    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;
+    }
+}
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..245e906
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -0,0 +1,544 @@
+/*
+ * 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 {
+        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_;
+
+   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);
+}
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..31ade13
--- /dev/null
+++ b/wifi/hostapd/1.2/IHostapd.hal
@@ -0,0 +1,42 @@
+/*
+ * 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.1::IHostapd;
+import HostapdStatus;
+import MacAddress;
+import Ieee80211ReasonCode;
+
+/**
+ * Top-level object for managing SoftAPs.
+ */
+interface IHostapd extends @1.1::IHostapd {
+    /**
+     * 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);
+};
diff --git a/wifi/hostapd/1.2/types.hal b/wifi/hostapd/1.2/types.hal
new file mode 100644
index 0000000..06e890b
--- /dev/null
+++ b/wifi/hostapd/1.2/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.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,
+};
+
+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;
+};
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..0d37221
--- /dev/null
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -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.
+ */
+
+#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::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 int kIfaceChannel = 6;
+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);
+    }
+
+    virtual void TearDown() override { stopHostapd(wifi_instance_name_); }
+
+   protected:
+    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;
+        IHostapd::IfaceParams iface_params_1_1;
+
+        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.channelParams.band = IHostapd::Band::BAND_2_4_GHZ;
+        iface_params_1_1.V1_0 = iface_params;
+        return iface_params_1_1;
+    }
+
+    IHostapd::NetworkParams getOpenNwParams() {
+        IHostapd::NetworkParams nw_params;
+        nw_params.ssid =
+            std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+        nw_params.isHidden = false;
+        nw_params.encryptionType = IHostapd::EncryptionType::NONE;
+        return nw_params;
+    }
+
+    // IHostapd object used for all tests in this fixture.
+    sp<IHostapd> hostapd_;
+    std::string wifi_instance_name_;
+    std::string hostapd_instance_name_;
+};
+
+/**
+ * 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_0 =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(),
+                    getOpenNwParams());
+    EXPECT_EQ(
+        android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
+        status_1_0.code);
+
+    auto status_1_2 =
+        HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(),
+                    kTestZeroMacAddr, kTestDisconnectReasonCode);
+    EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.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.3/Android.bp b/wifi/supplicant/1.3/Android.bp
new file mode 100644
index 0000000..3f20531
--- /dev/null
+++ b/wifi/supplicant/1.3/Android.bp
@@ -0,0 +1,23 @@
+// 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.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..bfd8946
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal
@@ -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.
+ */
+
+package android.hardware.wifi.supplicant@1.3;
+
+import @1.0::SupplicantStatus;
+import @1.2::ISupplicantStaIface;
+import ISupplicantStaIfaceCallback;
+
+/**
+ * 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 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);
+};
diff --git a/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
new file mode 100644
index 0000000..107e0fc
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaIfaceCallback.hal
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * 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 {
+    /**
+     * Indicates 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);
+};
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
new file mode 100644
index 0000000..ab08cff
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.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.wifi.supplicant@1.3;
+
+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 {
+    /**
+     * 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);
+
+    /**
+     * Add a 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);
+};
diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal
new file mode 100644
index 0000000..4e01ab1
--- /dev/null
+++ b/wifi/supplicant/1.3/types.hal
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant@1.3;
+
+/**
+ * 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.
+ */
+struct ConnectionCapabilities {
+    /**
+     * Wifi Technology
+     */
+    WifiTechnology technology;
+};
+
+/**
+ * WPA Driver capability.
+ */
+enum WpaDriverCapabilitiesMask : uint32_t {
+    /**
+     * Multi Band Operation.
+     */
+    MBO = 1 << 0,
+    /**
+     * Optimized Connectivity Experience.
+     */
+    OCE = 1 << 1,
+};
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..abb8600
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/Android.bp
@@ -0,0 +1,65 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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"],
+}
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..4dbb64e
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.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.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "wifi_hidl_test_utils.h"
+
+class WifiSupplicantHidlEnvironment_1_3 : public WifiSupplicantHidlEnvironment {
+   public:
+    // get the test environment singleton
+    static WifiSupplicantHidlEnvironment_1_3* Instance() {
+        static WifiSupplicantHidlEnvironment_1_3* instance =
+            new WifiSupplicantHidlEnvironment_1_3;
+        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>();
+        registerTestService<
+            ::android::hardware::wifi::supplicant::V1_3::ISupplicant>();
+    }
+
+   private:
+    WifiSupplicantHidlEnvironment_1_3() {}
+};
+
+WifiSupplicantHidlEnvironment* gEnv =
+    WifiSupplicantHidlEnvironment_1_3::Instance();
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnv->init(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        int status = RUN_ALL_TESTS();
+        LOG(INFO) << "Test result = " << status;
+    }
+    return status;
+}
diff --git a/wifi/supplicant/1.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..308808d
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp
@@ -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.
+ */
+
+#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_3::ISupplicantStaIface;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
+
+sp<ISupplicantStaIface> getSupplicantStaIface_1_3() {
+    return ISupplicantStaIface::castFrom(getSupplicantStaIface());
+}
+
+sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_3() {
+    return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork());
+}
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..39dbb8f
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+
+android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface>
+getSupplicantStaIface_1_3();
+android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork>
+createSupplicantStaNetwork_1_3();
+
+#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..2cf5881
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/hardware/wifi/supplicant/1.2/types.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 <hidl/HidlSupport.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::DppProgressCode;
+using ::android::hardware::wifi::supplicant::V1_3::ConnectionCapabilities;
+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;
+
+class SupplicantStaIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        startSupplicantAndWaitForHidlService();
+        EXPECT_TRUE(turnOnExcessiveLogging());
+        sta_iface_ = getSupplicantStaIface_1_3();
+        ASSERT_NE(sta_iface_.get(), nullptr);
+    }
+
+    virtual void TearDown() override { stopSupplicant(); }
+
+    int64_t pmkCacheExpirationTimeInSec;
+    std::vector<uint8_t> serializedPmkCacheEntry;
+
+   protected:
+    // ISupplicantStaIface object used for all tests in this fixture.
+    sp<ISupplicantStaIface> sta_iface_;
+};
+
+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> 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> onPmkCacheAdded(
+        int64_t /* expirationTimeInSec */,
+        const hidl_vec<uint8_t>& /* serializedEntry */) 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) {}
+};
+
+/*
+ * RegisterCallback_1_3
+ */
+TEST_F(SupplicantStaIfaceHidlTest, RegisterCallback_1_3) {
+    sta_iface_->registerCallback_1_3(
+        new IfaceCallback(), [](const SupplicantStatus& status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
+
+/*
+ * getConnectionCapabilities
+ */
+TEST_F(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) {
+    sta_iface_->getConnectionCapabilities(
+        [&](const SupplicantStatus& status,
+            ConnectionCapabilities /* capabilities */) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
+
+/*
+ * GetWpaDriverCapabilities
+ */
+TEST_F(SupplicantStaIfaceHidlTest, GetWpaDriverCapabilities) {
+    sta_iface_->getWpaDriverCapabilities(
+        [&](const SupplicantStatus& status, uint32_t) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
+
+/*
+ * SetMboCellularDataStatus
+ */
+TEST_F(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);
+        });
+}
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..07bc9d8
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -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.
+ */
+
+#include <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_3.h"
+
+using ::android::sp;
+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::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::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        startSupplicantAndWaitForHidlService();
+        EXPECT_TRUE(turnOnExcessiveLogging());
+        sta_network_ = createSupplicantStaNetwork_1_3();
+        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_;
+};
+
+/*
+ * SetGetOcsp
+ */
+TEST_F(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_F(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);
+        });
+}