Merge "IBootControl: Use new defaultPassthroughServiceImplementation signature." am: 240c726150 am: b1ec4c6aa1
am: decc075e5f

Change-Id: I14c96f8da4c6bdff019809cf926fe24ec84512ed
diff --git a/CleanSpec.mk b/CleanSpec.mk
index edde1cb..76594fb 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -80,3 +80,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/android.hardware.configstore@1.2.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk-Q/android.hardware.configstore@1.2.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/android.hardware.configstore@1.2.so)
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/etc/init/android.hardware.audio@2.0-service.rc $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.audio@2.0-service)
+$(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*)
diff --git a/audio/6.0/Android.bp b/audio/6.0/Android.bp
new file mode 100644
index 0000000..dc6bb98
--- /dev/null
+++ b/audio/6.0/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio@6.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IDevice.hal",
+        "IDevicesFactory.hal",
+        "IPrimaryDevice.hal",
+        "IStream.hal",
+        "IStreamIn.hal",
+        "IStreamOut.hal",
+        "IStreamOutCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.effect@6.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/audio/6.0/IDevice.hal b/audio/6.0/IDevice.hal
new file mode 100644
index 0000000..e885fe2
--- /dev/null
+++ b/audio/6.0/IDevice.hal
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStreamIn;
+import IStreamOut;
+
+interface IDevice {
+    /**
+     * Returns whether the audio hardware interface has been initialized.
+     *
+     * @return retval OK on success, NOT_INITIALIZED on failure.
+     */
+    initCheck() generates (Result retval);
+
+    /**
+     * Sets the audio volume for all audio activities other than voice call. If
+     * NOT_SUPPORTED is returned, the software mixer will emulate this
+     * capability.
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setMasterVolume(float volume) generates (Result retval);
+
+    /**
+     * Get the current master volume value for the HAL, if the HAL supports
+     * master volume control. For example, AudioFlinger will query this value
+     * from the primary audio HAL when the service starts and use the value for
+     * setting the initial master volume across all HALs. HALs which do not
+     * support this method must return NOT_SUPPORTED in 'retval'.
+     *
+     * @return retval operation completion status.
+     * @return volume 1.0f means unity, 0.0f is zero.
+     */
+    getMasterVolume() generates (Result retval, float volume);
+
+    /**
+     * Sets microphone muting state.
+     *
+     * @param mute whether microphone is muted.
+     * @return retval operation completion status.
+     */
+    setMicMute(bool mute) generates (Result retval);
+
+    /**
+     * Gets whether microphone is muted.
+     *
+     * @return retval operation completion status.
+     * @return mute whether microphone is muted.
+     */
+    getMicMute() generates (Result retval, bool mute);
+
+    /**
+     * Set the audio mute status for all audio activities. If the return value
+     * is NOT_SUPPORTED, the software mixer will emulate this capability.
+     *
+     * @param mute whether audio is muted.
+     * @return retval operation completion status.
+     */
+    setMasterMute(bool mute) generates (Result retval);
+
+    /**
+     * Get the current master mute status for the HAL, if the HAL supports
+     * master mute control. AudioFlinger will query this value from the primary
+     * audio HAL when the service starts and use the value for setting the
+     * initial master mute across all HALs. HAL must indicate that the feature
+     * is not supported by returning NOT_SUPPORTED status.
+     *
+     * @return retval operation completion status.
+     * @return mute whether audio is muted.
+     */
+    getMasterMute() generates (Result retval, bool mute);
+
+    /**
+     * Returns audio input buffer size according to parameters passed or
+     * INVALID_ARGUMENTS if one of the parameters is not supported.
+     *
+     * @param config audio configuration.
+     * @return retval operation completion status.
+     * @return bufferSize input buffer size in bytes.
+     */
+    getInputBufferSize(AudioConfig config)
+            generates (Result retval, uint64_t bufferSize);
+
+    /**
+     * This method creates and opens the audio hardware output stream.
+     * If the stream can not be opened with the proposed audio config,
+     * HAL must provide suggested values for the audio config.
+     *
+     * @param ioHandle handle assigned by AudioFlinger.
+     * @param device device type and (if needed) address.
+     * @param config stream configuration.
+     * @param flags additional flags.
+     * @param sourceMetadata Description of the audio that will be played.
+                             May be used by implementations to configure hardware effects.
+     * @return retval operation completion status.
+     * @return outStream created output stream.
+     * @return suggestedConfig in case of invalid parameters, suggested config.
+     */
+    openOutputStream(
+            AudioIoHandle ioHandle,
+            DeviceAddress device,
+            AudioConfig config,
+            bitfield<AudioOutputFlag> flags,
+            SourceMetadata sourceMetadata) generates (
+                    Result retval,
+                    IStreamOut outStream,
+                    AudioConfig suggestedConfig);
+
+    /**
+     * This method creates and opens the audio hardware input stream.
+     * If the stream can not be opened with the proposed audio config,
+     * HAL must provide suggested values for the audio config.
+     *
+     * @param ioHandle handle assigned by AudioFlinger.
+     * @param device device type and (if needed) address.
+     * @param config stream configuration.
+     * @param flags additional flags.
+     * @param sinkMetadata Description of the audio that is suggested by the client.
+     *                     May be used by implementations to configure processing effects.
+     * @return retval operation completion status.
+     * @return inStream in case of success, created input stream.
+     * @return suggestedConfig in case of invalid parameters, suggested config.
+     */
+    openInputStream(
+            AudioIoHandle ioHandle,
+            DeviceAddress device,
+            AudioConfig config,
+            bitfield<AudioInputFlag> flags,
+            SinkMetadata sinkMetadata) generates (
+                    Result retval,
+                    IStreamIn inStream,
+                    AudioConfig suggestedConfig);
+
+    /**
+     * Returns whether HAL supports audio patches.
+     *
+     * @return supports true if audio patches are supported.
+     */
+    supportsAudioPatches() generates (bool supports);
+
+    /**
+     * Creates an audio patch between several source and sink ports.  The handle
+     * is allocated by the HAL and must be unique for this audio HAL module.
+     *
+     * @param sources patch sources.
+     * @param sinks patch sinks.
+     * @return retval operation completion status.
+     * @return patch created patch handle.
+     */
+    createAudioPatch(vec<AudioPortConfig> sources, vec<AudioPortConfig> sinks)
+            generates (Result retval, AudioPatchHandle patch);
+
+    /**
+     * Release an audio patch.
+     *
+     * @param patch patch handle.
+     * @return retval operation completion status.
+     */
+    releaseAudioPatch(AudioPatchHandle patch) generates (Result retval);
+
+    /**
+     * Returns the list of supported attributes for a given audio port.
+     *
+     * As input, 'port' contains the information (type, role, address etc...)
+     * needed by the HAL to identify the port.
+     *
+     * As output, 'resultPort' contains possible attributes (sampling rates,
+     * formats, channel masks, gain controllers...) for this port.
+     *
+     * @param port port identifier.
+     * @return retval operation completion status.
+     * @return resultPort port descriptor with all parameters filled up.
+     */
+    getAudioPort(AudioPort port)
+            generates (Result retval, AudioPort resultPort);
+
+    /**
+     * Set audio port configuration.
+     *
+     * @param config audio port configuration.
+     * @return retval operation completion status.
+     */
+    setAudioPortConfig(AudioPortConfig config) generates (Result retval);
+
+    /**
+     * Gets the HW synchronization source of the device. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_HW_AV_SYNC on the legacy HAL.
+     * Optional method
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     * @return hwAvSync HW synchronization source
+     */
+    getHwAvSync() generates (Result retval, AudioHwSync hwAvSync);
+
+    /**
+     * Sets whether the screen is on. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_KEY_SCREEN_STATE on the legacy HAL.
+     * Optional method
+     *
+     * @param turnedOn whether the screen is turned on.
+     * @return retval operation completion status.
+     */
+    setScreenState(bool turnedOn) generates (Result retval);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be retrieved at the same time.
+     * The implementation should return as many requested parameters
+     * as possible, even if one or more is not supported
+     *
+     * @param context provides more information about the request
+     * @param keys keys of the requested parameters
+     * @return retval operation completion status.
+     *         OK must be returned if keys is empty.
+     *         NOT_SUPPORTED must be returned if at least one key is unknown.
+     * @return parameters parameter key value pairs.
+     *         Must contain the value of all requested keys if retval == OK
+     */
+    getParameters(vec<ParameterValue> context, vec<string> keys)
+            generates (Result retval, vec<ParameterValue> parameters);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be set at the same time though this is
+     * discouraged as it make failure analysis harder.
+     *
+     * If possible, a failed setParameters should not impact the platform state.
+     *
+     * @param context provides more information about the request
+     * @param parameters parameter key value pairs.
+     * @return retval operation completion status.
+     *         All parameters must be successfully set for OK to be returned
+     */
+    setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+            generates (Result retval);
+
+    /**
+     * Returns an array with available microphones in device.
+     *
+     * @return retval NOT_SUPPORTED if there are no microphones on this device
+     *                INVALID_STATE if the call is not successful,
+     *                OK otherwise.
+     *
+     * @return microphones array with microphones info
+     */
+    getMicrophones()
+         generates(Result retval, vec<MicrophoneInfo> microphones);
+
+    /**
+     * Notifies the device module about the connection state of an input/output
+     * device attached to it. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy HAL.
+     *
+     * @param address audio device specification.
+     * @param connected whether the device is connected.
+     * @return retval operation completion status.
+     */
+    setConnectedState(DeviceAddress address, bool connected)
+            generates (Result retval);
+};
diff --git a/audio/6.0/IDevicesFactory.hal b/audio/6.0/IDevicesFactory.hal
new file mode 100644
index 0000000..0483473
--- /dev/null
+++ b/audio/6.0/IDevicesFactory.hal
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IDevice;
+import IPrimaryDevice;
+
+/** This factory allows a HAL implementation to be split in multiple independent
+ *  devices (called module in the pre-treble API).
+ *  Note that this division is arbitrary and implementation are free
+ *  to only have a Primary.
+ *  The framework will query the devices according to audio_policy_configuration.xml
+ *
+ *  Each device name is arbitrary, provided by the vendor's audio_policy_configuration.xml
+ *  and only used to identify a device in this factory.
+ *  The framework must not interpret the name, treating it as a vendor opaque data
+ *  with the following exception:
+ *  - the "r_submix" device that must be present to support policyMixes (Eg: Android projected).
+ *    Note that this Device is included by default in a build derived from AOSP.
+ *
+ *  Note that on AOSP Oreo (including MR1) the "a2dp" module is not using this API
+ *  but is loaded directly from the system partition using the legacy API
+ *  due to limitations with the Bluetooth framework.
+ */
+interface IDevicesFactory {
+
+    /**
+     * Opens an audio device. To close the device, it is necessary to release
+     * references to the returned device object.
+     *
+     * @param device device name.
+     * @return retval operation completion status. Returns INVALID_ARGUMENTS
+     *         if there is no corresponding hardware module found,
+     *         NOT_INITIALIZED if an error occurred while opening the hardware
+     *         module.
+     * @return result the interface for the created device.
+     */
+    openDevice(string device) generates (Result retval, IDevice result);
+
+    /**
+     * Opens the Primary audio device that must be present.
+     * This function is not optional and must return successfully the primary device.
+     *
+     * This device must have the name "primary".
+     *
+     * The telephony stack uses this device to control the audio during a voice call.
+     *
+     * @return retval operation completion status. Must be SUCCESS.
+     *         For debugging, return INVALID_ARGUMENTS if there is no corresponding
+     *         hardware module found, NOT_INITIALIZED if an error occurred
+     *         while opening the hardware module.
+     * @return result the interface for the created device.
+     */
+    openPrimaryDevice() generates (Result retval, IPrimaryDevice result);
+};
diff --git a/audio/6.0/IPrimaryDevice.hal b/audio/6.0/IPrimaryDevice.hal
new file mode 100644
index 0000000..78cfc65
--- /dev/null
+++ b/audio/6.0/IPrimaryDevice.hal
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IDevice;
+
+interface IPrimaryDevice extends IDevice {
+    /**
+     * Sets the audio volume of a voice call.
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setVoiceVolume(float volume) generates (Result retval);
+
+    /**
+     * This method is used to notify the HAL about audio mode changes.
+     *
+     * @param mode new mode.
+     * @return retval operation completion status.
+     */
+    setMode(AudioMode mode) generates (Result retval);
+
+    /**
+     * Sets the name of the current BT SCO headset. Calling this method
+     * is equivalent to setting legacy "bt_headset_name" parameter.
+     * The BT SCO headset name must only be used for debugging purposes.
+     * Optional method
+     *
+     * @param name the name of the current BT SCO headset (can be empty).
+     * @return retval operation completion status.
+     */
+    setBtScoHeadsetDebugName(string name) generates (Result retval);
+
+    /**
+     * Gets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+     * Calling this method is equivalent to getting AUDIO_PARAMETER_KEY_BT_NREC
+     * on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT SCO NR + EC are enabled.
+     */
+    getBtScoNrecEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+     * Calling this method is equivalent to setting AUDIO_PARAMETER_KEY_BT_NREC
+     * on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT SCO NR + EC are enabled.
+     * @return retval operation completion status.
+     */
+    setBtScoNrecEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Gets whether BT SCO Wideband mode is enabled. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT Wideband is enabled.
+     */
+    getBtScoWidebandEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT SCO Wideband mode is enabled. Calling this method is
+     * equivalent to setting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT Wideband is enabled.
+     * @return retval operation completion status.
+     */
+    setBtScoWidebandEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Gets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+     * is equivalent to getting "hfp_enable" parameter value on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT HFP is enabled.
+     */
+    getBtHfpEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+     * is equivalent to setting "hfp_enable" parameter on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT HFP is enabled.
+     * @return retval operation completion status.
+     */
+    setBtHfpEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Sets the sampling rate of BT HFP (Hands-Free Profile). Calling this
+     * method is equivalent to setting "hfp_set_sampling_rate" parameter
+     * on the legacy HAL.
+     * Optional method
+     *
+     * @param sampleRateHz sample rate in Hz.
+     * @return retval operation completion status.
+     */
+    setBtHfpSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+    /**
+     * Sets the current output volume Hz for BT HFP (Hands-Free Profile).
+     * Calling this method is equivalent to setting "hfp_volume" parameter value
+     * on the legacy HAL (except that legacy HAL implementations expect
+     * an integer value in the range from 0 to 15.)
+     * Optional method
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setBtHfpVolume(float volume) generates (Result retval);
+
+    enum TtyMode : int32_t {
+        OFF,
+        VCO,
+        HCO,
+        FULL
+    };
+
+    /**
+     * Gets current TTY mode selection. Calling this method is equivalent to
+     * getting AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return mode TTY mode.
+     */
+    getTtyMode() generates (Result retval, TtyMode mode);
+
+    /**
+     * Sets current TTY mode. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+     *
+     * @param mode TTY mode.
+     * @return retval operation completion status.
+     */
+    setTtyMode(TtyMode mode) generates (Result retval);
+
+    /**
+     * Gets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+     * enabled. Calling this method is equivalent to getting
+     * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether HAC mode is enabled.
+     */
+    getHacEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+     * enabled. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether HAC mode is enabled.
+     * @return retval operation completion status.
+     */
+    setHacEnabled(bool enabled) generates (Result retval);
+
+    enum Rotation : int32_t {
+        DEG_0,
+        DEG_90,
+        DEG_180,
+        DEG_270
+    };
+
+    /**
+     * Updates HAL on the current rotation of the device relative to natural
+     * orientation. Calling this method is equivalent to setting legacy
+     * parameter "rotation".
+     *
+     * @param rotation rotation in degrees relative to natural device
+     *     orientation.
+     * @return retval operation completion status.
+     */
+    updateRotation(Rotation rotation) generates (Result retval);
+};
diff --git a/audio/6.0/IStream.hal b/audio/6.0/IStream.hal
new file mode 100644
index 0000000..f4c91f8
--- /dev/null
+++ b/audio/6.0/IStream.hal
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import android.hardware.audio.effect@6.0::IEffect;
+
+interface IStream {
+    /**
+     * Return the frame size (number of bytes per sample).
+     *
+     * @return frameSize frame size in bytes.
+     */
+    getFrameSize() generates (uint64_t frameSize);
+
+    /**
+     * Return the frame count of the buffer. Calling this method is equivalent
+     * to getting AUDIO_PARAMETER_STREAM_FRAME_COUNT on the legacy HAL.
+     *
+     * @return count frame count.
+     */
+    getFrameCount() generates (uint64_t count);
+
+    /**
+     * Return the size of input/output buffer in bytes for this stream.
+     * It must be a multiple of the frame size.
+     *
+     * @return buffer buffer size in bytes.
+     */
+    getBufferSize() generates (uint64_t bufferSize);
+
+    /**
+     * Return the sampling rate in Hz.
+     *
+     * @return sampleRateHz sample rate in Hz.
+     */
+    getSampleRate() generates (uint32_t sampleRateHz);
+
+    /**
+     * Return supported native sampling rates of the stream for a given format.
+     * A supported native sample rate is a sample rate that can be efficiently
+     * played by the hardware (typically without sample-rate conversions).
+     *
+     * This function is only called for dynamic profile. If called for
+     * non-dynamic profile is should return NOT_SUPPORTED or the same list
+     * as in audio_policy_configuration.xml.
+     *
+     * Calling this method is equivalent to getting
+     * AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES on the legacy HAL.
+     *
+     *
+     * @param format audio format for which the sample rates are supported.
+     * @return retval operation completion status.
+     *                Must be OK if the format is supported.
+     * @return sampleRateHz supported sample rates.
+     */
+    getSupportedSampleRates(AudioFormat format)
+            generates (Result retval, vec<uint32_t> sampleRates);
+
+    /**
+     * Sets the sampling rate of the stream. Calling this method is equivalent
+     * to setting AUDIO_PARAMETER_STREAM_SAMPLING_RATE on the legacy HAL.
+     * Optional method. If implemented, only called on a stopped stream.
+     *
+     * @param sampleRateHz sample rate in Hz.
+     * @return retval operation completion status.
+     */
+    setSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+    /**
+     * Return the channel mask of the stream.
+     *
+     * @return mask channel mask.
+     */
+    getChannelMask() generates (bitfield<AudioChannelMask> mask);
+
+    /**
+     * Return supported channel masks of the stream. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_CHANNELS on the legacy
+     * HAL.
+     *
+     * @param format audio format for which the channel masks are supported.
+     * @return retval operation completion status.
+     *                Must be OK if the format is supported.
+     * @return masks supported audio masks.
+     */
+    getSupportedChannelMasks(AudioFormat format)
+            generates (Result retval, vec<bitfield<AudioChannelMask>> masks);
+
+    /**
+     * Sets the channel mask of the stream. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_STREAM_CHANNELS on the legacy HAL.
+     * Optional method
+     *
+     * @param format audio format.
+     * @return retval operation completion status.
+     */
+    setChannelMask(bitfield<AudioChannelMask> mask) generates (Result retval);
+
+    /**
+     * Return the audio format of the stream.
+     *
+     * @return format audio format.
+     */
+    getFormat() generates (AudioFormat format);
+
+    /**
+     * Return supported audio formats of the stream. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy
+     * HAL.
+     *
+     * @return formats supported audio formats.
+     */
+    getSupportedFormats() generates (vec<AudioFormat> formats);
+
+    /**
+     * Sets the audio format of the stream. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_STREAM_FORMAT on the legacy HAL.
+     * Optional method
+     *
+     * @param format audio format.
+     * @return retval operation completion status.
+     */
+    setFormat(AudioFormat format) generates (Result retval);
+
+    /**
+     * Convenience method for retrieving several stream parameters in
+     * one transaction.
+     *
+     * @return sampleRateHz sample rate in Hz.
+     * @return mask channel mask.
+     * @return format audio format.
+     */
+    getAudioProperties() generates (
+            uint32_t sampleRateHz, bitfield<AudioChannelMask> mask, AudioFormat format);
+
+    /**
+     * Applies audio effect to the stream.
+     *
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect to apply.
+     * @return retval operation completion status.
+     */
+    addEffect(uint64_t effectId) generates (Result retval);
+
+    /**
+     * Stops application of the effect to the stream.
+     *
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect to remove.
+     * @return retval operation completion status.
+     */
+    removeEffect(uint64_t effectId) generates (Result retval);
+
+    /**
+     * Put the audio hardware input/output into standby mode.
+     * Driver must exit from standby mode at the next I/O operation.
+     *
+     * @return retval operation completion status.
+     */
+    standby() generates (Result retval);
+
+    /**
+     * Return the set of devices which this stream is connected to.
+     * Optional method
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     * @return device set of devices which this stream is connected to.
+     */
+    getDevices() generates (Result retval, vec<DeviceAddress> devices);
+
+    /**
+     * Connects the stream to one or multiple devices.
+     *
+     * This method must only be used for HALs that do not support
+     * 'IDevice.createAudioPatch' method. Calling this method is
+     * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING preceded
+     * with a device address in the legacy HAL interface.
+     *
+     * @param address device to connect the stream to.
+     * @return retval operation completion status.
+     */
+    setDevices(vec<DeviceAddress> devices) generates (Result retval);
+
+    /**
+     * Sets the HW synchronization source. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_STREAM_HW_AV_SYNC on the legacy HAL.
+     * Optional method
+     *
+     * @param hwAvSync HW synchronization source
+     * @return retval operation completion status.
+     */
+    setHwAvSync(AudioHwSync hwAvSync) generates (Result retval);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be retrieved at the same time.
+     * The implementation should return as many requested parameters
+     * as possible, even if one or more is not supported
+     *
+     * @param context provides more information about the request
+     * @param keys keys of the requested parameters
+     * @return retval operation completion status.
+     *         OK must be returned if keys is empty.
+     *         NOT_SUPPORTED must be returned if at least one key is unknown.
+     * @return parameters parameter key value pairs.
+     *         Must contain the value of all requested keys if retval == OK
+     */
+    getParameters(vec<ParameterValue> context, vec<string> keys)
+            generates (Result retval, vec<ParameterValue> parameters);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be set at the same time though this is
+     * discouraged as it make failure analysis harder.
+     *
+     * If possible, a failed setParameters should not impact the platform state.
+     *
+     * @param context provides more information about the request
+     * @param parameters parameter key value pairs.
+     * @return retval operation completion status.
+     *         All parameters must be successfully set for OK to be returned
+     */
+    setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+            generates (Result retval);
+
+    /**
+     * Called by the framework to start a stream operating in mmap mode.
+     * createMmapBuffer() must be called before calling start().
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     */
+    start() generates (Result retval);
+
+    /**
+     * Called by the framework to stop a stream operating in mmap mode.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     */
+    stop() generates (Result retval) ;
+
+    /**
+     * Called by the framework to retrieve information on the mmap buffer used for audio
+     * samples transfer.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @param minSizeFrames minimum buffer size requested. The actual buffer
+     *                     size returned in struct MmapBufferInfo can be larger.
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                NOT_INITIALIZED in case of memory allocation error
+     *                INVALID_ARGUMENTS if the requested buffer size is too large
+     *                INVALID_STATE if called out of sequence
+     * @return info    a MmapBufferInfo struct containing information on the MMMAP buffer created.
+     */
+    createMmapBuffer(int32_t minSizeFrames)
+            generates (Result retval, MmapBufferInfo info);
+
+    /**
+     * Called by the framework to read current read/write position in the mmap buffer
+     * with associated time stamp.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     * @return position a MmapPosition struct containing current HW read/write position in frames
+     *                  with associated time stamp.
+     */
+    getMmapPosition()
+            generates (Result retval, MmapPosition position);
+
+    /**
+     * Called by the framework to deinitialize the stream and free up
+     * all the currently allocated resources. It is recommended to close
+     * the stream on the client side as soon as it is becomes unused.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED if called on IStream instead of input or
+     *                              output stream interface.
+     *                INVALID_STATE if the stream was already closed.
+     */
+    close() generates (Result retval);
+};
diff --git a/audio/6.0/IStreamIn.hal b/audio/6.0/IStreamIn.hal
new file mode 100644
index 0000000..aadc370
--- /dev/null
+++ b/audio/6.0/IStreamIn.hal
@@ -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.
+ */
+
+package android.hardware.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStream;
+
+interface IStreamIn extends IStream {
+    /**
+     * Returns the source descriptor of the input stream. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_STREAM_INPUT_SOURCE on the legacy
+     * HAL.
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return source audio source.
+     */
+    getAudioSource() generates (Result retval, AudioSource source);
+
+    /**
+     * Set the input gain for the audio driver.
+     * Optional method
+     *
+     * @param gain 1.0f is unity, 0.0f is zero.
+     * @result retval operation completion status.
+     */
+    setGain(float gain) generates (Result retval);
+
+    /**
+     * Commands that can be executed on the driver reader thread.
+     */
+    enum ReadCommand : int32_t {
+        READ,
+        GET_CAPTURE_POSITION
+    };
+
+    /**
+     * Data structure passed to the driver for executing commands
+     * on the driver reader thread.
+     */
+    struct ReadParameters {
+        ReadCommand command;  // discriminator
+        union Params {
+            uint64_t read;    // READ command, amount of bytes to read, >= 0.
+            // No parameters for GET_CAPTURE_POSITION.
+        } params;
+    };
+
+    /**
+     * Data structure passed back to the client via status message queue
+     * of 'read' operation.
+     *
+     * Possible values of 'retval' field:
+     *  - OK, read operation was successful;
+     *  - INVALID_ARGUMENTS, stream was not configured properly;
+     *  - INVALID_STATE, stream is in a state that doesn't allow reads.
+     */
+    struct ReadStatus {
+        Result retval;
+        ReadCommand replyTo;  // discriminator
+        union Reply {
+            uint64_t read;    // READ command, amount of bytes read, >= 0.
+            struct CapturePosition { // same as generated by getCapturePosition.
+                uint64_t frames;
+                uint64_t time;
+            } capturePosition;
+        } reply;
+    };
+
+    /**
+     * Called when the metadata of the stream's sink has been changed.
+     * @param sinkMetadata Description of the audio that is suggested by the clients.
+     */
+    updateSinkMetadata(SinkMetadata sinkMetadata);
+
+    /**
+     * Set up required transports for receiving audio buffers from the driver.
+     *
+     * The transport consists of three message queues:
+     *  -- command queue is used to instruct the reader thread what operation
+     *     to perform;
+     *  -- data queue is used for passing audio data from the driver
+     *     to the client;
+     *  -- status queue is used for reporting operation status
+     *     (e.g. amount of bytes actually read or error code).
+     *
+     * The driver operates on a dedicated thread. The client must ensure that
+     * the thread is given an appropriate priority and assigned to correct
+     * scheduler and cgroup. For this purpose, the method returns identifiers
+     * of the driver thread.
+     *
+     * @param frameSize the size of a single frame, in bytes.
+     * @param framesCount the number of frames in a buffer.
+     * @param threadPriority priority of the driver thread.
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queues.
+     * @return commandMQ a message queue used for passing commands.
+     * @return dataMQ a message queue used for passing audio data in the format
+     *                specified at the stream opening.
+     * @return statusMQ a message queue used for passing status from the driver
+     *                  using ReadStatus structures.
+     * @return threadInfo identifiers of the driver's dedicated thread.
+     */
+    prepareForReading(uint32_t frameSize, uint32_t framesCount)
+    generates (
+            Result retval,
+            fmq_sync<ReadParameters> commandMQ,
+            fmq_sync<uint8_t> dataMQ,
+            fmq_sync<ReadStatus> statusMQ,
+            ThreadInfo threadInfo);
+
+    /**
+     * Return the amount of input frames lost in the audio driver since the last
+     * call of this function.
+     *
+     * Audio driver is expected to reset the value to 0 and restart counting
+     * upon returning the current value by this function call. Such loss
+     * typically occurs when the user space process is blocked longer than the
+     * capacity of audio driver buffers.
+     *
+     * @return framesLost the number of input audio frames lost.
+     */
+    getInputFramesLost() generates (uint32_t framesLost);
+
+    /**
+     * Return a recent count of the number of audio frames received and the
+     * clock time associated with that frame count.
+     *
+     * @return retval INVALID_STATE if the device is not ready/available,
+     *                NOT_SUPPORTED if the command is not supported,
+     *                OK otherwise.
+     * @return frames the total frame count received. This must be as early in
+     *                the capture pipeline as possible. In general, frames
+     *                must be non-negative and must not go "backwards".
+     * @return time is the clock monotonic time when frames was measured. In
+     *              general, time must be a positive quantity and must not
+     *              go "backwards".
+     */
+    getCapturePosition()
+            generates (Result retval, uint64_t frames, uint64_t time);
+
+    /**
+     * Returns an array with active microphones in the stream.
+     *
+     * @return retval INVALID_STATE if the call is not successful,
+     *                OK otherwise.
+     *
+     * @return microphones array with microphones info
+     */
+    getActiveMicrophones()
+               generates(Result retval, vec<MicrophoneInfo> microphones);
+
+    /**
+     * Specifies the logical microphone (for processing).
+     *
+     * If the feature is not supported an error should be returned
+     * If multiple microphones are present, this should be treated as a preference
+     * for their combined direction.
+     *
+     * Optional method
+     *
+     * @param Direction constant
+     * @return retval OK if the call is successful, an error code otherwise.
+     */
+    setMicrophoneDirection(MicrophoneDirection direction)
+               generates(Result retval);
+
+    /**
+     * Specifies the zoom factor for the selected microphone (for processing).
+     *
+     * If the feature is not supported an error should be returned
+     * If multiple microphones are present, this should be treated as a preference
+     * for their combined field dimension.
+     *
+     * Optional method
+     *
+     * @param the desired field dimension of microphone capture. Range is from -1 (wide angle),
+     * though 0 (no zoom) to 1 (maximum zoom).
+     *
+     * @return retval OK if the call is not successful, an error code otherwise.
+     */
+    setMicrophoneFieldDimension(float zoom) generates(Result retval);
+};
diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal
new file mode 100644
index 0000000..941ba61
--- /dev/null
+++ b/audio/6.0/IStreamOut.hal
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+import IStream;
+import IStreamOutCallback;
+
+interface IStreamOut extends IStream {
+    /**
+     * Return the audio hardware driver estimated latency in milliseconds.
+     *
+     * @return latencyMs latency in milliseconds.
+     */
+    getLatency() generates (uint32_t latencyMs);
+
+    /**
+     * This method is used in situations where audio mixing is done in the
+     * hardware. This method serves as a direct interface with hardware,
+     * allowing to directly set the volume as apposed to via the framework.
+     * This method might produce multiple PCM outputs or hardware accelerated
+     * codecs, such as MP3 or AAC.
+     * Optional method
+     *
+     * @param left left channel attenuation, 1.0f is unity, 0.0f is zero.
+     * @param right right channel attenuation, 1.0f is unity, 0.0f is zero.
+     * @return retval operation completion status.
+     *        If a volume is outside [0,1], return INVALID_ARGUMENTS
+     */
+    setVolume(float left, float right) generates (Result retval);
+
+    /**
+     * Commands that can be executed on the driver writer thread.
+     */
+    enum WriteCommand : int32_t {
+        WRITE,
+        GET_PRESENTATION_POSITION,
+        GET_LATENCY
+    };
+
+    /**
+     * Data structure passed back to the client via status message queue
+     * of 'write' operation.
+     *
+     * Possible values of 'retval' field:
+     *  - OK, write operation was successful;
+     *  - INVALID_ARGUMENTS, stream was not configured properly;
+     *  - INVALID_STATE, stream is in a state that doesn't allow writes;
+     *  - INVALID_OPERATION, retrieving presentation position isn't supported.
+     */
+    struct WriteStatus {
+        Result retval;
+        WriteCommand replyTo;  // discriminator
+        union Reply {
+            uint64_t written;  // WRITE command, amount of bytes written, >= 0.
+            struct PresentationPosition {  // same as generated by
+                uint64_t frames;           // getPresentationPosition.
+                TimeSpec timeStamp;
+            } presentationPosition;
+            uint32_t latencyMs; // Same as generated by getLatency.
+        } reply;
+    };
+
+    /**
+     * Called when the metadata of the stream's source has been changed.
+     * @param sourceMetadata Description of the audio that is played by the clients.
+     */
+    updateSourceMetadata(SourceMetadata sourceMetadata);
+
+    /**
+     * Set up required transports for passing audio buffers to the driver.
+     *
+     * The transport consists of three message queues:
+     *  -- command queue is used to instruct the writer thread what operation
+     *     to perform;
+     *  -- data queue is used for passing audio data from the client
+     *     to the driver;
+     *  -- status queue is used for reporting operation status
+     *     (e.g. amount of bytes actually written or error code).
+     *
+     * The driver operates on a dedicated thread. The client must ensure that
+     * the thread is given an appropriate priority and assigned to correct
+     * scheduler and cgroup. For this purpose, the method returns identifiers
+     * of the driver thread.
+     *
+     * @param frameSize the size of a single frame, in bytes.
+     * @param framesCount the number of frames in a buffer.
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queues.
+     * @return commandMQ a message queue used for passing commands.
+     * @return dataMQ a message queue used for passing audio data in the format
+     *                specified at the stream opening.
+     * @return statusMQ a message queue used for passing status from the driver
+     *                  using WriteStatus structures.
+     * @return threadInfo identifiers of the driver's dedicated thread.
+     */
+    prepareForWriting(uint32_t frameSize, uint32_t framesCount)
+    generates (
+            Result retval,
+            fmq_sync<WriteCommand> commandMQ,
+            fmq_sync<uint8_t> dataMQ,
+            fmq_sync<WriteStatus> statusMQ,
+            ThreadInfo threadInfo);
+
+    /**
+     * Return the number of audio frames written by the audio DSP to DAC since
+     * the output has exited standby.
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return dspFrames number of audio frames written.
+     */
+    getRenderPosition() generates (Result retval, uint32_t dspFrames);
+
+    /**
+     * Get the local time at which the next write to the audio driver will be
+     * presented. The units are microseconds, where the epoch is decided by the
+     * local audio HAL.
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return timestampUs time of the next write.
+     */
+    getNextWriteTimestamp() generates (Result retval, int64_t timestampUs);
+
+    /**
+     * Set the callback interface for notifying completion of non-blocking
+     * write and drain.
+     *
+     * Calling this function implies that all future 'write' and 'drain'
+     * must be non-blocking and use the callback to signal completion.
+     *
+     * 'clearCallback' method needs to be called in order to release the local
+     * callback proxy on the server side and thus dereference the callback
+     * implementation on the client side.
+     *
+     * @return retval operation completion status.
+     */
+    setCallback(IStreamOutCallback callback) generates (Result retval);
+
+    /**
+     * Clears the callback previously set via 'setCallback' method.
+     *
+     * Warning: failure to call this method results in callback implementation
+     * on the client side being held until the HAL server termination.
+     *
+     * If no callback was previously set, the method should be a no-op
+     * and return OK.
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     */
+    clearCallback() generates (Result retval);
+
+    /**
+     * Returns whether HAL supports pausing and resuming of streams.
+     *
+     * @return supportsPause true if pausing is supported.
+     * @return supportsResume true if resume is supported.
+     */
+    supportsPauseAndResume()
+            generates (bool supportsPause, bool supportsResume);
+
+    /**
+     * Notifies to the audio driver to stop playback however the queued buffers
+     * are retained by the hardware. Useful for implementing pause/resume. Empty
+     * implementation if not supported however must be implemented for hardware
+     * with non-trivial latency. In the pause state, some audio hardware may
+     * still be using power. Client code may consider calling 'suspend' after a
+     * timeout to prevent that excess power usage.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    pause() generates (Result retval);
+
+    /**
+     * Notifies to the audio driver to resume playback following a pause.
+     * Returns error INVALID_STATE if called without matching pause.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    resume() generates (Result retval);
+
+    /**
+     * Returns whether HAL supports draining of streams.
+     *
+     * @return supports true if draining is supported.
+     */
+    supportsDrain() generates (bool supports);
+
+    /**
+     * Requests notification when data buffered by the driver/hardware has been
+     * played. If 'setCallback' has previously been called to enable
+     * non-blocking mode, then 'drain' must not block, instead it must return
+     * quickly and completion of the drain is notified through the callback. If
+     * 'setCallback' has not been called, then 'drain' must block until
+     * completion.
+     *
+     * If 'type' is 'ALL', the drain completes when all previously written data
+     * has been played.
+     *
+     * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data
+     * for the current track has played to allow time for the framework to
+     * perform a gapless track switch.
+     *
+     * Drain must return immediately on 'stop' and 'flush' calls.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @param type type of drain.
+     * @return retval operation completion status.
+     */
+    drain(AudioDrain type) generates (Result retval);
+
+    /**
+     * Notifies to the audio driver to flush the queued data. Stream must
+     * already be paused before calling 'flush'.
+     * Optional method
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    flush() generates (Result retval);
+
+    /**
+     * Return a recent count of the number of audio frames presented to an
+     * external observer. This excludes frames which have been written but are
+     * still in the pipeline. The count is not reset to zero when output enters
+     * standby. Also returns the value of CLOCK_MONOTONIC as of this
+     * presentation count. The returned count is expected to be 'recent', but
+     * does not need to be the most recent possible value. However, the
+     * associated time must correspond to whatever count is returned.
+     *
+     * Example: assume that N+M frames have been presented, where M is a 'small'
+     * number. Then it is permissible to return N instead of N+M, and the
+     * timestamp must correspond to N rather than N+M. The terms 'recent' and
+     * 'small' are not defined. They reflect the quality of the implementation.
+     *
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return frames count of presented audio frames.
+     * @return timeStamp associated clock time.
+     */
+    getPresentationPosition()
+            generates (Result retval, uint64_t frames, TimeSpec timeStamp);
+
+    /**
+     * Selects a presentation for decoding from a next generation media stream
+     * (as defined per ETSI TS 103 190-2) and a program within the presentation.
+     * Optional method
+     *
+     * @param presentationId selected audio presentation.
+     * @param programId refinement for the presentation.
+     * @return retval operation completion status.
+     */
+    selectPresentation(int32_t presentationId, int32_t programId)
+            generates (Result retval);
+};
diff --git a/audio/6.0/IStreamOutCallback.hal b/audio/6.0/IStreamOutCallback.hal
new file mode 100644
index 0000000..e393d9a
--- /dev/null
+++ b/audio/6.0/IStreamOutCallback.hal
@@ -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.
+ */
+
+package android.hardware.audio@6.0;
+
+/**
+ * Asynchronous write callback interface.
+ */
+interface IStreamOutCallback {
+    /**
+     * Non blocking write completed.
+     */
+    oneway onWriteReady();
+
+    /**
+     * Drain completed.
+     */
+    oneway onDrainReady();
+
+    /**
+     * Stream hit an error.
+     */
+    oneway onError();
+};
diff --git a/audio/6.0/config/Android.bp b/audio/6.0/config/Android.bp
new file mode 100644
index 0000000..182dfcc
--- /dev/null
+++ b/audio/6.0/config/Android.bp
@@ -0,0 +1,7 @@
+
+xsd_config {
+    name: "audio_policy_configuration_V6_0",
+    srcs: ["audio_policy_configuration.xsd"],
+    package_name: "audio.policy.configuration.V6_0",
+}
+
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
new file mode 100644
index 0000000..7aa147c
--- /dev/null
+++ b/audio/6.0/config/api/current.txt
@@ -0,0 +1,422 @@
+// Signature format: 2.0
+package audio.policy.configuration.V6_0 {
+
+  public class AttachedDevices {
+    ctor public AttachedDevices();
+    method public java.util.List<java.lang.String> getItem();
+  }
+
+  public enum AudioDevice {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BACK_MIC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_BUS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_DEFAULT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_HDMI;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_IP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_LINE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_PROXY;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_SPDIF;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_STUB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_TV_TUNER;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_NONE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_BUS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_DEFAULT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_EARPIECE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_FM;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HDMI;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_IP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_LINE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_PROXY;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_STUB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
+  }
+
+  public enum AudioFormat {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADIF;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ELD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_ERLC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_HE_V1;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_HE_V2;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LATM_LC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_LTP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_MAIN;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_SCALABLE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_SSR;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AAC_XHE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AC3;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AC4;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_ALAC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_NB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_WB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_HD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_APTX_TWSP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_CELT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DSD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_DTS_HD;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCNW;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_EVRCWB;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_E_AC3;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_FLAC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_IEC61937;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LDAC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LHDC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_LHDC_LL;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_1_0;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_2_0;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MAT_2_1;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MP2;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_MP3;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_OPUS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_16_BIT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_32_BIT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_8_BIT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_PCM_FLOAT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_QCELP;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_SBC;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_VORBIS;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_WMA;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioFormat AUDIO_FORMAT_WMA_PRO;
+  }
+
+  public class AudioPolicyConfiguration {
+    ctor public AudioPolicyConfiguration();
+    method public audio.policy.configuration.V6_0.GlobalConfiguration getGlobalConfiguration();
+    method public java.util.List<audio.policy.configuration.V6_0.Modules> getModules();
+    method public audio.policy.configuration.V6_0.SurroundSound getSurroundSound();
+    method public audio.policy.configuration.V6_0.Version getVersion();
+    method public java.util.List<audio.policy.configuration.V6_0.Volumes> getVolumes();
+    method public void setGlobalConfiguration(audio.policy.configuration.V6_0.GlobalConfiguration);
+    method public void setSurroundSound(audio.policy.configuration.V6_0.SurroundSound);
+    method public void setVersion(audio.policy.configuration.V6_0.Version);
+  }
+
+  public enum AudioUsage {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ALARM;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_ASSISTANT;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_GAME;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_MEDIA;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_NOTIFICATION;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_UNKNOWN;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
+    enum_constant public static final audio.policy.configuration.V6_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+  }
+
+  public enum DeviceCategory {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+    enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+    enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_HEADSET;
+    enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+    enum_constant public static final audio.policy.configuration.V6_0.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+  }
+
+  public class DevicePorts {
+    ctor public DevicePorts();
+    method public java.util.List<audio.policy.configuration.V6_0.DevicePorts.DevicePort> getDevicePort();
+  }
+
+  public static class DevicePorts.DevicePort {
+    ctor public DevicePorts.DevicePort();
+    method public String getAddress();
+    method public java.util.List<audio.policy.configuration.V6_0.AudioFormat> getEncodedFormats();
+    method public audio.policy.configuration.V6_0.Gains getGains();
+    method public java.util.List<audio.policy.configuration.V6_0.Profile> getProfile();
+    method public audio.policy.configuration.V6_0.Role getRole();
+    method public String getTagName();
+    method public String getType();
+    method public boolean get_default();
+    method public void setAddress(String);
+    method public void setEncodedFormats(java.util.List<audio.policy.configuration.V6_0.AudioFormat>);
+    method public void setGains(audio.policy.configuration.V6_0.Gains);
+    method public void setRole(audio.policy.configuration.V6_0.Role);
+    method public void setTagName(String);
+    method public void setType(String);
+    method public void set_default(boolean);
+  }
+
+  public enum GainMode {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_CHANNELS;
+    enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_JOINT;
+    enum_constant public static final audio.policy.configuration.V6_0.GainMode AUDIO_GAIN_MODE_RAMP;
+  }
+
+  public class Gains {
+    ctor public Gains();
+    method public java.util.List<audio.policy.configuration.V6_0.Gains.Gain> getGain();
+  }
+
+  public static class Gains.Gain {
+    ctor public Gains.Gain();
+    method public String getChannel_mask();
+    method public int getDefaultValueMB();
+    method public int getMaxRampMs();
+    method public int getMaxValueMB();
+    method public int getMinRampMs();
+    method public int getMinValueMB();
+    method public audio.policy.configuration.V6_0.GainMode getMode();
+    method public String getName();
+    method public int getStepValueMB();
+    method public void setChannel_mask(String);
+    method public void setDefaultValueMB(int);
+    method public void setMaxRampMs(int);
+    method public void setMaxValueMB(int);
+    method public void setMinRampMs(int);
+    method public void setMinValueMB(int);
+    method public void setMode(audio.policy.configuration.V6_0.GainMode);
+    method public void setName(String);
+    method public void setStepValueMB(int);
+  }
+
+  public class GlobalConfiguration {
+    ctor public GlobalConfiguration();
+    method public boolean getSpeaker_drc_enabled();
+    method public void setSpeaker_drc_enabled(boolean);
+  }
+
+  public enum HalVersion {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.HalVersion _2_0;
+    enum_constant public static final audio.policy.configuration.V6_0.HalVersion _3_0;
+  }
+
+  public class MixPorts {
+    ctor public MixPorts();
+    method public java.util.List<audio.policy.configuration.V6_0.MixPorts.MixPort> getMixPort();
+  }
+
+  public static class MixPorts.MixPort {
+    ctor public MixPorts.MixPort();
+    method public String getFlags();
+    method public audio.policy.configuration.V6_0.Gains getGains();
+    method public long getMaxActiveCount();
+    method public long getMaxOpenCount();
+    method public String getName();
+    method public java.util.List<audio.policy.configuration.V6_0.AudioUsage> getPreferredUsage();
+    method public java.util.List<audio.policy.configuration.V6_0.Profile> getProfile();
+    method public audio.policy.configuration.V6_0.Role getRole();
+    method public void setFlags(String);
+    method public void setGains(audio.policy.configuration.V6_0.Gains);
+    method public void setMaxActiveCount(long);
+    method public void setMaxOpenCount(long);
+    method public void setName(String);
+    method public void setPreferredUsage(java.util.List<audio.policy.configuration.V6_0.AudioUsage>);
+    method public void setRole(audio.policy.configuration.V6_0.Role);
+  }
+
+  public enum MixType {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.MixType mix;
+    enum_constant public static final audio.policy.configuration.V6_0.MixType mux;
+  }
+
+  public class Modules {
+    ctor public Modules();
+    method public java.util.List<audio.policy.configuration.V6_0.Modules.Module> getModule();
+  }
+
+  public static class Modules.Module {
+    ctor public Modules.Module();
+    method public audio.policy.configuration.V6_0.AttachedDevices getAttachedDevices();
+    method public String getDefaultOutputDevice();
+    method public audio.policy.configuration.V6_0.DevicePorts getDevicePorts();
+    method public audio.policy.configuration.V6_0.HalVersion getHalVersion();
+    method public audio.policy.configuration.V6_0.MixPorts getMixPorts();
+    method public String getName();
+    method public audio.policy.configuration.V6_0.Routes getRoutes();
+    method public void setAttachedDevices(audio.policy.configuration.V6_0.AttachedDevices);
+    method public void setDefaultOutputDevice(String);
+    method public void setDevicePorts(audio.policy.configuration.V6_0.DevicePorts);
+    method public void setHalVersion(audio.policy.configuration.V6_0.HalVersion);
+    method public void setMixPorts(audio.policy.configuration.V6_0.MixPorts);
+    method public void setName(String);
+    method public void setRoutes(audio.policy.configuration.V6_0.Routes);
+  }
+
+  public class Profile {
+    ctor public Profile();
+    method public String getChannelMasks();
+    method public String getFormat();
+    method public String getName();
+    method public String getSamplingRates();
+    method public void setChannelMasks(String);
+    method public void setFormat(String);
+    method public void setName(String);
+    method public void setSamplingRates(String);
+  }
+
+  public class Reference {
+    ctor public Reference();
+    method public String getName();
+    method public java.util.List<java.lang.String> getPoint();
+    method public void setName(String);
+  }
+
+  public enum Role {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.Role sink;
+    enum_constant public static final audio.policy.configuration.V6_0.Role source;
+  }
+
+  public class Routes {
+    ctor public Routes();
+    method public java.util.List<audio.policy.configuration.V6_0.Routes.Route> getRoute();
+  }
+
+  public static class Routes.Route {
+    ctor public Routes.Route();
+    method public String getSink();
+    method public String getSources();
+    method public audio.policy.configuration.V6_0.MixType getType();
+    method public void setSink(String);
+    method public void setSources(String);
+    method public void setType(audio.policy.configuration.V6_0.MixType);
+  }
+
+  public enum Stream {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ACCESSIBILITY;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ALARM;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_BLUETOOTH_SCO;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_DTMF;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_MUSIC;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_NOTIFICATION;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_PATCH;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_REROUTING;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_RING;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_SYSTEM;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_TTS;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_VOICE_CALL;
+  }
+
+  public class SurroundFormats {
+    ctor public SurroundFormats();
+    method public java.util.List<audio.policy.configuration.V6_0.SurroundFormats.Format> getFormat();
+  }
+
+  public static class SurroundFormats.Format {
+    ctor public SurroundFormats.Format();
+    method public audio.policy.configuration.V6_0.AudioFormat getName();
+    method public java.util.List<audio.policy.configuration.V6_0.AudioFormat> getSubformats();
+    method public void setName(audio.policy.configuration.V6_0.AudioFormat);
+    method public void setSubformats(java.util.List<audio.policy.configuration.V6_0.AudioFormat>);
+  }
+
+  public class SurroundSound {
+    ctor public SurroundSound();
+    method public audio.policy.configuration.V6_0.SurroundFormats getFormats();
+    method public void setFormats(audio.policy.configuration.V6_0.SurroundFormats);
+  }
+
+  public enum Version {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V6_0.Version _1_0;
+  }
+
+  public class Volume {
+    ctor public Volume();
+    method public audio.policy.configuration.V6_0.DeviceCategory getDeviceCategory();
+    method public java.util.List<java.lang.String> getPoint();
+    method public String getRef();
+    method public audio.policy.configuration.V6_0.Stream getStream();
+    method public void setDeviceCategory(audio.policy.configuration.V6_0.DeviceCategory);
+    method public void setRef(String);
+    method public void setStream(audio.policy.configuration.V6_0.Stream);
+  }
+
+  public class Volumes {
+    ctor public Volumes();
+    method public java.util.List<audio.policy.configuration.V6_0.Reference> getReference();
+    method public java.util.List<audio.policy.configuration.V6_0.Volume> getVolume();
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static audio.policy.configuration.V6_0.AudioPolicyConfiguration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/audio/6.0/config/api/last_current.txt b/audio/6.0/config/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/6.0/config/api/last_current.txt
diff --git a/audio/6.0/config/api/last_removed.txt b/audio/6.0/config/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/6.0/config/api/last_removed.txt
diff --git a/audio/6.0/config/api/removed.txt b/audio/6.0/config/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/6.0/config/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..0dc89bb
--- /dev/null
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -0,0 +1,624 @@
+<?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.
+-->
+<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
+<xs:schema version="2.0"
+           elementFormDefault="qualified"
+           attributeFormDefault="unqualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <!-- List the config versions supported by audio policy. -->
+    <xs:simpleType name="version">
+        <xs:restriction base="xs:decimal">
+            <xs:enumeration value="1.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="halVersion">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Version of the interface the hal implements.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:decimal">
+            <!-- List of HAL versions supported by the framework. -->
+            <xs:enumeration value="2.0"/>
+            <xs:enumeration value="3.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="audioPolicyConfiguration">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="globalConfiguration" type="globalConfiguration"/>
+                <xs:element name="modules" type="modules" maxOccurs="unbounded"/>
+                <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/>
+                <xs:element name="surroundSound" type="surroundSound" minOccurs="0" />
+            </xs:sequence>
+            <xs:attribute name="version" type="version"/>
+        </xs:complexType>
+        <xs:key name="moduleNameKey">
+            <xs:selector xpath="modules/module"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:unique name="volumeTargetUniqueness">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@stream"/>
+            <xs:field xpath="@deviceCategory"/>
+        </xs:unique>
+        <xs:key name="volumeCurveNameKey">
+            <xs:selector xpath="volumes/reference"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@ref"/>
+        </xs:keyref>
+    </xs:element>
+    <xs:complexType name="globalConfiguration">
+        <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="modules">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                There should be one section per audio HW module present on the platform.
+                Each <module/> contains two mandatory tags: “halVersion” and “name”.
+                The module "name" is the same as in previous .conf file.
+                Each module must contain the following sections:
+                 - <devicePorts/>: a list of device descriptors for all
+                   input and output devices accessible via this module.
+                   This contains both permanently attached devices and removable devices.
+                 - <mixPorts/>: listing all output and input streams exposed by the audio HAL
+                 - <routes/>: list of possible connections between input
+                   and output devices or between stream and devices.
+                   A <route/> is defined by a set of 3 attributes:
+                        -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix)
+                        -"sink": the sink involved in this route
+                        -"sources": all the sources than can be connected to the sink via this route
+                 - <attachedDevices/>: permanently attached devices.
+                   The attachedDevices section is a list of devices names.
+                   Their names correspond to device names defined in "devicePorts" section.
+                 - <defaultOutputDevice/> is the device to be used when no policy rule applies
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="module" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0">
+                            <xs:unique name="attachedDevicesUniqueness">
+                                <xs:selector xpath="item"/>
+                                <xs:field xpath="."/>
+                            </xs:unique>
+                        </xs:element>
+                        <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/>
+                        <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/>
+                        <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
+                        <xs:element name="routes" type="routes" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:string" use="required"/>
+                    <xs:attribute name="halVersion" type="halVersion" use="required"/>
+                </xs:complexType>
+                <xs:unique name="mixPortNameUniqueness">
+                    <xs:selector xpath="mixPorts/mixPort"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+                <xs:key name="devicePortNameKey">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@tagName"/>
+                </xs:key>
+                <xs:unique name="devicePortUniqueness">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@type"/>
+                    <xs:field xpath="@address"/>
+                </xs:unique>
+                <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="defaultOutputDevice"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="attachedDevices/item"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <!-- The following 3 constraints try to make sure each sink port
+                     is reference in one an only one route. -->
+                <xs:key name="routeSinkKey">
+                    <!-- predicate [@type='sink'] does not work in xsd 1.0 -->
+                    <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/>
+                    <xs:field xpath="@tagName|@name"/>
+                </xs:key>
+                <xs:keyref name="routeSinkRef" refer="routeSinkKey">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:keyref>
+                <xs:unique name="routeUniqueness">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="attachedDevices">
+        <xs:sequence>
+            <xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- TODO: separate values by space for better xsd validations. -->
+    <xs:simpleType name="audioInOutFlags">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                "|" separated list of audio_output_flags_t or audio_input_flags_t.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="|[_A-Z]+(\|[_A-Z]+)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="role">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="sink"/>
+            <xs:enumeration value="source"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="mixPorts">
+        <xs:sequence>
+            <xs:element name="mixPort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:token" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="flags" type="audioInOutFlags"/>
+                    <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/>
+                    <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/>
+                    <xs:attribute name="preferredUsage" type="audioUsageList">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                When choosing the mixPort of an audio track, the audioPolicy
+                                first considers the mixPorts with a preferredUsage including
+                                the track AudioUsage preferred .
+                                If non support the track format, the other mixPorts are considered.
+                                Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive
+                                    the audio of all apps playing with a MEDIA usage.
+                                    It may receive audio from ALARM if there are no audio compatible
+                                    <mixPort preferredUsage="AUDIO_USAGE_ALARM" />.
+                             </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                </xs:complexType>
+                <xs:unique name="mixPortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="mixPortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- Enum values of audio_device_t in audio.h
+         TODO: generate from hidl to avoid manual sync.
+         TODO: separate source and sink in the xml for better xsd validations. -->
+    <xs:simpleType name="audioDevice">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_DEVICE_NONE"/>
+
+            <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/>
+
+            <!-- Due to the xml format, IN types can not be a separated from OUT types -->
+            <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="vendorExtension">
+        <!-- Vendor extension names must be prefixed by "VX_" to distinguish them from AOSP values.
+             Vendor are encouraged to namespace their module names to avoid conflicts.
+             Example for an hypothetical Google virtual reality device:
+                <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink">
+        -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="VX_[_a-zA-Z0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="extendableAudioDevice">
+        <xs:union memberTypes="audioDevice vendorExtension"/>
+    </xs:simpleType>
+    <!-- Enum values of audio_format_t in audio.h
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="audioFormat">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
+            <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRC"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP2"/>
+            <xs:enumeration value="AUDIO_FORMAT_QCELP"/>
+            <xs:enumeration value="AUDIO_FORMAT_DSD"/>
+            <xs:enumeration value="AUDIO_FORMAT_FLAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_ALAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_SBC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC4"/>
+            <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_CELT"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE"/>
+            <xs:enumeration value="AUDIO_FORMAT_LHDC"/>
+            <xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_TWSP"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="extendableAudioFormat">
+        <xs:union memberTypes="audioFormat vendorExtension"/>
+    </xs:simpleType>
+    <!-- Enum values of audio::common::4_0::AudioUsage
+         TODO: generate from HIDL to avoid manual sync. -->
+    <xs:simpleType name="audioUsage">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
+            <xs:enumeration value="AUDIO_USAGE_MEDIA" />
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+            <xs:enumeration value="AUDIO_USAGE_ALARM" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+            <xs:enumeration value="AUDIO_USAGE_GAME" />
+            <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioUsageList">
+        <xs:list itemType="audioUsage"/>
+    </xs:simpleType>
+    <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
+    <xs:simpleType name="samplingRates">
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[0-9]+(,[0-9]+)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
+    <xs:simpleType name="channelMask">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Comma (",") separated list of channel flags
+                from audio_channel_mask_t.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[_A-Z][_A-Z0-9]*(,[_A-Z][_A-Z0-9]*)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="profile">
+        <xs:attribute name="name" type="xs:token" use="optional"/>
+        <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
+        <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
+        <xs:attribute name="channelMasks" type="channelMask" use="optional"/>
+    </xs:complexType>
+    <xs:simpleType name="gainMode">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_GAIN_MODE_JOINT"/>
+            <xs:enumeration value="AUDIO_GAIN_MODE_CHANNELS"/>
+            <xs:enumeration value="AUDIO_GAIN_MODE_RAMP"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="gains">
+        <xs:sequence>
+            <xs:element name="gain" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="xs:token" use="required"/>
+                    <xs:attribute name="mode" type="gainMode" use="required"/>
+                    <xs:attribute name="channel_mask" type="channelMask" use="optional"/>
+                    <xs:attribute name="minValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="maxValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="defaultValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
+                    <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="devicePorts">
+        <xs:sequence>
+            <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="tagName" type="xs:token" use="required"/>
+                    <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="address" type="xs:string" use="optional" default=""/>
+                    <!-- Note that XSD 1.0 can not check that a type only has one default. -->
+                    <xs:attribute name="default" type="xs:boolean" use="optional">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                The default device will be used if multiple have the same type
+                                and no explicit route request exists for a specific device of
+                                that type.
+                            </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                    <xs:attribute name="encodedFormats" type="audioFormatsList" use="optional"
+                                  default="" />
+                </xs:complexType>
+                <xs:unique name="devicePortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="devicePortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="mixType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="mix"/>
+            <xs:enumeration value="mux"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="routes">
+        <xs:sequence>
+            <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+                <xs:annotation>
+                    <xs:documentation xml:lang="en">
+                        List all available sources for a given sink.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:complexType>
+                    <xs:attribute name="type" type="mixType" use="required"/>
+                    <xs:attribute name="sink" type="xs:string" use="required"/>
+                    <xs:attribute name="sources" type="xs:string" use="required"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="volumes">
+        <xs:sequence>
+            <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded">
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- TODO: Always require a ref for better xsd validations.
+               Currently a volume could have no points nor ref
+               as it can not be forbidden by xsd 1.0.-->
+    <xs:simpleType name="volumePoint">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Comma separated pair of number.
+                The fist one is the framework level (between 0 and 100).
+                The second one is the volume to send to the HAL.
+                The framework will interpolate volumes not specified.
+                Their MUST be at least 2 points specified.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of audio_stream_type_t in audio-base.h
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="stream">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+            <xs:enumeration value="AUDIO_STREAM_RING"/>
+            <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+            <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+            <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+            <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+            <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+            <xs:enumeration value="AUDIO_STREAM_TTS"/>
+            <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+            <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
+            <xs:enumeration value="AUDIO_STREAM_PATCH"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of device_category from Volume.h.
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="deviceCategory">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+            <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+            <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="volume">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Volume section defines a volume curve for a given use case and device category.
+                It contains a list of points of this curve expressing the attenuation in Millibels
+                for a given volume index from 0 to 100.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </volume>
+
+                It may also reference a reference/@name to avoid duplicating curves.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                        ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+                <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </reference>
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="stream" type="stream"/>
+        <xs:attribute name="deviceCategory" type="deviceCategory"/>
+        <xs:attribute name="ref" type="xs:token" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="reference">
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="name" type="xs:token" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="surroundSound">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Surround Sound section provides configuration related to handling of
+                multi-channel formats.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="formats" type="surroundFormats"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="audioFormatsList">
+        <xs:list itemType="audioFormat" />
+    </xs:simpleType>
+    <xs:complexType name="surroundFormats">
+        <xs:sequence>
+            <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="audioFormat" use="required"/>
+                    <xs:attribute name="subformats" type="audioFormatsList" />
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+</xs:schema>
diff --git a/audio/6.0/types.hal b/audio/6.0/types.hal
new file mode 100644
index 0000000..1a704f8
--- /dev/null
+++ b/audio/6.0/types.hal
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@6.0;
+
+import android.hardware.audio.common@6.0;
+
+enum Result : int32_t {
+    OK,
+    NOT_INITIALIZED,
+    INVALID_ARGUMENTS,
+    INVALID_STATE,
+    /**
+     * Methods marked as "Optional method" must return this result value
+     * if the operation is not supported by HAL.
+     */
+    NOT_SUPPORTED
+};
+
+@export(name="audio_drain_type_t", value_prefix="AUDIO_DRAIN_")
+enum AudioDrain : int32_t {
+    /** drain() returns when all data has been played. */
+    ALL,
+    /**
+     * drain() returns a short time before all data from the current track has
+     * been played to give time for gapless track switch.
+     */
+    EARLY_NOTIFY
+};
+
+/**
+ * A substitute for POSIX timespec.
+ */
+struct TimeSpec {
+    uint64_t tvSec;   // seconds
+    uint64_t tvNSec;  // nanoseconds
+};
+
+struct ParameterValue {
+    string key;
+    string value;
+};
+
+enum MmapBufferFlag : uint32_t {
+    NONE    = 0x0,
+    /**
+     * If the buffer can be securely shared to untrusted applications
+     * through the AAudio exclusive mode.
+     * Only set this flag if applications are restricted from accessing the
+     * memory surrounding the audio data buffer by a kernel mechanism.
+     * See Linux kernel's dma_buf.
+     */
+    APPLICATION_SHAREABLE    = 0x1,
+};
+
+/**
+ * Mmap buffer descriptor returned by IStream.createMmapBuffer().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapBufferInfo {
+    /** Mmap memory buffer */
+    memory  sharedMemory;
+    /** Total buffer size in frames */
+    uint32_t bufferSizeFrames;
+    /** Transfer size granularity in frames */
+    uint32_t burstSizeFrames;
+    /** Attributes describing the buffer. */
+    bitfield<MmapBufferFlag> flags;
+};
+
+/**
+ * Mmap buffer read/write position returned by IStream.getMmapPosition().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapPosition {
+    int64_t  timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC
+    int32_t  positionFrames;  // increasing 32 bit frame count reset when IStream.stop() is called
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * message queues used by StreamIn and StreamOut.
+ */
+enum MessageQueueFlagBits : uint32_t {
+    NOT_EMPTY = 1 << 0,
+    NOT_FULL = 1 << 1
+};
+
+/*
+ * Microphone information
+ *
+ */
+
+/**
+ * A 3D point used to represent position or orientation of a microphone.
+ *
+ * Position: Coordinates of the microphone's capsule, in meters, from the
+ * bottom-left-back corner of the bounding box of android device in natural
+ * orientation (PORTRAIT for phones, LANDSCAPE for tablets, tvs, etc).
+ * The orientation musth match the reported by the api Display.getRotation().
+ *
+ * Orientation: Normalized vector to signal the main orientation of the
+ * microphone's capsule. Magnitude = sqrt(x^2 + y^2 + z^2) = 1
+ */
+struct AudioMicrophoneCoordinate {
+    float x;
+    float y;
+    float z;
+};
+
+/**
+ * Enum to identify the type of channel mapping for active microphones.
+ * Used channels further identify if the microphone has any significative
+ * process (e.g. High Pass Filtering, dynamic compression)
+ * Simple processing as constant gain adjustment must be DIRECT.
+ */
+enum AudioMicrophoneChannelMapping : uint32_t {
+    UNUSED      = 0, /* Channel not used */
+    DIRECT      = 1, /* Channel used and signal not processed */
+    PROCESSED   = 2, /* Channel used and signal has some process */
+};
+
+/**
+ * Enum to identify locations of microphones in regards to the body of the
+ * android device.
+ */
+enum AudioMicrophoneLocation : uint32_t {
+    UNKNOWN             = 0,
+    MAINBODY            = 1,
+    MAINBODY_MOVABLE    = 2,
+    PERIPHERAL          = 3,
+};
+
+/**
+ * Identifier to help group related microphones together
+ * e.g. microphone arrays should belong to the same group
+ */
+typedef int32_t AudioMicrophoneGroup;
+
+/**
+ * Enum with standard polar patterns of microphones
+ */
+enum AudioMicrophoneDirectionality : uint32_t {
+    UNKNOWN         = 0,
+    OMNI            = 1,
+    BI_DIRECTIONAL  = 2,
+    CARDIOID        = 3,
+    HYPER_CARDIOID  = 4,
+    SUPER_CARDIOID  = 5,
+};
+
+/**
+ * A (frequency, level) pair. Used to represent frequency response.
+ */
+struct AudioFrequencyResponsePoint {
+    /** In Hz */
+    float frequency;
+    /** In dB */
+    float level;
+};
+
+/**
+ * Structure used by the HAL to describe microphone's characteristics
+ * Used by StreamIn and Device
+ */
+struct MicrophoneInfo {
+    /** Unique alphanumeric id for microphone. Guaranteed to be the same
+     * even after rebooting.
+     */
+    string                                  deviceId;
+    /**
+     * Device specific information
+     */
+    DeviceAddress                           deviceAddress;
+    /** Each element of the vector must describe the channel with the same
+     *  index.
+     */
+    vec<AudioMicrophoneChannelMapping>      channelMapping;
+    /** Location of the microphone in regard to the body of the device */
+    AudioMicrophoneLocation                 location;
+    /** Identifier to help group related microphones together
+     *  e.g. microphone arrays should belong to the same group
+     */
+    AudioMicrophoneGroup                    group;
+    /** Index of this microphone within the group.
+     *  (group, index) must be unique within the same device.
+     */
+    uint32_t                                indexInTheGroup;
+    /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */
+    float                                   sensitivity;
+    /** Level in dB of the max SPL supported at 1000 Hz */
+    float                                   maxSpl;
+    /** Level in dB of the min SPL supported at 1000 Hz */
+    float                                   minSpl;
+    /** Standard polar pattern of the microphone */
+    AudioMicrophoneDirectionality           directionality;
+    /** Vector with ordered frequency responses (from low to high frequencies)
+     *  with the frequency response of the microphone.
+     *  Levels are in dB, relative to level at 1000 Hz
+     */
+    vec<AudioFrequencyResponsePoint>        frequencyResponse;
+    /** Position of the microphone's capsule in meters, from the
+     *  bottom-left-back corner of the bounding box of device.
+     */
+    AudioMicrophoneCoordinate               position;
+    /** Normalized point to signal the main orientation of the microphone's
+     *  capsule. sqrt(x^2 + y^2 + z^2) = 1
+     */
+    AudioMicrophoneCoordinate               orientation;
+};
+
+/**
+ * Constants used by the HAL to determine how to select microphones and process those inputs in
+ * order to optimize for capture in the specified direction.
+ *
+ * MicrophoneDirection Constants are defined in MicrophoneDirection.java.
+ */
+@export(name="audio_microphone_direction_t", value_prefix="MIC_DIRECTION_")
+enum MicrophoneDirection : int32_t {
+    /**
+     * Don't do any directionality processing of the activated microphone(s).
+     */
+    UNSPECIFIED = 0,
+    /**
+     * Optimize capture for audio coming from the screen-side of the device.
+     */
+    FRONT = 1,
+    /**
+     * Optimize capture for audio coming from the side of the device opposite the screen.
+     */
+    BACK = 2,
+    /**
+     * Optimize capture for audio coming from an off-device microphone.
+     */
+    EXTERNAL = 3,
+};
diff --git a/audio/common/6.0/Android.bp b/audio/common/6.0/Android.bp
new file mode 100644
index 0000000..1a4e054
--- /dev/null
+++ b/audio/common/6.0/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio.common@6.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
new file mode 100644
index 0000000..132f86d
--- /dev/null
+++ b/audio/common/6.0/types.hal
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.common@6.0;
+
+import android.hidl.safe_union@1.0;
+
+/*
+ *
+ *  IDs and Handles
+ *
+ */
+
+/**
+ * Handle type for identifying audio sources and sinks.
+ */
+typedef int32_t AudioIoHandle;
+
+/**
+ * Audio hw module handle functions or structures referencing a module.
+ */
+typedef int32_t AudioModuleHandle;
+
+/**
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+typedef int32_t AudioPortHandle;
+
+/**
+ * Each patch is identified by a handle at the interface used to create that
+ * patch. For instance, when a patch is created by the audio HAL, the HAL
+ * allocates and returns a handle.  This handle is unique to a given audio HAL
+ * hardware module.  But the same patch receives another system wide unique
+ * handle allocated by the framework.  This unique handle is used for all
+ * transactions inside the framework.
+ */
+typedef int32_t AudioPatchHandle;
+
+/**
+ * A HW synchronization source returned by the audio HAL.
+ */
+typedef uint32_t AudioHwSync;
+
+/**
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+@export(name="")
+enum AudioHandleConsts : int32_t {
+    AUDIO_IO_HANDLE_NONE = 0,
+    AUDIO_MODULE_HANDLE_NONE = 0,
+    AUDIO_PORT_HANDLE_NONE = 0,
+    AUDIO_PATCH_HANDLE_NONE = 0,
+};
+
+/**
+ * Commonly used structure for passing unique identifieds (UUID).
+ * For the definition of UUID, refer to ITU-T X.667 spec.
+ */
+struct Uuid {
+    uint32_t timeLow;
+    uint16_t timeMid;
+    uint16_t versionAndTimeHigh;
+    uint16_t variantAndClockSeqHigh;
+    uint8_t[6] node;
+};
+
+
+/*
+ *
+ *  Audio streams
+ *
+ */
+
+/**
+ * Audio stream type describing the intended use case of a stream.
+ */
+@export(name="audio_stream_type_t", value_prefix="AUDIO_STREAM_")
+enum AudioStreamType : int32_t {
+    // These values must kept in sync with
+    //  frameworks/base/media/java/android/media/AudioSystem.java
+    DEFAULT          = -1,
+    MIN              = 0,
+    VOICE_CALL       = 0,
+    SYSTEM           = 1,
+    RING             = 2,
+    MUSIC            = 3,
+    ALARM            = 4,
+    NOTIFICATION     = 5,
+    BLUETOOTH_SCO    = 6,
+    ENFORCED_AUDIBLE = 7,  // Sounds that cannot be muted by user and must be
+                           // routed to speaker
+    DTMF             = 8,
+    TTS              = 9,  // Transmitted Through Speaker.  Plays over speaker
+                           // only, silent on other devices
+    ACCESSIBILITY    = 10, // For accessibility talk back prompts
+};
+
+@export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
+enum AudioSource : int32_t {
+    // These values must kept in sync with
+    //  frameworks/base/media/java/android/media/MediaRecorder.java,
+    //  frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
+    //  system/media/audio_effects/include/audio_effects/audio_effects_conf.h
+    DEFAULT             = 0,
+    MIC                 = 1,
+    VOICE_UPLINK        = 2,
+    VOICE_DOWNLINK      = 3,
+    VOICE_CALL          = 4,
+    CAMCORDER           = 5,
+    VOICE_RECOGNITION   = 6,
+    VOICE_COMMUNICATION = 7,
+    /**
+     * Source for the mix to be presented remotely. An example of remote
+     * presentation is Wifi Display where a dongle attached to a TV can be used
+     * to play the mix captured by this audio source.
+     */
+    REMOTE_SUBMIX       = 8,
+    /**
+     * Source for unprocessed sound. Usage examples include level measurement
+     * and raw signal analysis.
+     */
+    UNPROCESSED         = 9,
+    /**
+     * Source for capturing audio meant to be processed in real time and played back for live
+     * performance (e.g karaoke). The capture path will minimize latency and coupling with
+     * playback path.
+     */
+    VOICE_PERFORMANCE    = 10,
+    /**
+     * Source for an echo canceller to capture the reference signal to be cancelled.
+     * The echo reference signal will be captured as close as possible to the DAC in order
+     * to include all post processing applied to the playback path.
+     */
+    ECHO_REFERENCE      = 1997,
+    FM_TUNER            = 1998,
+    HOTWORD             = 1999,
+};
+
+typedef int32_t AudioSession;
+/**
+ * Special audio session values.
+ */
+@export(name="audio_session_t", value_prefix="AUDIO_SESSION_")
+enum AudioSessionConsts : int32_t {
+    /**
+     * Session for effects attached to a particular output stream
+     * (value must be less than 0)
+     */
+    OUTPUT_STAGE = -1,
+    /**
+     * Session for effects applied to output mix. These effects can
+     * be moved by audio policy manager to another output stream
+     * (value must be 0)
+     */
+    OUTPUT_MIX = 0,
+    /**
+     * Application does not specify an explicit session ID to be used, and
+     * requests a new session ID to be allocated. Corresponds to
+     * AudioManager.AUDIO_SESSION_ID_GENERATE and
+     * AudioSystem.AUDIO_SESSION_ALLOCATE.
+     */
+    ALLOCATE = 0,
+    /**
+     * For use with AudioRecord::start(), this indicates no trigger session.
+     * It is also used with output tracks and patch tracks, which never have a
+     * session.
+     */
+    NONE = 0
+};
+
+/**
+ * Audio format  is a 32-bit word that consists of:
+ *   main format field (upper 8 bits)
+ *   sub format field (lower 24 bits).
+ *
+ * The main format indicates the main codec type. The sub format field indicates
+ * options and parameters for each format. The sub format is mainly used for
+ * record to indicate for instance the requested bitrate or profile.  It can
+ * also be used for certain formats to give informations not present in the
+ * encoded audio stream (e.g. octet alignement for AMR).
+ */
+@export(name="audio_format_t", value_prefix="AUDIO_FORMAT_")
+enum AudioFormat : uint32_t {
+    INVALID             = 0xFFFFFFFFUL,
+    DEFAULT             = 0,
+    PCM                 = 0x00000000UL,
+    MP3                 = 0x01000000UL,
+    AMR_NB              = 0x02000000UL,
+    AMR_WB              = 0x03000000UL,
+    AAC                 = 0x04000000UL,
+    /** Deprecated, Use AAC_HE_V1 */
+    HE_AAC_V1           = 0x05000000UL,
+    /** Deprecated, Use AAC_HE_V2 */
+    HE_AAC_V2           = 0x06000000UL,
+    VORBIS              = 0x07000000UL,
+    OPUS                = 0x08000000UL,
+    AC3                 = 0x09000000UL,
+    E_AC3               = 0x0A000000UL,
+    DTS                 = 0x0B000000UL,
+    DTS_HD              = 0x0C000000UL,
+    /** IEC61937 is encoded audio wrapped in 16-bit PCM. */
+    IEC61937            = 0x0D000000UL,
+    DOLBY_TRUEHD        = 0x0E000000UL,
+    EVRC                = 0x10000000UL,
+    EVRCB               = 0x11000000UL,
+    EVRCWB              = 0x12000000UL,
+    EVRCNW              = 0x13000000UL,
+    AAC_ADIF            = 0x14000000UL,
+    WMA                 = 0x15000000UL,
+    WMA_PRO             = 0x16000000UL,
+    AMR_WB_PLUS         = 0x17000000UL,
+    MP2                 = 0x18000000UL,
+    QCELP               = 0x19000000UL,
+    DSD                 = 0x1A000000UL,
+    FLAC                = 0x1B000000UL,
+    ALAC                = 0x1C000000UL,
+    APE                 = 0x1D000000UL,
+    AAC_ADTS            = 0x1E000000UL,
+    SBC                 = 0x1F000000UL,
+    APTX                = 0x20000000UL,
+    APTX_HD             = 0x21000000UL,
+    AC4                 = 0x22000000UL,
+    LDAC                = 0x23000000UL,
+    /** Dolby Metadata-enhanced Audio Transmission */
+    MAT                 = 0x24000000UL,
+    AAC_LATM            = 0x25000000UL,
+    CELT                = 0x26000000UL,
+    APTX_ADAPTIVE       = 0x27000000UL,
+    LHDC                = 0x28000000UL,
+    LHDC_LL             = 0x29000000UL,
+    APTX_TWSP           = 0x2A000000UL,
+
+    /** Deprecated */
+    MAIN_MASK           = 0xFF000000UL,
+    SUB_MASK            = 0x00FFFFFFUL,
+
+    /* Subformats */
+    PCM_SUB_16_BIT        = 0x1, // PCM signed 16 bits
+    PCM_SUB_8_BIT         = 0x2, // PCM unsigned 8 bits
+    PCM_SUB_32_BIT        = 0x3, // PCM signed .31 fixed point
+    PCM_SUB_8_24_BIT      = 0x4, // PCM signed 8.23 fixed point
+    PCM_SUB_FLOAT         = 0x5, // PCM single-precision float pt
+    PCM_SUB_24_BIT_PACKED = 0x6, // PCM signed .23 fix pt (3 bytes)
+
+    MP3_SUB_NONE          = 0x0,
+
+    AMR_SUB_NONE          = 0x0,
+
+    AAC_SUB_MAIN          = 0x1,
+    AAC_SUB_LC            = 0x2,
+    AAC_SUB_SSR           = 0x4,
+    AAC_SUB_LTP           = 0x8,
+    AAC_SUB_HE_V1         = 0x10,
+    AAC_SUB_SCALABLE      = 0x20,
+    AAC_SUB_ERLC          = 0x40,
+    AAC_SUB_LD            = 0x80,
+    AAC_SUB_HE_V2         = 0x100,
+    AAC_SUB_ELD           = 0x200,
+    AAC_SUB_XHE           = 0x300,
+
+    VORBIS_SUB_NONE       = 0x0,
+
+    E_AC3_SUB_JOC         = 0x1,
+
+    MAT_SUB_1_0           = 0x1,
+    MAT_SUB_2_0           = 0x2,
+    MAT_SUB_2_1           = 0x3,
+
+    /* Aliases */
+    /** note != AudioFormat.ENCODING_PCM_16BIT */
+    PCM_16_BIT          = (PCM | PCM_SUB_16_BIT),
+    /** note != AudioFormat.ENCODING_PCM_8BIT */
+    PCM_8_BIT           = (PCM | PCM_SUB_8_BIT),
+    PCM_32_BIT          = (PCM | PCM_SUB_32_BIT),
+    PCM_8_24_BIT        = (PCM | PCM_SUB_8_24_BIT),
+    PCM_FLOAT           = (PCM | PCM_SUB_FLOAT),
+    PCM_24_BIT_PACKED   = (PCM | PCM_SUB_24_BIT_PACKED),
+    AAC_MAIN            = (AAC | AAC_SUB_MAIN),
+    AAC_LC              = (AAC | AAC_SUB_LC),
+    AAC_SSR             = (AAC | AAC_SUB_SSR),
+    AAC_LTP             = (AAC | AAC_SUB_LTP),
+    AAC_HE_V1           = (AAC | AAC_SUB_HE_V1),
+    AAC_SCALABLE        = (AAC | AAC_SUB_SCALABLE),
+    AAC_ERLC            = (AAC | AAC_SUB_ERLC),
+    AAC_LD              = (AAC | AAC_SUB_LD),
+    AAC_HE_V2           = (AAC | AAC_SUB_HE_V2),
+    AAC_ELD             = (AAC | AAC_SUB_ELD),
+    AAC_XHE             = (AAC | AAC_SUB_XHE),
+    AAC_ADTS_MAIN       = (AAC_ADTS | AAC_SUB_MAIN),
+    AAC_ADTS_LC         = (AAC_ADTS | AAC_SUB_LC),
+    AAC_ADTS_SSR        = (AAC_ADTS | AAC_SUB_SSR),
+    AAC_ADTS_LTP        = (AAC_ADTS | AAC_SUB_LTP),
+    AAC_ADTS_HE_V1      = (AAC_ADTS | AAC_SUB_HE_V1),
+    AAC_ADTS_SCALABLE   = (AAC_ADTS | AAC_SUB_SCALABLE),
+    AAC_ADTS_ERLC       = (AAC_ADTS | AAC_SUB_ERLC),
+    AAC_ADTS_LD         = (AAC_ADTS | AAC_SUB_LD),
+    AAC_ADTS_HE_V2      = (AAC_ADTS | AAC_SUB_HE_V2),
+    AAC_ADTS_ELD        = (AAC_ADTS | AAC_SUB_ELD),
+    AAC_ADTS_XHE        = (AAC_ADTS | AAC_SUB_XHE),
+    E_AC3_JOC           = (E_AC3 | E_AC3_SUB_JOC),
+    MAT_1_0             = (MAT | MAT_SUB_1_0),
+    MAT_2_0             = (MAT | MAT_SUB_2_0),
+    MAT_2_1             = (MAT | MAT_SUB_2_1),
+    AAC_LATM_LC         = (AAC_LATM | AAC_SUB_LC),
+    AAC_LATM_HE_V1      = (AAC_LATM | AAC_SUB_HE_V1),
+    AAC_LATM_HE_V2      = (AAC_LATM | AAC_SUB_HE_V2),
+};
+
+/**
+ * Usage of these values highlights places in the code that use 2- or 8- channel
+ * assumptions.
+ */
+@export(name="")
+enum FixedChannelCount : int32_t {
+    FCC_2 = 2, // This is typically due to legacy implementation of stereo I/O
+    FCC_8 = 8  // This is typically due to audio mixer and resampler limitations
+};
+
+/**
+ * A channel mask per se only defines the presence or absence of a channel, not
+ * the order.
+ *
+ * The channel order convention is that channels are interleaved in order from
+ * least significant channel mask bit to most significant channel mask bit,
+ * with unused bits skipped. For example for stereo, LEFT would be first,
+ * followed by RIGHT.
+ * Any exceptions to this convention are noted at the appropriate API.
+ *
+ * AudioChannelMask is an opaque type and its internal layout should not be
+ * assumed as it may change in the future.  Instead, always use functions
+ * to examine it.
+ *
+ * These are the current representations:
+ *
+ *   REPRESENTATION_POSITION
+ *     is a channel mask representation for position assignment.  Each low-order
+ *     bit corresponds to the spatial position of a transducer (output), or
+ *     interpretation of channel (input).  The user of a channel mask needs to
+ *     know the context of whether it is for output or input.  The constants
+ *     OUT_* or IN_* apply to the bits portion.  It is not permitted for no bits
+ *     to be set.
+ *
+ *   REPRESENTATION_INDEX
+ *     is a channel mask representation for index assignment.  Each low-order
+ *     bit corresponds to a selected channel.  There is no platform
+ *     interpretation of the various bits.  There is no concept of output or
+ *     input.  It is not permitted for no bits to be set.
+ *
+ * All other representations are reserved for future use.
+ *
+ * Warning: current representation distinguishes between input and output, but
+ * this will not the be case in future revisions of the platform. Wherever there
+ * is an ambiguity between input and output that is currently resolved by
+ * checking the channel mask, the implementer should look for ways to fix it
+ * with additional information outside of the mask.
+ */
+@export(name="", value_prefix="AUDIO_CHANNEL_")
+enum AudioChannelMask : uint32_t {
+    /** must be 0 for compatibility */
+    REPRESENTATION_POSITION = 0,
+    /** 1 is reserved for future use */
+    REPRESENTATION_INDEX    = 2,
+    /* 3 is reserved for future use */
+
+    /** These can be a complete value of AudioChannelMask */
+    NONE                      = 0x0,
+    INVALID                   = 0xC0000000,
+
+   /*
+    * These can be the bits portion of an AudioChannelMask
+    * with representation REPRESENTATION_POSITION.
+    */
+
+    /** output channels */
+    OUT_FRONT_LEFT            = 0x1,
+    OUT_FRONT_RIGHT           = 0x2,
+    OUT_FRONT_CENTER          = 0x4,
+    OUT_LOW_FREQUENCY         = 0x8,
+    OUT_BACK_LEFT             = 0x10,
+    OUT_BACK_RIGHT            = 0x20,
+    OUT_FRONT_LEFT_OF_CENTER  = 0x40,
+    OUT_FRONT_RIGHT_OF_CENTER = 0x80,
+    OUT_BACK_CENTER           = 0x100,
+    OUT_SIDE_LEFT             = 0x200,
+    OUT_SIDE_RIGHT            = 0x400,
+    OUT_TOP_CENTER            = 0x800,
+    OUT_TOP_FRONT_LEFT        = 0x1000,
+    OUT_TOP_FRONT_CENTER      = 0x2000,
+    OUT_TOP_FRONT_RIGHT       = 0x4000,
+    OUT_TOP_BACK_LEFT         = 0x8000,
+    OUT_TOP_BACK_CENTER       = 0x10000,
+    OUT_TOP_BACK_RIGHT        = 0x20000,
+    OUT_TOP_SIDE_LEFT         = 0x40000,
+    OUT_TOP_SIDE_RIGHT        = 0x80000,
+
+    /**
+     * Haptic channel characteristics are specific to a device and
+     * only used to play device specific resources (eg: ringtones).
+     * The HAL can freely map A and B to haptic controllers, the
+     * framework shall not interpret those values and forward them
+     * from the device audio assets.
+     */
+    OUT_HAPTIC_A              = 0x20000000,
+    OUT_HAPTIC_B              = 0x10000000,
+
+    OUT_MONO     = OUT_FRONT_LEFT,
+    OUT_STEREO   = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
+    OUT_2POINT1  = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
+    OUT_2POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+                         OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+                         OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT |
+                         OUT_LOW_FREQUENCY),
+    OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER |
+                         OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_FRONT_CENTER |
+                        OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT |
+                        OUT_LOW_FREQUENCY),
+    OUT_QUAD     = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT),
+    OUT_QUAD_BACK = OUT_QUAD,
+    /** like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
+    OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_BACK_CENTER),
+    OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER),
+    OUT_5POINT1   = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT),
+    OUT_5POINT1_BACK = OUT_5POINT1,
+    /** like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
+    OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_5POINT1POINT2  = (OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_5POINT1POINT4  = (OUT_5POINT1 |
+            OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT |
+            OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
+    OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT |
+            OUT_BACK_CENTER),
+    /** matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND */
+    OUT_7POINT1  = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT |
+            OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_7POINT1POINT2  = (OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+    OUT_7POINT1POINT4  = (OUT_7POINT1 |
+            OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT |
+            OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
+    OUT_MONO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_HAPTIC_A),
+    OUT_STEREO_HAPTIC_A = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_HAPTIC_A),
+    OUT_HAPTIC_AB = (OUT_HAPTIC_A | OUT_HAPTIC_B),
+    OUT_MONO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_HAPTIC_A | OUT_HAPTIC_B),
+    OUT_STEREO_HAPTIC_AB = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_HAPTIC_A | OUT_HAPTIC_B),
+    // Note that the 2.0 OUT_ALL* have been moved to helper functions
+
+    /* These are bits only, not complete values */
+
+    /** input channels */
+    IN_LEFT            = 0x4,
+    IN_RIGHT           = 0x8,
+    IN_FRONT           = 0x10,
+    IN_BACK            = 0x20,
+    IN_LEFT_PROCESSED  = 0x40,
+    IN_RIGHT_PROCESSED = 0x80,
+    IN_FRONT_PROCESSED = 0x100,
+    IN_BACK_PROCESSED  = 0x200,
+    IN_PRESSURE        = 0x400,
+    IN_X_AXIS          = 0x800,
+    IN_Y_AXIS          = 0x1000,
+    IN_Z_AXIS          = 0x2000,
+    IN_BACK_LEFT       = 0x10000,
+    IN_BACK_RIGHT      = 0x20000,
+    IN_CENTER          = 0x40000,
+    IN_LOW_FREQUENCY   = 0x100000,
+    IN_TOP_LEFT        = 0x200000,
+    IN_TOP_RIGHT       = 0x400000,
+
+    IN_VOICE_UPLINK    = 0x4000,
+    IN_VOICE_DNLINK    = 0x8000,
+
+    IN_MONO   = IN_FRONT,
+    IN_STEREO = (IN_LEFT | IN_RIGHT),
+    IN_FRONT_BACK = (IN_FRONT | IN_BACK),
+    IN_6 = (IN_LEFT | IN_RIGHT |
+            IN_FRONT | IN_BACK |
+            IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED),
+    IN_2POINT0POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT),
+    IN_2POINT1POINT2 = (IN_LEFT | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT |
+            IN_LOW_FREQUENCY),
+    IN_3POINT0POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT | IN_TOP_LEFT | IN_TOP_RIGHT),
+    IN_3POINT1POINT2 = (IN_LEFT | IN_CENTER | IN_RIGHT |
+            IN_TOP_LEFT | IN_TOP_RIGHT | IN_LOW_FREQUENCY),
+    IN_5POINT1 = (IN_LEFT | IN_CENTER | IN_RIGHT |
+                  IN_BACK_LEFT | IN_BACK_RIGHT | IN_LOW_FREQUENCY),
+    IN_VOICE_UPLINK_MONO = (IN_VOICE_UPLINK | IN_MONO),
+    IN_VOICE_DNLINK_MONO = (IN_VOICE_DNLINK | IN_MONO),
+    IN_VOICE_CALL_MONO   = (IN_VOICE_UPLINK_MONO |
+            IN_VOICE_DNLINK_MONO),
+    // Note that the 2.0 IN_ALL* have been moved to helper functions
+
+    COUNT_MAX    = 30,
+    INDEX_HDR    = REPRESENTATION_INDEX << COUNT_MAX,
+    INDEX_MASK_1 = INDEX_HDR | ((1 << 1) - 1),
+    INDEX_MASK_2 = INDEX_HDR | ((1 << 2) - 1),
+    INDEX_MASK_3 = INDEX_HDR | ((1 << 3) - 1),
+    INDEX_MASK_4 = INDEX_HDR | ((1 << 4) - 1),
+    INDEX_MASK_5 = INDEX_HDR | ((1 << 5) - 1),
+    INDEX_MASK_6 = INDEX_HDR | ((1 << 6) - 1),
+    INDEX_MASK_7 = INDEX_HDR | ((1 << 7) - 1),
+    INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1),
+    INDEX_MASK_9 = INDEX_HDR | ((1 << 9) - 1),
+    INDEX_MASK_10 = INDEX_HDR | ((1 << 10) - 1),
+    INDEX_MASK_11 = INDEX_HDR | ((1 << 11) - 1),
+    INDEX_MASK_12 = INDEX_HDR | ((1 << 12) - 1),
+    INDEX_MASK_13 = INDEX_HDR | ((1 << 13) - 1),
+    INDEX_MASK_14 = INDEX_HDR | ((1 << 14) - 1),
+    INDEX_MASK_15 = INDEX_HDR | ((1 << 15) - 1),
+    INDEX_MASK_16 = INDEX_HDR | ((1 << 16) - 1),
+    INDEX_MASK_17 = INDEX_HDR | ((1 << 17) - 1),
+    INDEX_MASK_18 = INDEX_HDR | ((1 << 18) - 1),
+    INDEX_MASK_19 = INDEX_HDR | ((1 << 19) - 1),
+    INDEX_MASK_20 = INDEX_HDR | ((1 << 20) - 1),
+    INDEX_MASK_21 = INDEX_HDR | ((1 << 21) - 1),
+    INDEX_MASK_22 = INDEX_HDR | ((1 << 22) - 1),
+    INDEX_MASK_23 = INDEX_HDR | ((1 << 23) - 1),
+    INDEX_MASK_24 = INDEX_HDR | ((1 << 24) - 1),
+};
+
+/**
+ * Major modes for a mobile device. The current mode setting affects audio
+ * routing.
+ */
+@export(name="audio_mode_t", value_prefix="AUDIO_MODE_")
+enum AudioMode : int32_t {
+    NORMAL           = 0,
+    RINGTONE         = 1,
+    /** Calls handled by the telephony stack (Eg: PSTN). */
+    IN_CALL          = 2,
+    /** Calls handled by apps (Eg: Hangout). */
+    IN_COMMUNICATION = 3,
+};
+
+@export(name="", value_prefix="AUDIO_DEVICE_")
+enum AudioDevice : uint32_t {
+    NONE                          = 0x0,
+    /** reserved bits */
+    BIT_IN                        = 0x80000000,
+    BIT_DEFAULT                   = 0x40000000,
+    /** output devices */
+    OUT_EARPIECE                  = 0x1,
+    OUT_SPEAKER                   = 0x2,
+    OUT_WIRED_HEADSET             = 0x4,
+    OUT_WIRED_HEADPHONE           = 0x8,
+    OUT_BLUETOOTH_SCO             = 0x10,
+    OUT_BLUETOOTH_SCO_HEADSET     = 0x20,
+    OUT_BLUETOOTH_SCO_CARKIT      = 0x40,
+    OUT_BLUETOOTH_A2DP            = 0x80,
+    OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+    OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200,
+    OUT_AUX_DIGITAL               = 0x400,
+    OUT_HDMI                      = OUT_AUX_DIGITAL,
+    /** uses an analog connection (multiplexed over the USB pins for instance) */
+    OUT_ANLG_DOCK_HEADSET         = 0x800,
+    OUT_DGTL_DOCK_HEADSET         = 0x1000,
+    /** USB accessory mode: Android device is USB device and dock is USB host */
+    OUT_USB_ACCESSORY             = 0x2000,
+    /** USB host mode: Android device is USB host and dock is USB device */
+    OUT_USB_DEVICE                = 0x4000,
+    OUT_REMOTE_SUBMIX             = 0x8000,
+    /** Telephony voice TX path */
+    OUT_TELEPHONY_TX              = 0x10000,
+    /** Analog jack with line impedance detected */
+    OUT_LINE                      = 0x20000,
+    /** HDMI Audio Return Channel */
+    OUT_HDMI_ARC                  = 0x40000,
+    /** S/PDIF out */
+    OUT_SPDIF                     = 0x80000,
+    /** FM transmitter out */
+    OUT_FM                        = 0x100000,
+    /** Line out for av devices */
+    OUT_AUX_LINE                  = 0x200000,
+    /** limited-output speaker device for acoustic safety */
+    OUT_SPEAKER_SAFE              = 0x400000,
+    OUT_IP                        = 0x800000,
+    /** audio bus implemented by the audio system (e.g an MOST stereo channel) */
+    OUT_BUS                       = 0x1000000,
+    OUT_PROXY                     = 0x2000000,
+    OUT_USB_HEADSET               = 0x4000000,
+    OUT_HEARING_AID               = 0x8000000,
+    OUT_ECHO_CANCELLER            = 0x10000000,
+    OUT_DEFAULT                   = BIT_DEFAULT,
+    // Note that the 2.0 OUT_ALL* have been moved to helper functions
+
+    /** input devices */
+    IN_COMMUNICATION         = BIT_IN | 0x1,
+    IN_AMBIENT               = BIT_IN | 0x2,
+    IN_BUILTIN_MIC           = BIT_IN | 0x4,
+    IN_BLUETOOTH_SCO_HEADSET = BIT_IN | 0x8,
+    IN_WIRED_HEADSET         = BIT_IN | 0x10,
+    IN_AUX_DIGITAL           = BIT_IN | 0x20,
+    IN_HDMI                  = IN_AUX_DIGITAL,
+    /** Telephony voice RX path */
+    IN_VOICE_CALL            = BIT_IN | 0x40,
+    IN_TELEPHONY_RX          = IN_VOICE_CALL,
+    IN_BACK_MIC              = BIT_IN | 0x80,
+    IN_REMOTE_SUBMIX         = BIT_IN | 0x100,
+    IN_ANLG_DOCK_HEADSET     = BIT_IN | 0x200,
+    IN_DGTL_DOCK_HEADSET     = BIT_IN | 0x400,
+    IN_USB_ACCESSORY         = BIT_IN | 0x800,
+    IN_USB_DEVICE            = BIT_IN | 0x1000,
+    /** FM tuner input */
+    IN_FM_TUNER              = BIT_IN | 0x2000,
+    /** TV tuner input */
+    IN_TV_TUNER              = BIT_IN | 0x4000,
+    /** Analog jack with line impedance detected */
+    IN_LINE                  = BIT_IN | 0x8000,
+    /** S/PDIF in */
+    IN_SPDIF                 = BIT_IN | 0x10000,
+    IN_BLUETOOTH_A2DP        = BIT_IN | 0x20000,
+    IN_LOOPBACK              = BIT_IN | 0x40000,
+    IN_IP                    = BIT_IN | 0x80000,
+    /** audio bus implemented by the audio system (e.g an MOST stereo channel) */
+    IN_BUS                   = BIT_IN | 0x100000,
+    IN_PROXY                 = BIT_IN | 0x1000000,
+    IN_USB_HEADSET           = BIT_IN | 0x2000000,
+    IN_BLUETOOTH_BLE         = BIT_IN | 0x4000000,
+    IN_ECHO_REFERENCE        = BIT_IN | 0x10000000,
+    IN_DEFAULT               = BIT_IN | BIT_DEFAULT,
+
+    // Note that the 2.0 IN_ALL* have been moved to helper functions
+};
+
+/**
+ * IEEE 802 MAC address.
+ */
+typedef uint8_t[6] MacAddress;
+
+/**
+ * Specifies a device address in case when several devices of the same type
+ * can be connected (e.g. BT A2DP, USB).
+ */
+struct DeviceAddress {
+    AudioDevice device;  // discriminator
+    union Address {
+        MacAddress mac;     // used for BLUETOOTH_A2DP_*
+        uint8_t[4] ipv4;    // used for IP
+        struct Alsa {
+            int32_t card;
+            int32_t device;
+        } alsa;             // used for USB_*
+    } address;
+    /** Arbitrary BUS device unique address. Should not be interpreted by the framework. */
+    string busAddress;
+    /** Arbitrary REMOTE_SUBMIX device unique address. Should not be interpreted by the HAL. */
+    string rSubmixAddress;
+};
+
+/**
+ * The audio output flags serve two purposes:
+ *
+ *  - when an AudioTrack is created they indicate a "wish" to be connected to an
+ *    output stream with attributes corresponding to the specified flags;
+ *
+ *  - when present in an output profile descriptor listed for a particular audio
+ *    hardware module, they indicate that an output stream can be opened that
+ *    supports the attributes indicated by the flags.
+ *
+ * The audio policy manager will try to match the flags in the request
+ * (when getOuput() is called) to an available output stream.
+ */
+@export(name="audio_output_flags_t", value_prefix="AUDIO_OUTPUT_FLAG_")
+enum AudioOutputFlag : int32_t {
+    NONE    = 0x0, // no attributes
+    DIRECT  = 0x1, // this output directly connects a track
+                   // to one output stream: no software mixer
+    PRIMARY = 0x2, // this output is the primary output of the device. It is
+                   // unique and must be present. It is opened by default and
+                   // receives routing, audio mode and volume controls related
+                   // to voice calls.
+    FAST    = 0x4,    // output supports "fast tracks", defined elsewhere
+    DEEP_BUFFER      = 0x8,   // use deep audio buffers
+    COMPRESS_OFFLOAD = 0x10,  // offload playback of compressed streams to
+                              // hardware codec
+    NON_BLOCKING     = 0x20,  // use non-blocking write
+    HW_AV_SYNC = 0x40,   // output uses a hardware A/V sync
+    TTS        = 0x80,   // output for streams transmitted through speaker at a
+                         // sample rate high enough to accommodate lower-range
+                         // ultrasonic p/b
+    RAW        = 0x100,  // minimize signal processing
+    SYNC       = 0x200,  // synchronize I/O streams
+    IEC958_NONAUDIO = 0x400, // Audio stream contains compressed audio in SPDIF
+                             // data bursts, not PCM.
+    DIRECT_PCM = 0x2000,     // Audio stream containing PCM data that needs
+                             // to pass through compress path for DSP post proc.
+    MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode.
+    VOIP_RX = 0x8000,    // preferred output for VoIP calls.
+    /** preferred output for call music */
+    INCALL_MUSIC = 0x10000,
+};
+
+/**
+ * The audio input flags are analogous to audio output flags.
+ * Currently they are used only when an AudioRecord is created,
+ * to indicate a preference to be connected to an input stream with
+ * attributes corresponding to the specified flags.
+ */
+@export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_")
+enum AudioInputFlag : int32_t {
+    NONE         = 0x0,  // no attributes
+    FAST         = 0x1,  // prefer an input that supports "fast tracks"
+    HW_HOTWORD   = 0x2,  // prefer an input that captures from hw hotword source
+    RAW          = 0x4,  // minimize signal processing
+    SYNC         = 0x8,  // synchronize I/O streams
+    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
+};
+
+@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
+enum AudioUsage : int32_t {
+    // These values must kept in sync with
+    //  frameworks/base/media/java/android/media/AudioAttributes.java
+    // Note that not all framework values are exposed
+    UNKNOWN                            = 0,
+    MEDIA                              = 1,
+    VOICE_COMMUNICATION                = 2,
+    VOICE_COMMUNICATION_SIGNALLING     = 3,
+    ALARM                              = 4,
+    NOTIFICATION                       = 5,
+    NOTIFICATION_TELEPHONY_RINGTONE    = 6,
+    ASSISTANCE_ACCESSIBILITY           = 11,
+    ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
+    ASSISTANCE_SONIFICATION            = 13,
+    GAME                               = 14,
+    VIRTUAL_SOURCE                     = 15,
+    ASSISTANT                          = 16,
+};
+
+/** Type of audio generated by an application. */
+@export(name="audio_content_type_t", value_prefix="AUDIO_CONTENT_TYPE_")
+enum AudioContentType : uint32_t {
+    // Do not change these values without updating their counterparts
+    // in frameworks/base/media/java/android/media/AudioAttributes.java
+    UNKNOWN      = 0,
+    SPEECH       = 1,
+    MUSIC        = 2,
+    MOVIE        = 3,
+    SONIFICATION = 4,
+};
+
+/**
+ * Additional information about the stream passed to hardware decoders.
+ */
+struct AudioOffloadInfo {
+    uint32_t sampleRateHz;
+    bitfield<AudioChannelMask> channelMask;
+    AudioFormat format;
+    AudioStreamType streamType;
+    uint32_t bitRatePerSecond;
+    int64_t durationMicroseconds;  // -1 if unknown
+    bool hasVideo;
+    bool isStreaming;
+    uint32_t bitWidth;
+    uint32_t bufferSize;
+    AudioUsage usage;
+};
+
+/**
+ * Commonly used audio stream configuration parameters.
+ */
+struct AudioConfig {
+    uint32_t sampleRateHz;
+    bitfield<AudioChannelMask> channelMask;
+    AudioFormat format;
+    AudioOffloadInfo offloadInfo;
+    uint64_t frameCount;
+};
+
+/** Metadata of a playback track for a StreamOut. */
+struct PlaybackTrackMetadata {
+    AudioUsage usage;
+    AudioContentType contentType;
+    /**
+     * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+     * 2 means double amplification...
+     * Must not be negative.
+     */
+    float gain;
+};
+
+/** Metadatas of the source of a StreamOut. */
+struct SourceMetadata {
+    vec<PlaybackTrackMetadata> tracks;
+};
+
+/** Metadata of a record track for a StreamIn. */
+struct RecordTrackMetadata {
+    AudioSource source;
+    /**
+     * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+     * 2 means double amplification...
+     * Must not be negative.
+     */
+    float gain;
+    /**
+     * Indicates the destination of an input stream, can be left unspecified.
+     */
+    safe_union Destination {
+        Monostate unspecified;
+        DeviceAddress device;
+    };
+    Destination destination;
+};
+
+/** Metadatas of the sink of a StreamIn. */
+struct SinkMetadata {
+    vec<RecordTrackMetadata> tracks;
+};
+
+
+/*
+ *
+ *  Volume control
+ *
+ */
+
+/**
+ * Type of gain control exposed by an audio port.
+ */
+@export(name="", value_prefix="AUDIO_GAIN_MODE_")
+enum AudioGainMode : uint32_t {
+    JOINT = 0x1,    // supports joint channel gain control
+    CHANNELS = 0x2, // supports separate channel gain control
+    RAMP = 0x4      // supports gain ramps
+};
+
+/**
+ * An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port.
+ */
+struct AudioGain {
+    bitfield<AudioGainMode> mode;
+    bitfield<AudioChannelMask> channelMask; // channels which gain an be controlled
+    int32_t minValue;     // minimum gain value in millibels
+    int32_t maxValue;     // maximum gain value in millibels
+    int32_t defaultValue; // default gain value in millibels
+    uint32_t stepValue;   // gain step in millibels
+    uint32_t minRampMs;   // minimum ramp duration in ms
+    uint32_t maxRampMs;   // maximum ramp duration in ms
+};
+
+/**
+ * The gain configuration structure is used to get or set the gain values of a
+ * given port.
+ */
+struct AudioGainConfig {
+    int32_t index;  // index of the corresponding AudioGain in AudioPort.gains
+    AudioGainMode mode;
+    AudioChannelMask channelMask;  // channels which gain value follows
+    /**
+     * 4 = sizeof(AudioChannelMask),
+     * 8 is not "FCC_8", so it won't need to be changed for > 8 channels.
+     * Gain values in millibels for each channel ordered from LSb to MSb in
+     * channel mask. The number of values is 1 in joint mode or
+     * popcount(channel_mask).
+     */
+    int32_t[4 * 8] values;
+    uint32_t rampDurationMs;  // ramp duration in ms
+};
+
+
+/*
+ *
+ *  Routing control
+ *
+ */
+
+/*
+ * Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * the interface.
+ */
+
+/** Audio port role: either source or sink */
+@export(name="audio_port_role_t", value_prefix="AUDIO_PORT_ROLE_")
+enum AudioPortRole : int32_t {
+    NONE,
+    SOURCE,
+    SINK,
+};
+
+/**
+ * Audio port type indicates if it is a session (e.g AudioTrack), a mix (e.g
+ * PlaybackThread output) or a physical device (e.g OUT_SPEAKER)
+ */
+@export(name="audio_port_type_t", value_prefix="AUDIO_PORT_TYPE_")
+enum AudioPortType : int32_t {
+    NONE,
+    DEVICE,
+    MIX,
+    SESSION,
+};
+
+/**
+ * Extension for audio port configuration structure when the audio port is a
+ * hardware device.
+ */
+struct AudioPortConfigDeviceExt {
+    AudioModuleHandle hwModule;  // module the device is attached to
+    AudioDevice type;            // device type (e.g OUT_SPEAKER)
+    uint8_t[32] address;         // device address. "" if N/A
+};
+
+/**
+ * Extension for audio port configuration structure when the audio port is an
+ * audio session.
+ */
+struct AudioPortConfigSessionExt {
+    AudioSession session;
+};
+
+/**
+ * Flags indicating which fields are to be considered in AudioPortConfig.
+ */
+@export(name="", value_prefix="AUDIO_PORT_CONFIG_")
+enum AudioPortConfigMask : uint32_t {
+    SAMPLE_RATE = 0x1,
+    CHANNEL_MASK =  0x2,
+    FORMAT = 0x4,
+    GAIN = 0x8,
+};
+
+/**
+ * Audio port configuration structure used to specify a particular configuration
+ * of an audio port.
+ */
+struct AudioPortConfig {
+    AudioPortHandle id;
+    bitfield<AudioPortConfigMask> configMask;
+    uint32_t sampleRateHz;
+    bitfield<AudioChannelMask> channelMask;
+    AudioFormat format;
+    AudioGainConfig gain;
+    AudioPortType type;  // type is used as a discriminator for Ext union
+    AudioPortRole role;  // role is used as a discriminator for UseCase union
+    union Ext {
+        AudioPortConfigDeviceExt device;
+        struct AudioPortConfigMixExt {
+            AudioModuleHandle hwModule; // module the stream is attached to
+            AudioIoHandle ioHandle;     // I/O handle of the input/output stream
+            union UseCase {
+                AudioStreamType stream;
+                AudioSource source;
+            } useCase;
+        } mix;
+        AudioPortConfigSessionExt session;
+    } ext;
+};
+
+/**
+ * Extension for audio port structure when the audio port is a hardware device.
+ */
+struct AudioPortDeviceExt {
+    AudioModuleHandle hwModule;    // module the device is attached to
+    AudioDevice type;
+    /** 32 byte string identifying the port. */
+    uint8_t[32] address;
+};
+
+/**
+ * Latency class of the audio mix.
+ */
+@export(name="audio_mix_latency_class_t", value_prefix="AUDIO_LATENCY_")
+enum AudioMixLatencyClass : int32_t {
+    LOW,
+    NORMAL
+};
+
+struct AudioPortMixExt {
+    AudioModuleHandle hwModule;     // module the stream is attached to
+    AudioIoHandle ioHandle;         // I/O handle of the stream
+    AudioMixLatencyClass latencyClass;
+};
+
+/**
+ * Extension for audio port structure when the audio port is an audio session.
+ */
+struct AudioPortSessionExt {
+    AudioSession session;
+};
+
+struct AudioPort {
+    AudioPortHandle id;
+    AudioPortRole role;
+    string name;
+    vec<uint32_t> sampleRates;
+    vec<bitfield<AudioChannelMask>> channelMasks;
+    vec<AudioFormat> formats;
+    vec<AudioGain> gains;
+    AudioPortConfig activeConfig; // current audio port configuration
+    AudioPortType type;  // type is used as a discriminator
+    union Ext {
+        AudioPortDeviceExt device;
+        AudioPortMixExt mix;
+        AudioPortSessionExt session;
+    } ext;
+};
+
+struct ThreadInfo {
+    int64_t pid;
+    int64_t tid;
+};
diff --git a/audio/common/all-versions/copyHAL.sh b/audio/common/all-versions/copyHAL.sh
new file mode 100755
index 0000000..d07012f
--- /dev/null
+++ b/audio/common/all-versions/copyHAL.sh
@@ -0,0 +1,204 @@
+#/usr/bin/env bash
+
+set -euo pipefail
+
+if (echo "$@" |grep -qe -h); then
+    echo "This script will generate a new HAL version identical to an other one."
+    echo "This helps creating the boilerplate for a new version."
+    echo
+    echo "USAGE: $0 [BASE_VERSION] [NEW_VERSION]"
+    echo "       BASE_VERSION default value is the highest version currently existing"
+    echo "       NEW_VERSION default value is BASE_VERSION + 1"
+    echo
+    echo "Example: to generate a V6.0 by copying V5, do: $0 5.0 6.0"
+    exit
+fi
+readonly HAL_DIRECTORY=hardware/interfaces/audio
+readonly HAL_VTS_DIRECTORY=core/all-versions/vts/functional
+readonly HAL_VTS_FILE=AudioPrimaryHidlHalTest.cpp
+readonly HAL_SERVICE_DIRECTORY=common/all-versions/default/service/
+readonly HAL_SERVICE_CPP=service.cpp
+
+readonly FWK_DIRECTORY=frameworks/av/media/libaudiohal
+readonly IMPL_DIRECTORY=impl
+readonly IMPL_FACTORYHAL=$IMPL_DIRECTORY/include/libaudiohal/FactoryHalHidl.h
+
+readonly VTS_DIRECTORY=test/vts-testcase/hal/audio
+readonly VTS_LIST=test/vts/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk
+readonly WATCHDOG=frameworks/base/services/core/java/com/android/server/Watchdog.cpp
+readonly GSI_CURRENT=build/make/target/product/gsi/current.txt
+
+readonly BASE_VERSION=${1:-$(ls $ANDROID_BUILD_TOP/$HAL_DIRECTORY | grep -E '[0-9]+\.[0-9]+' |
+                                  sort -n |tail -n1)}
+readonly BASE_MAJOR_VERSION=${BASE_VERSION%.*}
+readonly BASE_MINOR_VERSION=${BASE_VERSION##*.}
+
+readonly NEW_VERSION="${2:-$((${BASE_MAJOR_VERSION} + 1)).0}"
+readonly NEW_MAJOR_VERSION=${NEW_VERSION%.*}
+readonly NEW_MINOR_VERSION=${NEW_VERSION##*.}
+
+
+readonly BASE_VERSION_REGEX="${BASE_MAJOR_VERSION}[._]${BASE_MINOR_VERSION}"
+readonly NEW_VERSION_REGEX="${NEW_MAJOR_VERSION}[._]${NEW_MINOR_VERSION}"
+
+readonly BASE_VERSION_ESCAPE="${BASE_MAJOR_VERSION}\.${BASE_MINOR_VERSION}"
+readonly BASE_VERSION_UNDERSCORE="${BASE_MAJOR_VERSION}_${BASE_MINOR_VERSION}"
+readonly NEW_VERSION_UNDERSCORE="${NEW_MAJOR_VERSION}_${NEW_MINOR_VERSION}"
+updateVersion() {
+    if [ $1 == "-e" ]; then
+        local -r REGEX="$2"; shift 2
+    else
+        local -r REGEX="$BASE_VERSION_REGEX"
+    fi
+    awk -i inplace -e "{if (!/$REGEX/) print; else {
+                            if (original_before) print
+                            if (original_after) original_line=\$0;
+
+                            gsub(/$BASE_VERSION_ESCAPE/,\"$NEW_VERSION\");
+                            gsub(/$BASE_VERSION_UNDERSCORE/,\"$NEW_VERSION_UNDERSCORE\");
+                            gsub(/MAJOR_VERSION=$BASE_MAJOR_VERSION/,
+                                 \"MAJOR_VERSION=$NEW_MAJOR_VERSION\");
+                            gsub(/MINOR_VERSION=$BASE_MINOR_VERSION/,
+                                 \"MINOR_VERSION=$NEW_MINOR_VERSION\");
+
+                            print
+                            if (original_after) print original_line
+                       }}" "$@"
+}
+
+updateAudioVersion() {
+    updateVersion -e "audio.*$BASE_VERSION_REGEX" "$@"
+}
+
+updateLicenceDates() {
+    # Update date on the 2 first lines
+    sed -i "1,2 s/20[0-9][0-9]/$(date +"%Y")/g" "$@"
+}
+
+echo "Creating new audio HAL V$NEW_VERSION based on V$BASE_VERSION"
+echo "Press Ctrl-C to cancel, Enter to continue"
+read
+
+MODIFIED=
+runIfNeeded() {
+    local -r TARGET=$1; shift
+    cd $ANDROID_BUILD_TOP/$TARGET
+    if grep -q -r "audio.*$NEW_VERSION_REGEX"; then
+        echo "  Skipping $TARGET as already up to date"
+    else
+        echo "  Updating $PWD"
+        MODIFIED+=$'\n - '$TARGET
+        "$@"
+    fi
+}
+
+createHALVersion() {
+    local -r DIRS=". common effect"
+    local COPY=
+    echo "Copy $BASE_VERSION to $NEW_VERSION in $DIRS"
+    for DIR in $DIRS; do
+        cp -Tar $DIR/$BASE_VERSION $DIR/$NEW_VERSION
+        COPY+=" $DIR/$NEW_VERSION"
+    done
+
+    echo "Replacing $BASE_VERSION by $NEW_VERSION in the copied files"
+    updateVersion $(find $COPY -type f)
+    updateLicenceDates $(find $COPY -type f)
+
+    echo "Update implementation and VTS generic code"
+    local -r FILES="*/all-versions/default/Android.bp */all-versions/vts/functional/Android.bp"
+    updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $FILES
+    sed -i '${/^$/d}' $FILES # Remove \n at the end of the files
+
+    updateVersion -v original_before=1 $HAL_SERVICE_DIRECTORY/Android.bp
+
+    updateVersion -e "audio::.*$BASE_VERSION_REGEX" -v original_after=1 \
+        $HAL_SERVICE_DIRECTORY/$HAL_SERVICE_CPP
+    updateVersion -e "audio\/.*$BASE_VERSION_REGEX" -v original_before=1 \
+        $HAL_SERVICE_DIRECTORY/$HAL_SERVICE_CPP
+
+    local -r HAL_VTS_PATH=$HAL_VTS_DIRECTORY/$NEW_VERSION/$HAL_VTS_FILE
+    mkdir -p $(dirname $HAL_VTS_PATH)
+    cat > $HAL_VTS_PATH <<EOF
+/*
+ * Copyright (C) $(date +"%Y") The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// pull in all the <= $BASE_VERSION tests
+#include "$BASE_VERSION/$(basename AudioPrimaryHidlHalTest.cpp)"
+EOF
+
+    echo "New HAL version $NEW_VERSION successfully created"
+}
+
+echo "Creating new audio HAL definition, default impl and VTS"
+runIfNeeded $HAL_DIRECTORY createHALVersion
+
+
+createFrameworkAdapter() {
+    updateVersion -v original_before=1 Android.bp
+    updateVersion -v original_before=1 -v RS= -v ORS='\n\n' $IMPL_FACTORYHAL/Android.bp
+    updateVersion -v original_after=1 $IMPL_FACTORYHAL
+}
+echo "Now creating the framework adapter version"
+runIfNeeded $FWK_DIRECTORY createFrameworkAdapter
+
+createVTSXML() {
+    cp -Tar V$BASE_VERSION_UNDERSCORE V$NEW_VERSION_UNDERSCORE
+    cp -Tar effect/{V$BASE_VERSION_UNDERSCORE,V$NEW_VERSION_UNDERSCORE}
+    local -r FILES=$(find {.,effect}/V$NEW_VERSION_UNDERSCORE -type f)
+    updateVersion $FILES
+    updateLicenceDates $FILES
+}
+echo "Now update VTS XML"
+runIfNeeded $VTS_DIRECTORY createVTSXML
+
+echo "Now register new VTS"
+runIfNeeded $(dirname $VTS_LIST) updateAudioVersion -v original_before=1 $(basename $VTS_LIST)
+
+echo "Now update watchdog"
+runIfNeeded $(dirname $WATCHDOG) updateAudioVersion -v original_before=1 $(basename $WATCHDOG)
+
+echo "Now update GSI current.txt"
+runIfNeeded $(dirname $GSI_CURRENT) update-vndk-list.sh
+
+if ! [ "$MODIFIED" ]; then
+    echo
+    echo "$NEW_VERSION already exist, nothing to do"
+    exit
+fi
+
+cat << EOF
+
+All File generated successfully. Please submit a patch in all those directories: $MODIFIED
+
+-----------------------------------------------------------
+WHAT WAS *NOT* DONE, and you need to do now:
+ 1) You need to choose if the new HAL is optional or not for new devices.
+    Either add or replace $BASE_VERSION by $NEW_VERSION in
+    compatibility_matrices/compatibility_matrix.current.xml
+    Do not forget to update both the "audio" and "audio.effects" HAL'
+
+ 2) Then you need to choose a device to update its audio HAL implementation:
+    a) Update the HAL manifest of your device: open your device manifest.xml
+       and replace $BASE_VERSION by $NEW_VERSION for both
+        - android.hardware.audio
+        - android.hardware.audio.effect
+    b) Go to your device device.mk (usually next to the manifest) and replace:
+        - android.hardware.audio@$BASE_VERSION-impl by
+          android.hardware.audio@$NEW_VERSION-impl
+        - android.hardware.audio.effect@$BASE_VERSION-impl by
+          android.hardware.audio.effect@$NEW_VERSION-impl
+EOF
diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp
index c0bd34c..0eb4a71 100644
--- a/audio/common/all-versions/default/Android.bp
+++ b/audio/common/all-versions/default/Android.bp
@@ -69,7 +69,6 @@
 cc_library_shared {
     name: "android.hardware.audio.common@2.0-util",
     defaults: ["android.hardware.audio.common-util_default"],
-
     shared_libs: [
         "android.hardware.audio.common@2.0",
     ],
@@ -83,7 +82,6 @@
 cc_library_shared {
     name: "android.hardware.audio.common@4.0-util",
     defaults: ["android.hardware.audio.common-util_default"],
-
     shared_libs: [
         "android.hardware.audio.common@4.0",
     ],
@@ -97,7 +95,6 @@
 cc_library_shared {
     name: "android.hardware.audio.common@5.0-util",
     defaults: ["android.hardware.audio.common-util_default"],
-
     shared_libs: [
         "android.hardware.audio.common@5.0",
     ],
@@ -107,3 +104,16 @@
         "-include common/all-versions/VersionMacro.h",
     ]
 }
+
+cc_library_shared {
+    name: "android.hardware.audio.common@6.0-util",
+    defaults: ["android.hardware.audio.common-util_default"],
+    shared_libs: [
+        "android.hardware.audio.common@6.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
new file mode 100644
index 0000000..4565730
--- /dev/null
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -0,0 +1,51 @@
+cc_binary {
+    name: "android.hardware.audio.service",
+
+    init_rc: ["android.hardware.audio.service.rc"],
+    relative_install_path: "hw",
+    vendor: true,
+    // Only support 32 bit  as the binary must always be installed at the same
+    // location for init to start it and the build system does not support
+    // having two binaries installable to the same location even if they are
+    // not installed in the same build.
+    compile_multilib: "32",
+    srcs: ["service.cpp"],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libbinder",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "libhardware",
+        "android.hardware.audio@2.0",
+        "android.hardware.audio@4.0",
+        "android.hardware.audio@5.0",
+        "android.hardware.audio@6.0",
+        "android.hardware.audio.common@2.0",
+        "android.hardware.audio.common@4.0",
+        "android.hardware.audio.common@5.0",
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.effect@2.0",
+        "android.hardware.audio.effect@4.0",
+        "android.hardware.audio.effect@5.0",
+        "android.hardware.audio.effect@6.0",
+        "android.hardware.bluetooth.a2dp@1.0",
+        "android.hardware.bluetooth.audio@2.0",
+        "android.hardware.soundtrigger@2.0",
+        "android.hardware.soundtrigger@2.1",
+        "android.hardware.soundtrigger@2.2",
+    ],
+}
+
+// Legacy service name, use android.hardware.audio.service instead
+phony {
+    name: "android.hardware.audio@2.0-service",
+    required: ["android.hardware.audio.service"],
+}
diff --git a/audio/common/all-versions/default/service/Android.mk b/audio/common/all-versions/default/service/Android.mk
deleted file mode 100644
index 236f1fd..0000000
--- a/audio/common/all-versions/default/service/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-LOCAL_PATH := $(call my-dir)
-
-#
-# Service
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.audio@2.0-service
-LOCAL_INIT_RC := android.hardware.audio@2.0-service.rc
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_SRC_FILES := \
-    service.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libbinder \
-    libhidlbase \
-    liblog \
-    libutils \
-    libhardware \
-    android.hardware.audio@2.0 \
-    android.hardware.audio@4.0 \
-    android.hardware.audio@5.0 \
-    android.hardware.audio.common@2.0 \
-    android.hardware.audio.common@4.0 \
-    android.hardware.audio.common@5.0 \
-    android.hardware.audio.effect@2.0 \
-    android.hardware.audio.effect@4.0 \
-    android.hardware.audio.effect@5.0 \
-    android.hardware.bluetooth.a2dp@1.0 \
-    android.hardware.bluetooth.audio@2.0 \
-    android.hardware.soundtrigger@2.0 \
-    android.hardware.soundtrigger@2.1 \
-    android.hardware.soundtrigger@2.2
-
-# Can not switch to Android.bp until AUDIOSERVER_MULTILIB
-# is deprecated as build config variable are not supported
-ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
-LOCAL_MULTILIB := 32
-else
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-endif
-
-include $(BUILD_EXECUTABLE)
diff --git a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
similarity index 81%
rename from audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
rename to audio/common/all-versions/default/service/android.hardware.audio.service.rc
index 72b4d19..63d2542 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio@2.0-service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
@@ -1,4 +1,4 @@
-service vendor.audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service
+service vendor.audio-hal /vendor/bin/hw/android.hardware.audio.service
     class hal
     user audioserver
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 8a7b2ea..2730f3b 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -19,9 +19,11 @@
 #include <android/hardware/audio/2.0/IDevicesFactory.h>
 #include <android/hardware/audio/4.0/IDevicesFactory.h>
 #include <android/hardware/audio/5.0/IDevicesFactory.h>
+#include <android/hardware/audio/6.0/IDevicesFactory.h>
 #include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
 #include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
 #include <android/hardware/audio/effect/5.0/IEffectsFactory.h>
+#include <android/hardware/audio/effect/6.0/IEffectsFactory.h>
 #include <android/hardware/bluetooth/a2dp/1.0/IBluetoothAudioOffload.h>
 #include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioProvidersFactory.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
@@ -36,6 +38,15 @@
 using namespace android::hardware;
 using android::OK;
 
+/** Try to register the provided factories in the provided order.
+ *  If any registers successfully, do not register any other and return true.
+ *  If all fail, return false.
+ */
+template <class... Factories>
+bool registerPassthroughServiceImplementations() {
+    return ((registerPassthroughServiceImplementation<Factories>() != OK) && ...);
+}
+
 int main(int /* argc */, char* /* argv */ []) {
     ::android::ProcessState::initWithDriver("/dev/vndbinder");
     // start a threadpool for vndbinder interactions
@@ -50,30 +61,36 @@
     }
     configureRpcThreadpool(16, true /*callerWillJoin*/);
 
-    bool fail = registerPassthroughServiceImplementation<audio::V5_0::IDevicesFactory>() != OK &&
-                registerPassthroughServiceImplementation<audio::V4_0::IDevicesFactory>() != OK &&
-                registerPassthroughServiceImplementation<audio::V2_0::IDevicesFactory>() != OK;
-    LOG_ALWAYS_FATAL_IF(fail, "Could not register audio core API 2, 4 nor 5");
+    // Keep versions on a separate line for easier parsing
+    // clang-format off
+    LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
+                                audio::V6_0::IDevicesFactory,
+                                audio::V5_0::IDevicesFactory,
+                                audio::V4_0::IDevicesFactory,
+                                audio::V2_0::IDevicesFactory>()),
+                        "Could not register audio core API");
 
-    fail = registerPassthroughServiceImplementation<audio::effect::V5_0::IEffectsFactory>() != OK &&
-           registerPassthroughServiceImplementation<audio::effect::V4_0::IEffectsFactory>() != OK &&
-           registerPassthroughServiceImplementation<audio::effect::V2_0::IEffectsFactory>() != OK,
-    LOG_ALWAYS_FATAL_IF(fail, "Could not register audio effect API 2, 4 nor 5");
+    LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<
+                                audio::effect::V6_0::IEffectsFactory,
+                                audio::effect::V5_0::IEffectsFactory,
+                                audio::effect::V4_0::IEffectsFactory,
+                                audio::effect::V2_0::IEffectsFactory>()),
+                        "Could not register audio effect API");
+    // clang-format on
 
-    fail = registerPassthroughServiceImplementation<soundtrigger::V2_2::ISoundTriggerHw>() != OK &&
-           registerPassthroughServiceImplementation<soundtrigger::V2_1::ISoundTriggerHw>() != OK &&
-           registerPassthroughServiceImplementation<soundtrigger::V2_0::ISoundTriggerHw>() != OK,
-    ALOGW_IF(fail, "Could not register soundtrigger API 2.0, 2.1 nor 2.2");
+    ALOGW_IF((registerPassthroughServiceImplementations<soundtrigger::V2_2::ISoundTriggerHw,
+                                                        soundtrigger::V2_1::ISoundTriggerHw,
+                                                        soundtrigger::V2_0::ISoundTriggerHw>()),
+             "Could not register soundtrigger API");
 
-    fail = registerPassthroughServiceImplementation<
-                   bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>() != OK;
-    ALOGW_IF(fail, "Could not register Bluetooth Audio API 2.0");
+    ALOGW_IF(registerPassthroughServiceImplementations<
+                     bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>(),
+             "Could not register Bluetooth audio API");
 
     // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
-    fail =
-        registerPassthroughServiceImplementation<bluetooth::a2dp::V1_0::IBluetoothAudioOffload>() !=
-        OK;
-    ALOGW_IF(fail, "Could not register Bluetooth audio offload 1.0");
+    ALOGW_IF(registerPassthroughServiceImplementations<
+                     bluetooth::a2dp::V1_0::IBluetoothAudioOffload>(),
+             "Could not register Bluetooth audio offload API");
 
     joinRpcThreadpool();
 }
diff --git a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
index 0e416f3..2b240ce 100644
--- a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
+++ b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
@@ -20,9 +20,6 @@
 #include <functional>
 #include <list>
 
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <gtest/gtest.h>
-
 namespace android {
 namespace hardware {
 namespace audio {
@@ -34,18 +31,20 @@
  * Avoid destroying static objects after main return.
  * Post main return destruction leads to incorrect gtest timing measurements as
  * well as harder debuging if anything goes wrong during destruction. */
-class Environment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
+class EnvironmentTearDown {
+  public:
     using TearDownFunc = std::function<void()>;
     void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_front(std::move(tearDown)); }
 
-   private:
-    void HidlTearDown() override {
+  protected:
+    void executeAllTearDowns() {
         // Call the tear downs in reverse order of insertion
         for (auto& tearDown : tearDowns) {
             tearDown();
         }
     }
+
+  private:
     std::list<TearDownFunc> tearDowns;
 };
 
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
index 000ce18..b8b7fee 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -19,12 +19,14 @@
     export_include_dirs: ["include"],
 
     shared_libs: [
+        "libaudiofoundation",
         "libbase",
         "libcutils",
         "libfmq",
         "libhardware",
         "libhidlbase",
         "liblog",
+        "libmedia_helper",
         "libutils",
         "android.hardware.audio.common-util",
     ],
@@ -36,22 +38,16 @@
         "libhardware_headers",
         "libmedia_headers",
     ],
-
-    whole_static_libs: [
-        "libmedia_helper",
-    ],
 }
 
 cc_library_shared {
     name: "android.hardware.audio@2.0-impl",
     defaults: ["android.hardware.audio-impl_default"],
-
     shared_libs: [
         "android.hardware.audio@2.0",
         "android.hardware.audio.common@2.0",
         "android.hardware.audio.common@2.0-util",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=2",
         "-DMINOR_VERSION=0",
@@ -68,7 +64,6 @@
         "android.hardware.audio.common@4.0",
         "android.hardware.audio.common@4.0-util",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=4",
         "-DMINOR_VERSION=0",
@@ -79,16 +74,29 @@
 cc_library_shared {
     name: "android.hardware.audio@5.0-impl",
     defaults: ["android.hardware.audio-impl_default"],
-
     shared_libs: [
         "android.hardware.audio@5.0",
         "android.hardware.audio.common@5.0",
         "android.hardware.audio.common@5.0-util",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=5",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
     ]
 }
+
+cc_library_shared {
+    name: "android.hardware.audio@6.0-impl",
+    defaults: ["android.hardware.audio-impl_default"],
+    shared_libs: [
+        "android.hardware.audio@6.0",
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.common@6.0-util",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp
index e62f6d3..2a4ef6d 100644
--- a/audio/core/all-versions/default/Stream.cpp
+++ b/audio/core/all-versions/default/Stream.cpp
@@ -26,9 +26,8 @@
 #include <android/log.h>
 #include <hardware/audio.h>
 #include <hardware/audio_effect.h>
+#include <media/AudioContainers.h>
 #include <media/TypeConverter.h>
-#include <utils/SortedVector.h>
-#include <utils/Vector.h>
 
 namespace android {
 namespace hardware {
@@ -100,11 +99,11 @@
     Result result =
         getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue, context);
     hidl_vec<uint32_t> sampleRates;
-    SortedVector<uint32_t> halSampleRates;
+    SampleRateSet halSampleRates;
     if (result == Result::OK) {
         halSampleRates =
             samplingRatesFromString(halListValue.string(), AudioParameter::valueListSeparator);
-        sampleRates.setToExternal(halSampleRates.editArray(), halSampleRates.size());
+        sampleRates = hidl_vec<uint32_t>(halSampleRates.begin(), halSampleRates.end());
         // Legacy get_parameter does not return a status_t, thus can not advertise of failure.
         // Note that this method must succeed (non empty list) if the format is supported.
         if (sampleRates.size() == 0) {
@@ -126,13 +125,14 @@
     String8 halListValue;
     Result result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue, context);
     hidl_vec<AudioChannelBitfield> channelMasks;
-    SortedVector<audio_channel_mask_t> halChannelMasks;
+    ChannelMaskSet halChannelMasks;
     if (result == Result::OK) {
         halChannelMasks =
             channelMasksFromString(halListValue.string(), AudioParameter::valueListSeparator);
         channelMasks.resize(halChannelMasks.size());
-        for (size_t i = 0; i < halChannelMasks.size(); ++i) {
-            channelMasks[i] = AudioChannelBitfield(halChannelMasks[i]);
+        size_t i = 0;
+        for (auto channelMask : halChannelMasks) {
+            channelMasks[i++] = AudioChannelBitfield(channelMask);
         }
         // Legacy get_parameter does not return a status_t, thus can not advertise of failure.
         // Note that this method must succeed (non empty list) if the format is supported.
@@ -168,7 +168,7 @@
     String8 halListValue;
     Result result = getParam(AudioParameter::keyStreamSupportedFormats, &halListValue);
     hidl_vec<AudioFormat> formats;
-    Vector<audio_format_t> halFormats;
+    FormatVector halFormats;
     if (result == Result::OK) {
         halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator);
         formats.resize(halFormats.size());
diff --git a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
index 7906bf1..c189464 100644
--- a/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/2.0/AudioPrimaryHidlHalTest.cpp
@@ -60,19 +60,20 @@
                "deconnection",
                testConnectedState(stream.get()))
 
-TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync()));
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail",
+               ASSERT_IS_OK(getDevice()->getHwAvSync()));
 
-TEST_F(AudioPrimaryHidlTest, setMode) {
+TEST_P(AudioPrimaryHidlTest, setMode) {
     doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
     // Test Invalid values
     for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) {
         SCOPED_TRACE("mode=" + toString(mode));
-        ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode));
+        ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(mode));
     }
     // Test valid values
     for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
                            AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
         SCOPED_TRACE("mode=" + toString(mode));
-        ASSERT_OK(device->setMode(mode));
+        ASSERT_OK(getDevice()->setMode(mode));
     }
 }
diff --git a/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h
new file mode 100644
index 0000000..6373e39
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/2.0/EnvironmentTearDown.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
+#define ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+
+#include "utility/EnvironmentTearDown.h"
+
+class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown,
+                    public ::testing::VtsHalHidlTargetTestEnvBase {
+  private:
+    void HidlTearDown() override {
+        executeAllTearDowns();
+        VtsHalHidlTargetTestEnvBase::HidlTearDown();
+    }
+};
+
+#endif  // ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index 15be3bf..cd93643 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -16,28 +16,18 @@
 
 #include "AudioPrimaryHidlHalTest.h"
 
-static void waitForDeviceDestruction() {
-    // FIXME: there is no way to know when the remote IDevice is being destroyed
-    //        Binder does not support testing if an object is alive, thus
-    //        wait for 100ms to let the binder destruction propagates and
-    //        the remote device has the time to be destroyed.
-    //        flushCommand makes sure all local command are sent, thus should reduce
-    //        the latency between local and remote destruction.
-    IPCThreadState::self()->flushCommands();
-    usleep(100 * 1000);
-}
-
-TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
+TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
     doc::test("Calling openDevice(\"primary\") should return the primary device.");
+    if (getDeviceName() != DeviceManager::kPrimaryDevice) {
+        GTEST_SKIP() << "No primary device on this factory";  // returns
+    }
+
     struct WaitExecutor {
-        ~WaitExecutor() { waitForDeviceDestruction(); }
+        ~WaitExecutor() { DeviceManager::waitForInstanceDestruction(); }
     } waitExecutor;  // Make sure we wait for the device destruction on exiting from the test.
     Result result;
     sp<IDevice> baseDevice;
-    ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
-    if (result != Result::OK && isPrimaryDeviceOptional()) {
-        GTEST_SKIP() << "No primary device on this factory";  // returns
-    }
+    ASSERT_OK(getDevicesFactory()->openDevice("primary", returnIn(result, baseDevice)));
     ASSERT_OK(result);
     ASSERT_TRUE(baseDevice != nullptr);
 
@@ -50,10 +40,13 @@
 /////////////////////////// get(Active)Microphones ///////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) {
+TEST_P(AudioHidlDeviceTest, GetMicrophonesTest) {
     doc::test("Make sure getMicrophones always succeeds");
     hidl_vec<MicrophoneInfo> microphones;
-    ASSERT_OK(device->getMicrophones(returnIn(res, microphones)));
+    ASSERT_OK(getDevice()->getMicrophones(returnIn(res, microphones)));
+    if (res == Result::NOT_SUPPORTED) {
+        GTEST_SKIP() << "getMicrophones is not supported";  // returns
+    }
     ASSERT_OK(res);
     if (microphones.size() > 0) {
         // When there is microphone on the phone, try to open an input stream
@@ -75,15 +68,15 @@
             }
             sp<IStreamIn> stream;
             AudioConfig suggestedConfig{};
-            ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, config, flags,
-                                              initMetadata,
-                                              returnIn(res, stream, suggestedConfig)));
+            ASSERT_OK(getDevice()->openInputStream(ioHandle, microphone.deviceAddress, config,
+                                                   flags, initMetadata,
+                                                   returnIn(res, stream, suggestedConfig)));
             if (res != Result::OK) {
                 ASSERT_TRUE(stream == nullptr);
                 AudioConfig suggestedConfigRetry{};
-                ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress,
-                                                  suggestedConfig, flags, initMetadata,
-                                                  returnIn(res, stream, suggestedConfigRetry)));
+                ASSERT_OK(getDevice()->openInputStream(
+                        ioHandle, microphone.deviceAddress, suggestedConfig, flags, initMetadata,
+                        returnIn(res, stream, suggestedConfigRetry)));
             }
             ASSERT_OK(res);
             hidl_vec<MicrophoneInfo> activeMicrophones;
@@ -131,7 +124,7 @@
     }
 }
 
-TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
+TEST_P(AudioHidlDeviceTest, SetConnectedState) {
     doc::test("Check that the HAL can be notified of device connection and deconnection");
     using AD = AudioDevice;
     for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
@@ -140,7 +133,7 @@
             SCOPED_TRACE("state=" + ::testing::PrintToString(state));
             DeviceAddress address = {};
             address.device = deviceType;
-            auto ret = device->setConnectedState(address, state);
+            auto ret = getDevice()->setConnectedState(address, state);
             ASSERT_TRUE(ret.isOk());
             if (ret == Result::NOT_SUPPORTED) {
                 doc::partialTest("setConnectedState is not supported");
@@ -153,9 +146,7 @@
     // Because there is no way of knowing if the devices were connected before
     // calling setConnectedState, there is no way to restore the HAL to its
     // initial state. To workaround this, destroy the HAL at the end of this test.
-    device.clear();
-    waitForDeviceDestruction();
-    ASSERT_NO_FATAL_FAILURE(initPrimaryDevice());
+    ASSERT_TRUE(resetDevice());
 }
 
 static void testGetDevices(IStream* stream, AudioDevice expectedDevice) {
@@ -199,7 +190,7 @@
     }
     ASSERT_OK(res);
 }
-TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(device.get()));
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(getDevice().get()));
 
 TEST_P(InputStreamTest, updateSinkMetadata) {
     doc::test("The HAL should not crash on metadata change");
@@ -259,58 +250,58 @@
     ASSERT_OK(stream->updateSourceMetadata(initMetadata));
 }
 
-TEST_F(AudioPrimaryHidlTest, setMode) {
+TEST_P(AudioPrimaryHidlTest, setMode) {
     doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
     // Test Invalid values
     for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) {
-        ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode)))
-            << "mode=" << mode;
+        ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
+                << "mode=" << mode;
     }
     // Test valid values
     for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
                            AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
-        ASSERT_OK(device->setMode(mode)) << "mode=" << toString(mode);
+        ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
     }
 }
 
-TEST_F(AudioPrimaryHidlTest, setBtHfpSampleRate) {
+TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) {
     doc::test(
         "Make sure setBtHfpSampleRate either succeeds or "
         "indicates that it is not supported at all, or that the provided value is invalid");
     for (auto samplingRate : {8000, 16000, 22050, 24000}) {
-        ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, device->setBtHfpSampleRate(samplingRate));
+        ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setBtHfpSampleRate(samplingRate));
     }
 }
 
-TEST_F(AudioPrimaryHidlTest, setBtHfpVolume) {
+TEST_P(AudioPrimaryHidlTest, setBtHfpVolume) {
     doc::test(
         "Make sure setBtHfpVolume is either not supported or "
         "only succeed if volume is in [0,1]");
-    auto ret = device->setBtHfpVolume(0.0);
+    auto ret = getDevice()->setBtHfpVolume(0.0);
     ASSERT_TRUE(ret.isOk());
     if (ret == Result::NOT_SUPPORTED) {
         doc::partialTest("setBtHfpVolume is not supported");
         return;
     }
-    testUnitaryGain([](float volume) { return device->setBtHfpVolume(volume); });
+    testUnitaryGain([this](float volume) { return getDevice()->setBtHfpVolume(volume); });
 }
 
-TEST_F(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) {
+TEST_P(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) {
     doc::test(
         "Make sure setBtScoHeadsetDebugName either succeeds or "
         "indicates that it is not supported");
-    ASSERT_RESULT(okOrNotSupported, device->setBtScoHeadsetDebugName("test"));
+    ASSERT_RESULT(okOrNotSupported, getDevice()->setBtScoHeadsetDebugName("test"));
 }
 
-TEST_F(AudioPrimaryHidlTest, updateRotation) {
+TEST_P(AudioPrimaryHidlTest, updateRotation) {
     doc::test("Check that the hal can receive the current rotation");
     for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180,
                               Rotation::DEG_270, Rotation::DEG_0}) {
-        ASSERT_RESULT(okOrNotSupported, device->updateRotation(rotation));
+        ASSERT_RESULT(okOrNotSupported, getDevice()->updateRotation(rotation));
     }
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) {
     doc::test("Query and set the BT HFP state");
     testAccessors<OPTIONAL>("BtHfpEnabled", Initial{false, OPTIONAL}, {true},
                             &IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled);
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
new file mode 100644
index 0000000..937de0a
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// pull in all the <= 5.0 tests
+#include "5.0/AudioPrimaryHidlHalTest.cpp"
+
+const std::vector<DeviceParameter>& getDeviceParametersForFactoryTests() {
+    static std::vector<DeviceParameter> parameters = [] {
+        std::vector<DeviceParameter> result;
+        const auto factories =
+                ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor);
+        for (const auto& factoryName : factories) {
+            result.emplace_back(factoryName,
+                                DeviceManager::getInstance().getPrimary(factoryName) != nullptr
+                                        ? DeviceManager::kPrimaryDevice
+                                        : "");
+        }
+        return result;
+    }();
+    return parameters;
+}
+
+const std::vector<DeviceParameter>& getDeviceParametersForPrimaryDeviceTests() {
+    static std::vector<DeviceParameter> parameters = [] {
+        std::vector<DeviceParameter> result;
+        const auto primary = std::find_if(
+                getDeviceParameters().begin(), getDeviceParameters().end(), [](const auto& elem) {
+                    return std::get<PARAM_DEVICE_NAME>(elem) == DeviceManager::kPrimaryDevice;
+                });
+        if (primary != getDeviceParameters().end()) result.push_back(*primary);
+        return result;
+    }();
+    return parameters;
+}
+
+const std::vector<DeviceParameter>& getDeviceParameters() {
+    static std::vector<DeviceParameter> parameters = [] {
+        std::vector<DeviceParameter> result;
+        const auto factories =
+                ::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor);
+        const auto devices = getCachedPolicyConfig().getModulesWithDevicesNames();
+        result.reserve(devices.size());
+        for (const auto& factoryName : factories) {
+            for (const auto& deviceName : devices) {
+                if (DeviceManager::getInstance().get(factoryName, deviceName) != nullptr) {
+                    result.emplace_back(factoryName, deviceName);
+                }
+            }
+        }
+        return result;
+    }();
+    return parameters;
+}
diff --git a/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h
new file mode 100644
index 0000000..593759f
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/6.0/EnvironmentTearDown.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
+#define ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
+
+#include <gtest/gtest.h>
+
+#include "utility/EnvironmentTearDown.h"
+
+class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown,
+                    public ::testing::Environment {
+  public:
+    void init(int* /*argc*/, char** /*argv*/) {}  // emulate VtsHalHidlTargetTestEnvBase
+  private:
+    void TearDown() override { executeAllTearDowns(); }
+};
+
+// FIXME: Will be removed while making getDeviceParameters to use the config
+static constexpr const char* kDefaultServiceName = "default";
+
+#endif  // ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 88fdb5a..1818e36 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -19,11 +19,13 @@
     defaults: ["VtsHalTargetTestDefaults"],
     static_libs: [
         "android.hardware.audio.common.test.utility",
+        "libaudiofoundation",
         "libaudiopolicycomponents",
         "libmedia_helper",
         "libxml2",
     ],
     shared_libs: [
+        "libbinder",
         "libfmq",
     ],
     header_libs: [
@@ -82,3 +84,20 @@
         "-include common/all-versions/VersionMacro.h",
     ]
 }
+
+cc_test {
+    name: "VtsHalAudioV6_0TargetTest",
+    defaults: ["VtsHalAudioTargetTest_defaults"],
+    srcs: [
+        "6.0/AudioPrimaryHidlHalTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.audio@6.0",
+        "android.hardware.audio.common@6.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 6c51c1b..7bdc5e1 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -23,6 +23,8 @@
 #include <initializer_list>
 #include <limits>
 #include <list>
+#include <map>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -31,7 +33,9 @@
 
 #include <hwbinder/IPCThreadState.h>
 
+#if MAJOR_VERSION <= 5
 #include <VtsHalHidlTargetTestBase.h>
+#endif
 
 #include <android-base/logging.h>
 
@@ -44,16 +48,25 @@
 #include <Serializer.h>
 #include <fmq/EventFlag.h>
 #include <fmq/MessageQueue.h>
+#if MAJOR_VERSION >= 6
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#endif
 
 #include <common/all-versions/VersionUtils.h>
 
 #include "utility/AssertOk.h"
 #include "utility/Documentation.h"
-#include "utility/EnvironmentTearDown.h"
 #include "utility/PrettyPrintAudioTypes.h"
 #include "utility/ReturnIn.h"
 #include "utility/ValidateXml.h"
 
+#if MAJOR_VERSION <= 5
+#include "2.0/EnvironmentTearDown.h"
+#elif MAJOR_VERSION >= 6
+#include "6.0/EnvironmentTearDown.h"
+#endif
+
 /** Provide version specific functions that are used in the generic tests */
 #if MAJOR_VERSION == 2
 #include "2.0/AudioPrimaryHidlHalUtils.h"
@@ -105,14 +118,43 @@
 
 class AudioHidlTestEnvironment : public ::Environment {
    public:
-    virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+#if MAJOR_VERSION <= 5
+     void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+#endif
 };
 
 // Instance to register global tearDown
 static AudioHidlTestEnvironment* environment;
 
-class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
+#define AUDIO_PRIMARY_HIDL_HAL_TEST
+#include "DeviceManager.h"
+
+#if MAJOR_VERSION <= 5
+using HidlTestBase = ::testing::VtsHalHidlTargetTestBase;
+#elif MAJOR_VERSION >= 6
+using HidlTestBase = ::testing::Test;
+#endif
+
+class HidlTest : public HidlTestBase {
+  public:
+    virtual ~HidlTest() = default;
+
+  protected:
+    // Factory and device name getters to be overridden in subclasses.
+    virtual const std::string& getFactoryName() const = 0;
+    virtual const std::string& getDeviceName() const = 0;
+
+    sp<IDevicesFactory> getDevicesFactory() const {
+        return DevicesFactoryManager::getInstance().get(getFactoryName());
+    }
+    sp<IDevice> getDevice() const {
+        return DeviceManager::getInstance().get(getFactoryName(), getDeviceName());
+    }
+    bool resetDevice() const {
+        return DeviceManager::getInstance().reset(getFactoryName(), getDeviceName());
+    }
+    bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); }
+
     // Convenient member to store results
     Result res;
 };
@@ -158,7 +200,25 @@
         }
         mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this);
         if (mStatus == OK) {
-            mPrimaryModule = getHwModules().getModuleFromName("primary");
+            mPrimaryModule = getHwModules().getModuleFromName(DeviceManager::kPrimaryDevice);
+            // Available devices are not 'attached' to modules at this moment.
+            // Need to go over available devices and find their module.
+            for (const auto& device : availableOutputDevices) {
+                for (const auto& module : hwModules) {
+                    if (module->getDeclaredDevices().indexOf(device) >= 0) {
+                        mModulesWithDevicesNames.insert(module->getName());
+                        break;
+                    }
+                }
+            }
+            for (const auto& device : availableInputDevices) {
+                for (const auto& module : hwModules) {
+                    if (module->getDeclaredDevices().indexOf(device) >= 0) {
+                        mModulesWithDevicesNames.insert(module->getName());
+                        break;
+                    }
+                }
+            }
         }
     }
     status_t getStatus() const { return mStatus; }
@@ -172,11 +232,15 @@
     }
     const std::string& getFilePath() const { return mFilePath; }
     sp<const HwModule> getPrimaryModule() const { return mPrimaryModule; }
+    const std::set<std::string>& getModulesWithDevicesNames() const {
+        return mModulesWithDevicesNames;
+    }
 
    private:
     status_t mStatus = NO_INIT;
     std::string mFilePath;
     sp<HwModule> mPrimaryModule = nullptr;
+    std::set<std::string> mModulesWithDevicesNames;
 };
 
 // Cached policy config after parsing for faster test startup
@@ -189,61 +253,113 @@
     return *policyConfig;
 }
 
-class AudioPolicyConfigTest : public HidlTest {
-   public:
+class AudioPolicyConfigTest : public HidlTestBase {
+  public:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp());  // setup base
-
+        ASSERT_NO_FATAL_FAILURE(HidlTestBase::SetUp());  // setup base
         auto& policyConfig = getCachedPolicyConfig();
         ASSERT_EQ(0, policyConfig.getStatus()) << policyConfig.getError();
-
-        mPrimaryConfig = policyConfig.getPrimaryModule();
-        ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: "
-                                    << policyConfig.getFilePath();
     }
-    sp<const HwModule> mPrimaryConfig = nullptr;
 };
 
 TEST_F(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) {
     doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)");
 }
 
+TEST_F(AudioPolicyConfigTest, HasPrimaryModule) {
+    auto& policyConfig = getCachedPolicyConfig();
+    ASSERT_TRUE(policyConfig.getPrimaryModule() != nullptr)
+            << "Could not find primary module in configuration file: "
+            << policyConfig.getFilePath();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////// Test parameter types and definitions ////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+enum { PARAM_FACTORY_NAME, PARAM_DEVICE_NAME };
+using DeviceParameter = std::tuple<std::string, std::string>;
+
+static inline std::string DeviceParameterToString(
+        const ::testing::TestParamInfo<DeviceParameter>& info) {
+    const auto& deviceName = std::get<PARAM_DEVICE_NAME>(info.param);
+#if MAJOR_VERSION <= 5
+    return !deviceName.empty() ? deviceName : std::to_string(info.index);
+#elif MAJOR_VERSION >= 6
+    const auto factoryName =
+            ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo<std::string>{
+                    std::get<PARAM_FACTORY_NAME>(info.param), info.index});
+    return !deviceName.empty() ? factoryName + "_" + deviceName : factoryName;
+#endif
+}
+
+#if MAJOR_VERSION <= 5
+// For V2..5 the factory is looked up using the instance name passed
+// in the environment, only one factory is returned. This is because the VTS
+// framework will call the test for each instance. Only the primary device of
+// the default service factory can be tested.
+
+// Return a pair of <"default", "primary"> or <[non-default name], "">
+// This is used to parametrize device factory tests.
+// The device name is used to indicate whether IPrimaryDevice is required.
+const std::vector<DeviceParameter>& getDeviceParametersForFactoryTests() {
+    static std::vector<DeviceParameter> parameters = {
+            {environment->getServiceName<IDevicesFactory>(),
+             environment->getServiceName<IDevicesFactory>() == kDefaultServiceName
+                     ? DeviceManager::kPrimaryDevice
+                     : ""}};
+    return parameters;
+}
+// Return a pair of <"default", "primary"> or nothing.
+// This is used to parametrize primary device tests.
+const std::vector<DeviceParameter>& getDeviceParametersForPrimaryDeviceTests() {
+    static std::vector<DeviceParameter> parameters =
+            !std::get<PARAM_DEVICE_NAME>(*getDeviceParametersForFactoryTests().begin()).empty()
+                    ? getDeviceParametersForFactoryTests()
+                    : std::vector<DeviceParameter>{};
+    return parameters;
+}
+// In V2..5 device tests must only test the primary device.
+// No device tests are executed for non-primary devices.
+const std::vector<DeviceParameter>& getDeviceParameters() {
+    return getDeviceParametersForPrimaryDeviceTests();
+}
+#elif MAJOR_VERSION >= 6
+// For V6 and above these functions are implemented in 6.0/AudioPrimaryHidlHalTest.cpp
+const std::vector<DeviceParameter>& getDeviceParametersForFactoryTests();
+const std::vector<DeviceParameter>& getDeviceParametersForPrimaryDeviceTests();
+const std::vector<DeviceParameter>& getDeviceParameters();
+#endif
+
+class AudioHidlTestWithDeviceParameter : public HidlTest,
+                                         public ::testing::WithParamInterface<DeviceParameter> {
+  protected:
+    const std::string& getFactoryName() const override {
+        return std::get<PARAM_FACTORY_NAME>(GetParam());
+    }
+    const std::string& getDeviceName() const override {
+        return std::get<PARAM_DEVICE_NAME>(GetParam());
+    }
+};
+
 //////////////////////////////////////////////////////////////////////////////
 ////////////////////// getService audio_devices_factory //////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-// Test all audio devices
-class AudioHidlTest : public AudioPolicyConfigTest {
-   public:
-     static void SetUpTestSuite() {
-         devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(
-                 environment->getServiceName<IDevicesFactory>());
-     }
-
-     static void TearDownTestSuite() { devicesFactory.clear(); }
-
-     void SetUp() override {
-         ASSERT_NO_FATAL_FAILURE(AudioPolicyConfigTest::SetUp());  // setup base
-         // Failures during SetUpTestSuite do not cause test termination.
-         ASSERT_TRUE(devicesFactory != nullptr);
-     }
-
-   protected:
-    // Cache the devicesFactory retrieval to speed up each test by ~0.5s
-    static sp<IDevicesFactory> devicesFactory;
-
-    static bool isPrimaryDeviceOptional() {
-        // It's OK not to have "primary" device on non-default audio HAL service.
-        return environment->getServiceName<IDevicesFactory>() != kDefaultServiceName;
+// Test audio devices factory
+class AudioHidlTest : public AudioHidlTestWithDeviceParameter {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceParameter::SetUp());  // setup base
+        ASSERT_TRUE(getDevicesFactory() != nullptr);
     }
 };
-sp<IDevicesFactory> AudioHidlTest::devicesFactory;
 
-TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
+TEST_P(AudioHidlTest, GetAudioDevicesFactoryService) {
     doc::test("Test the getService");
 }
 
-TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
+TEST_P(AudioHidlTest, OpenDeviceInvalidParameter) {
     doc::test("Test passing an invalid parameter to openDevice");
     Result result;
     sp<IDevice> device;
@@ -252,82 +368,80 @@
 #elif MAJOR_VERSION >= 4
     auto invalidDevice = "Non existing device";
 #endif
-    ASSERT_OK(devicesFactory->openDevice(invalidDevice, returnIn(result, device)));
+    ASSERT_OK(getDevicesFactory()->openDevice(invalidDevice, returnIn(result, device)));
     ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
     ASSERT_TRUE(device == nullptr);
 }
 
+INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest,
+                        ::testing::ValuesIn(getDeviceParametersForFactoryTests()),
+                        &DeviceParameterToString);
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// openDevice ///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Test all audio devices
+class AudioHidlDeviceTest : public AudioHidlTest {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp());  // setup base
+        ASSERT_TRUE(getDevice() != nullptr);
+    }
+};
+
+TEST_P(AudioHidlDeviceTest, OpenDevice) {
+    doc::test("Test openDevice (called during setup)");
+}
+
+TEST_P(AudioHidlDeviceTest, Init) {
+    doc::test("Test that the audio hal initialized correctly");
+    ASSERT_OK(getDevice()->initCheck());
+}
+
+INSTANTIATE_TEST_CASE_P(AudioHidlDevice, AudioHidlDeviceTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////////////// openDevice primary ///////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
 // Test the primary device
-class AudioPrimaryHidlTest : public AudioHidlTest {
-   public:
-     static void SetUpTestSuite() {
-         ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUpTestSuite());
-         ASSERT_NO_FATAL_FAILURE(initPrimaryDevice());
-     }
-
-     static void TearDownTestSuite() {
-         device.clear();
-         AudioHidlTest::TearDownTestSuite();
-     }
-
+class AudioPrimaryHidlTest : public AudioHidlDeviceTest {
+  public:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp());  // setup base
-        if (device == nullptr && isPrimaryDeviceOptional()) {
-            GTEST_SKIP() << "No primary device on this factory";
-        }
-        ASSERT_TRUE(device != nullptr);
+        ASSERT_NO_FATAL_FAILURE(AudioHidlDeviceTest::SetUp());  // setup base
+        ASSERT_TRUE(getDevice() != nullptr);
     }
 
-   protected:
-    // Cache the device opening to speed up each test by ~0.5s
-    static sp<IPrimaryDevice> device;
-
-    static void initPrimaryDevice() {
-        // Failures during test suite set up do not cause test termination.
-        ASSERT_TRUE(devicesFactory != nullptr);
-        Result result;
-#if MAJOR_VERSION == 2
-        sp<IDevice> baseDevice;
-        ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
-                                             returnIn(result, baseDevice)));
-        ASSERT_OK(result);
-        ASSERT_TRUE(baseDevice != nullptr);
-
-        device = IPrimaryDevice::castFrom(baseDevice);
-#elif MAJOR_VERSION >= 4
-        ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device)));
-        ASSERT_OK(result);
-#endif
+  protected:
+    sp<IPrimaryDevice> getDevice() const {
+        return DeviceManager::getInstance().getPrimary(getFactoryName());
     }
 };
-sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
 
-TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
-    doc::test("Test the openDevice (called during setup)");
+TEST_P(AudioPrimaryHidlTest, OpenPrimaryDevice) {
+    doc::test("Test openPrimaryDevice (called during setup)");
 }
 
-TEST_F(AudioPrimaryHidlTest, Init) {
-    doc::test("Test that the audio primary hal initialized correctly");
-    ASSERT_OK(device->initCheck());
-}
+INSTANTIATE_TEST_CASE_P(AudioPrimaryHidl, AudioPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                        &DeviceParameterToString);
 
 //////////////////////////////////////////////////////////////////////////////
 ///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-template <class Property>
-class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
-   protected:
+template <class Property, class BaseTestClass = AudioHidlDeviceTest>
+class AccessorHidlTest : public BaseTestClass {
+  protected:
     enum Optionality { REQUIRED, OPTIONAL };
     struct Initial {  // Initial property value
         Initial(Property value, Optionality check = REQUIRED) : value(value), check(check) {}
         Property value;
         Optionality check;  // If this initial value should be checked
     };
+    using BaseTestClass::res;
     /** Test a property getter and setter.
      *  The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL.
      */
@@ -339,7 +453,7 @@
                                       optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
 
         Property initialValue = expectedInitial.value;
-        ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+        ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, initialValue)));
         ASSERT_RESULT(expectedResults, res);
         if (res == Result::OK && expectedInitial.check == REQUIRED) {
             EXPECT_EQ(expectedInitial.value, initialValue);
@@ -350,7 +464,7 @@
         for (Property setValue : valuesToTest) {
             SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
                          testing::PrintToString(setValue));
-            auto ret = (device.get()->*setter)(setValue);
+            auto ret = (BaseTestClass::getDevice().get()->*setter)(setValue);
             ASSERT_RESULT(expectedResults, ret);
             if (ret == Result::NOT_SUPPORTED) {
                 doc::partialTest(propertyName + " setter is not supported");
@@ -358,7 +472,7 @@
             }
             Property getValue;
             // Make sure the getter returns the same value just set
-            ASSERT_OK((device.get()->*getter)(returnIn(res, getValue)));
+            ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, getValue)));
             ASSERT_RESULT(expectedResults, res);
             if (res == Result::NOT_SUPPORTED) {
                 doc::partialTest(propertyName + " getter is not supported");
@@ -370,31 +484,40 @@
         for (Property invalidValue : invalidValues) {
             SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
                          testing::PrintToString(invalidValue));
-            EXPECT_RESULT(invalidArgsOrNotSupported, (device.get()->*setter)(invalidValue));
+            EXPECT_RESULT(invalidArgsOrNotSupported,
+                          (BaseTestClass::getDevice().get()->*setter)(invalidValue));
         }
 
         // Restore initial value
-        EXPECT_RESULT(expectedResults, (device.get()->*setter)(initialValue));
+        EXPECT_RESULT(expectedResults, (BaseTestClass::getDevice().get()->*setter)(initialValue));
     }
 };
 
-using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>;
+using BoolAccessorHidlTest = AccessorHidlTest<bool>;
+using BoolAccessorPrimaryHidlTest = AccessorHidlTest<bool, AudioPrimaryHidlTest>;
 
-TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
+TEST_P(BoolAccessorHidlTest, MicMuteTest) {
     doc::test("Check that the mic can be muted and unmuted");
-    testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute);
+    testAccessors<OPTIONAL>("mic mute", Initial{false}, {true}, &IDevice::setMicMute,
+                            &IDevice::getMicMute);
     // TODO: check that the mic is really muted (all sample are 0)
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
+TEST_P(BoolAccessorHidlTest, MasterMuteTest) {
     doc::test("If master mute is supported, try to mute and unmute the master output");
     testAccessors<OPTIONAL>("master mute", Initial{false}, {true}, &IDevice::setMasterMute,
                             &IDevice::getMasterMute);
     // TODO: check that the master volume is really muted
 }
 
-using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
-TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
+INSTANTIATE_TEST_CASE_P(BoolAccessorHidl, BoolAccessorHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                        &DeviceParameterToString);
+
+using FloatAccessorHidlTest = AccessorHidlTest<float>;
+TEST_P(FloatAccessorHidlTest, MasterVolumeTest) {
     doc::test("Test the master volume if supported");
     testAccessors<OPTIONAL>(
         "master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume,
@@ -402,24 +525,31 @@
     // TODO: check that the master volume is really changed
 }
 
+INSTANTIATE_TEST_CASE_P(FloatAccessorHidl, FloatAccessorHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////// AudioPatches ////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
-   protected:
-     bool areAudioPatchesSupported() { return extract(device->supportsAudioPatches()); }
+class AudioPatchHidlTest : public AudioHidlDeviceTest {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioHidlDeviceTest::SetUp());  // setup base
+        if (!areAudioPatchesSupported()) {
+            GTEST_SKIP() << "Audio patches are not supported";
+        }
+    }
 };
 
-TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
+TEST_P(AudioPatchHidlTest, AudioPatches) {
     doc::test("Test if audio patches are supported");
-    if (!areAudioPatchesSupported()) {
-        doc::partialTest("Audio patches are not supported");
-        return;
-    }
     // TODO: test audio patches
 }
 
+INSTANTIATE_TEST_CASE_P(AudioPatchHidl, AudioPatchHidlTest,
+                        ::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
+
 //////////////////////////////////////////////////////////////////////////////
 //////////////// Required and recommended audio format support ///////////////
 // From:
@@ -429,8 +559,7 @@
 /////////// TODO: move to the beginning of the file for easier update ////////
 //////////////////////////////////////////////////////////////////////////////
 
-class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
-   public:
+struct ConfigHelper {
     // for retro compatibility only test the primary device IN_BUILTIN_MIC
     // FIXME: in the next audio HAL version, test all available devices
     static bool primaryHasMic() {
@@ -502,21 +631,48 @@
     }
 };
 
+// Nesting a tuple in another tuple allows to use GTest Combine function to generate
+// all combinations of devices and configs.
+enum { PARAM_DEVICE, PARAM_CONFIG };
+using DeviceConfigParameter = std::tuple<DeviceParameter, AudioConfig>;
+
 /** Generate a test name based on an audio config.
  *
  * As the only parameter changing are channel mask and sample rate,
  * only print those ones in the test name.
  */
-static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) {
-    const AudioConfig& config = info.param;
-    return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" +
+static string DeviceConfigParameterToString(
+        const testing::TestParamInfo<DeviceConfigParameter>& info) {
+    const AudioConfig& config = std::get<PARAM_CONFIG>(info.param);
+    const auto deviceName = DeviceParameterToString(::testing::TestParamInfo<DeviceParameter>{
+            std::get<PARAM_DEVICE>(info.param), info.index});
+    return (deviceName.empty() ? "" : deviceName + "_") + to_string(info.index) + "__" +
+           to_string(config.sampleRateHz) + "_" +
            // "MONO" is more clear than "FRONT_LEFT"
            ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
              config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO))
-                ? "MONO"
-                : ::testing::PrintToString(config.channelMask));
+                    ? "MONO"
+                    : ::testing::PrintToString(config.channelMask));
 }
 
+class AudioHidlTestWithDeviceConfigParameter
+    : public HidlTest,
+      public ::testing::WithParamInterface<DeviceConfigParameter> {
+  protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp());  // setup base
+        ASSERT_TRUE(getDevicesFactory() != nullptr);
+        ASSERT_TRUE(getDevice() != nullptr);
+    }
+    const std::string& getFactoryName() const override {
+        return std::get<PARAM_FACTORY_NAME>(std::get<PARAM_DEVICE>(GetParam()));
+    }
+    const std::string& getDeviceName() const override {
+        return std::get<PARAM_DEVICE_NAME>(std::get<PARAM_DEVICE>(GetParam()));
+    }
+    const AudioConfig& getConfig() const { return std::get<PARAM_CONFIG>(GetParam()); }
+};
+
 //////////////////////////////////////////////////////////////////////////////
 ///////////////////////////// getInputBufferSize /////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
@@ -525,12 +681,11 @@
 // android.hardware.microphone
 //        how to get this value ? is it a property ???
 
-class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest,
-                                      public ::testing::WithParamInterface<AudioConfig> {
-   protected:
+class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParameter {
+  protected:
     void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
         uint64_t bufferSize;
-        ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
+        ASSERT_OK(getDevice()->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
 
         switch (res) {
             case Result::INVALID_ARGUMENTS:
@@ -554,16 +709,20 @@
     doc::test(
         "Input buffer size must be retrievable for a format with required "
         "support.");
-    inputBufferSizeTest(GetParam(), true);
+    inputBufferSizeTest(getConfig(), true);
 }
 INSTANTIATE_TEST_CASE_P(
-    RequiredInputBufferSize, RequiredInputBufferSizeTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
-    &generateTestName);
+        RequiredInputBufferSize, RequiredInputBufferSizeTest,
+        // FIXME: uses primaryHasMic
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 INSTANTIATE_TEST_CASE_P(
-    SupportedInputBufferSize, RequiredInputBufferSizeTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
-    &generateTestName);
+        SupportedInputBufferSize, RequiredInputBufferSizeTest,
+        ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
+                           ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 
 // Test that the recommended capture config are supported or lead to a
 // INVALID_ARGUMENTS return
@@ -572,21 +731,24 @@
     doc::test(
         "Input buffer size should be retrievable for a format with recommended "
         "support.");
-    inputBufferSizeTest(GetParam(), false);
+    inputBufferSizeTest(getConfig(), false);
 }
 INSTANTIATE_TEST_CASE_P(
-    RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
-    &generateTestName);
+        RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
+        // FIXME: uses primaryHasMic
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////////////// setScreenState ///////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, setScreenState) {
+TEST_P(AudioHidlDeviceTest, setScreenState) {
     doc::test("Check that the hal can receive the screen state");
     for (bool turnedOn : {false, true, true, false, false}) {
-        ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn));
+        ASSERT_RESULT(okOrNotSupported, getDevice()->setScreenState(turnedOn));
     }
 }
 
@@ -594,15 +756,16 @@
 //////////////////////////// {get,set}Parameters /////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, getParameters) {
+TEST_P(AudioHidlDeviceTest, getParameters) {
     doc::test("Check that the hal can set and get parameters");
     hidl_vec<ParameterValue> context;
     hidl_vec<hidl_string> keys;
     hidl_vec<ParameterValue> values;
-    ASSERT_OK(Parameters::get(device, keys, returnIn(res, values)));
-    ASSERT_OK(Parameters::set(device, values));
+    ASSERT_OK(Parameters::get(getDevice(), keys, returnIn(res, values)));
+    ASSERT_RESULT(okOrNotSupported, res);
+    ASSERT_RESULT(okOrNotSupported, Parameters::set(getDevice(), values));
     values.resize(0);
-    ASSERT_OK(Parameters::set(device, values));
+    ASSERT_RESULT(okOrNotSupported, Parameters::set(getDevice(), values));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -643,14 +806,14 @@
     EXPECT_EQ(0, close(fds[1])) << errno;
 }
 
-TEST_F(AudioPrimaryHidlTest, DebugDump) {
+TEST_P(AudioHidlDeviceTest, DebugDump) {
     doc::test("Check that the hal can dump its state without error");
-    testDebugDump([](const auto& handle) { return dump(device, handle); });
+    testDebugDump([this](const auto& handle) { return dump(getDevice(), handle); });
 }
 
-TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
+TEST_P(AudioHidlDeviceTest, DebugDumpInvalidArguments) {
     doc::test("Check that the hal dump doesn't crash on invalid arguments");
-    ASSERT_OK(dump(device, hidl_handle()));
+    ASSERT_OK(dump(getDevice(), hidl_handle()));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -658,9 +821,8 @@
 //////////////////////////////////////////////////////////////////////////////
 
 template <class Stream>
-class OpenStreamTest : public AudioConfigPrimaryTest,
-                       public ::testing::WithParamInterface<AudioConfig> {
-   protected:
+class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
+  protected:
     template <class Open>
     void testOpen(Open openStream, const AudioConfig& config) {
         // FIXME: Open a stream without an IOHandle
@@ -701,7 +863,7 @@
         return res;
     }
 
-    void waitForStreamDestruction() {
+    static void waitForStreamDestruction() {
         // FIXME: there is no way to know when the remote IStream is being destroyed
         //        Binder does not support testing if an object is alive, thus
         //        wait for 100ms to let the binder destruction propagates and
@@ -712,12 +874,12 @@
         usleep(100 * 1000);
     }
 
-   private:
+  private:
     void TearDown() override {
         if (open) {
             ASSERT_OK(closeStream());
         }
-        AudioConfigPrimaryTest::TearDown();
+        AudioHidlTestWithDeviceConfigParameter::TearDown();
     }
 
    protected:
@@ -732,20 +894,20 @@
 class OutputStreamTest : public OpenStreamTest<IStreamOut> {
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
-        if (IsSkipped()) return;                           // do not attempt to use 'device'
         address.device = AudioDevice::OUT_DEFAULT;
-        const AudioConfig& config = GetParam();
+        const AudioConfig& config = getConfig();
         // TODO: test all flag combination
         auto flags = mkEnumBitfield(AudioOutputFlag::NONE);
         testOpen(
-            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                [&](AudioIoHandle handle, AudioConfig config, auto cb) {
 #if MAJOR_VERSION == 2
-                return device->openOutputStream(handle, address, config, flags, cb);
+                    return getDevice()->openOutputStream(handle, address, config, flags, cb);
 #elif MAJOR_VERSION >= 4
-                return device->openOutputStream(handle, address, config, flags, initMetadata, cb);
+                    return getDevice()->openOutputStream(handle, address, config, flags,
+                                                         initMetadata, cb);
 #endif
-            },
-            config);
+                },
+                config);
     }
 #if MAJOR_VERSION >= 4
 
@@ -762,35 +924,41 @@
         "recommended config");
     // Open done in SetUp
 }
+// FIXME: Add instantiations for non-primary devices with configs harvested from the APM config file
 INSTANTIATE_TEST_CASE_P(
-    RequiredOutputStreamConfigSupport, OutputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
-    &generateTestName);
+        RequiredOutputStreamConfigSupport, OutputStreamTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig())),
+        &DeviceConfigParameterToString);
 INSTANTIATE_TEST_CASE_P(
-    SupportedOutputStreamConfig, OutputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
-    &generateTestName);
+        SupportedOutputStreamConfig, OutputStreamTest,
+        ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
+                           ::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig())),
+        &DeviceConfigParameterToString);
 
 INSTANTIATE_TEST_CASE_P(
-    RecommendedOutputStreamConfigSupport, OutputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
-    &generateTestName);
+        RecommendedOutputStreamConfigSupport, OutputStreamTest,
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig())),
+        &DeviceConfigParameterToString);
 
 ////////////////////////////// openInputStream //////////////////////////////
 
 class InputStreamTest : public OpenStreamTest<IStreamIn> {
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
-        if (IsSkipped()) return;                           // do not attempt to use 'device'
         address.device = AudioDevice::IN_DEFAULT;
-        const AudioConfig& config = GetParam();
+        const AudioConfig& config = getConfig();
         // TODO: test all supported flags and source
         auto flags = mkEnumBitfield(AudioInputFlag::NONE);
         testOpen(
-            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
-                return device->openInputStream(handle, address, config, flags, initMetadata, cb);
-            },
-            config);
+                [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                    return getDevice()->openInputStream(handle, address, config, flags,
+                                                        initMetadata, cb);
+                },
+                config);
     }
 
    protected:
@@ -808,18 +976,25 @@
     // Open done in setup
 }
 INSTANTIATE_TEST_CASE_P(
-    RequiredInputStreamConfigSupport, InputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
-    &generateTestName);
+        RequiredInputStreamConfigSupport, InputStreamTest,
+        // FIXME: uses primaryHasMic
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 INSTANTIATE_TEST_CASE_P(
-    SupportedInputStreamConfig, InputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
-    &generateTestName);
+        SupportedInputStreamConfig, InputStreamTest,
+        ::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
+                           ::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 
 INSTANTIATE_TEST_CASE_P(
-    RecommendedInputStreamConfigSupport, InputStreamTest,
-    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
-    &generateTestName);
+        RecommendedInputStreamConfigSupport, InputStreamTest,
+        // FIXME: uses primaryHasMic
+        ::testing::Combine(
+                ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                ::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())),
+        &DeviceConfigParameterToString);
 
 //////////////////////////////////////////////////////////////////////////////
 ////////////////////////////// IStream getters ///////////////////////////////
@@ -1332,35 +1507,39 @@
 /////////////////////////////// PrimaryDevice ////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
+TEST_P(AudioPrimaryHidlTest, setVoiceVolume) {
     doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
-    testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); });
+    testUnitaryGain([this](float volume) { return getDevice()->setVoiceVolume(volume); });
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
     doc::test("Query and set the BT SCO NR&EC state");
     testAccessors<OPTIONAL>("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true},
                             &IPrimaryDevice::setBtScoNrecEnabled,
                             &IPrimaryDevice::getBtScoNrecEnabled);
 }
 
-TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
     doc::test("Query and set the SCO whideband state");
     testAccessors<OPTIONAL>("BtScoWideband", Initial{false, OPTIONAL}, {true},
                             &IPrimaryDevice::setBtScoWidebandEnabled,
                             &IPrimaryDevice::getBtScoWidebandEnabled);
 }
 
-using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<IPrimaryDevice::TtyMode>;
-TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
+using TtyModeAccessorPrimaryHidlTest =
+        AccessorHidlTest<IPrimaryDevice::TtyMode, AudioPrimaryHidlTest>;
+TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
     doc::test("Query and set the TTY mode state");
     testAccessors<OPTIONAL>(
         "TTY mode", Initial{IPrimaryDevice::TtyMode::OFF},
         {IPrimaryDevice::TtyMode::HCO, IPrimaryDevice::TtyMode::VCO, IPrimaryDevice::TtyMode::FULL},
         &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
 }
+INSTANTIATE_TEST_CASE_P(TtyModeAccessorPrimaryHidl, TtyModeAccessorPrimaryHidlTest,
+                        ::testing::ValuesIn(getDeviceParametersForPrimaryDeviceTests()),
+                        &DeviceParameterToString);
 
-TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
+TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) {
     doc::test("Query and set the HAC state");
     testAccessors<OPTIONAL>("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled,
                             &IPrimaryDevice::getHacEnabled);
@@ -1372,9 +1551,13 @@
 
 int main(int argc, char** argv) {
     environment = new AudioHidlTestEnvironment;
+    // For V2..5 it's critical to initialize environment before GTest.
+    // The environment parses the service name from the command line,
+    // then it can be used in GTest parameter generators which are
+    // initialized during the call to InitGoogleTest.
+    environment->init(&argc, argv);
     ::testing::AddGlobalTestEnvironment(environment);
     ::testing::InitGoogleTest(&argc, argv);
-    environment->init(&argc, argv);
     int status = RUN_ALL_TESTS();
     return status;
 }
diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h
new file mode 100644
index 0000000..b6e2db0
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/DeviceManager.h
@@ -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.
+ */
+
+// Code in this file uses 'environment'
+#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST
+#error Must be included from AudioPrimaryHidlTest.h
+#endif
+
+template <class Derived, class Key, class Interface>
+class InterfaceManager {
+  public:
+    sp<Interface> get(const Key& name) {
+        auto existing = instances.find(name);
+        if (existing != instances.end()) return existing->second;
+        auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name));
+        if (inserted->second) {
+            environment->registerTearDown([name]() { (void)Derived::getInstance().reset(name); });
+        }
+        return inserted->second;
+    }
+
+    // The test must check that reset was successful. Reset failure means that the test code
+    // is holding a strong reference to the device.
+    bool reset(const Key& name) __attribute__((warn_unused_result)) {
+        auto iter = instances.find(name);
+        if (iter == instances.end()) return true;
+        ::android::wp<Interface> weak = iter->second;
+        instances.erase(iter);
+        if (weak.promote() != nullptr) return false;
+        waitForInstanceDestruction();
+        return true;
+    }
+
+    static void waitForInstanceDestruction() {
+        // FIXME: there is no way to know when the remote IDevice is being destroyed
+        //        Binder does not support testing if an object is alive, thus
+        //        wait for 100ms to let the binder destruction propagates and
+        //        the remote device has the time to be destroyed.
+        //        flushCommand makes sure all local command are sent, thus should reduce
+        //        the latency between local and remote destruction.
+        IPCThreadState::self()->flushCommands();
+        usleep(100 * 1000);
+    }
+
+  protected:
+    std::map<Key, sp<Interface>> instances;
+};
+
+class DevicesFactoryManager
+    : public InterfaceManager<DevicesFactoryManager, std::string, IDevicesFactory> {
+  public:
+    static DevicesFactoryManager& getInstance() {
+        static DevicesFactoryManager instance;
+        return instance;
+    }
+    static sp<IDevicesFactory> createInterfaceInstance(const std::string& name) {
+#if MAJOR_VERSION <= 5
+        return ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(name);
+#elif MAJOR_VERSION >= 6
+        return IDevicesFactory::getService(name);
+#endif
+    }
+};
+
+using FactoryAndDevice = std::tuple<std::string, std::string>;
+class DeviceManager : public InterfaceManager<DeviceManager, FactoryAndDevice, IDevice> {
+  public:
+    static DeviceManager& getInstance() {
+        static DeviceManager instance;
+        return instance;
+    }
+    static sp<IDevice> createInterfaceInstance(const FactoryAndDevice& factoryAndDevice) {
+        auto [factoryName, name] = factoryAndDevice;
+        sp<IDevicesFactory> factory = DevicesFactoryManager::getInstance().get(factoryName);
+        return name == kPrimaryDevice ? openPrimaryDevice(factory) : openDevice(factory, name);
+    }
+    using InterfaceManager::reset;
+
+    static constexpr const char* kPrimaryDevice = "primary";
+
+    sp<IDevice> get(const std::string& factoryName, const std::string& name) {
+        return InterfaceManager::get(std::make_tuple(factoryName, name));
+    }
+    sp<IPrimaryDevice> getPrimary(const std::string& factoryName) {
+        sp<IDevice> device = get(factoryName, kPrimaryDevice);
+        return device != nullptr ? IPrimaryDevice::castFrom(device) : nullptr;
+    }
+    bool reset(const std::string& factoryName, const std::string& name)
+            __attribute__((warn_unused_result)) {
+        return InterfaceManager::reset(std::make_tuple(factoryName, name));
+    }
+    bool resetPrimary(const std::string& factoryName) __attribute__((warn_unused_result)) {
+        return reset(factoryName, kPrimaryDevice);
+    }
+
+  private:
+    static sp<IDevice> openDevice(const sp<IDevicesFactory>& factory, const std::string& name) {
+        if (factory == nullptr) return nullptr;
+        sp<IDevice> device;
+#if MAJOR_VERSION >= 4
+        Result result;
+        auto ret = factory->openDevice(name, returnIn(result, device));
+        if (!ret.isOk() || result != Result::OK || device == nullptr) {
+            ALOGW("Device %s can not be opened, transaction: %s, result %d, device %p",
+                  name.c_str(), ret.description().c_str(), result, device.get());
+            return nullptr;
+        }
+#else
+        (void)name;
+#endif
+        return device;
+    }
+
+    static sp<IDevice> openPrimaryDevice(const sp<IDevicesFactory>& factory) {
+        if (factory == nullptr) return nullptr;
+        Result result;
+        sp<IDevice> device;
+#if MAJOR_VERSION == 2
+        auto ret = factory->openDevice(IDevicesFactory::Device::PRIMARY, returnIn(result, device));
+#elif MAJOR_VERSION >= 4
+        auto ret = factory->openPrimaryDevice(returnIn(result, device));
+#endif
+        if (!ret.isOk() || result != Result::OK || device == nullptr) {
+            ALOGW("Primary device can not be opened, transaction: %s, result %d, device %p",
+                  ret.description().c_str(), result, device.get());
+            return nullptr;
+        }
+        return device;
+    }
+};
diff --git a/audio/effect/5.0/xml/Android.bp b/audio/effect/5.0/xml/Android.bp
index 967135c..eb2bcee 100644
--- a/audio/effect/5.0/xml/Android.bp
+++ b/audio/effect/5.0/xml/Android.bp
@@ -1,6 +1,6 @@
 
 xsd_config {
-    name: "audio_effects_conf",
+    name: "audio_effects_conf_V5_0",
     srcs: ["audio_effects_conf.xsd"],
     package_name: "audio.effects.V5_0",
 }
diff --git a/audio/effect/6.0/Android.bp b/audio/effect/6.0/Android.bp
new file mode 100644
index 0000000..b6184f3
--- /dev/null
+++ b/audio/effect/6.0/Android.bp
@@ -0,0 +1,33 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio.effect@6.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IAcousticEchoCancelerEffect.hal",
+        "IAutomaticGainControlEffect.hal",
+        "IBassBoostEffect.hal",
+        "IDownmixEffect.hal",
+        "IEffect.hal",
+        "IEffectBufferProviderCallback.hal",
+        "IEffectsFactory.hal",
+        "IEnvironmentalReverbEffect.hal",
+        "IEqualizerEffect.hal",
+        "ILoudnessEnhancerEffect.hal",
+        "INoiseSuppressionEffect.hal",
+        "IPresetReverbEffect.hal",
+        "IVirtualizerEffect.hal",
+        "IVisualizerEffect.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@6.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/audio/effect/6.0/IAcousticEchoCancelerEffect.hal b/audio/effect/6.0/IAcousticEchoCancelerEffect.hal
new file mode 100644
index 0000000..f7d769f
--- /dev/null
+++ b/audio/effect/6.0/IAcousticEchoCancelerEffect.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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IAcousticEchoCancelerEffect extends IEffect {
+    /**
+     * Sets echo delay value in milliseconds.
+     */
+    setEchoDelay(uint32_t echoDelayMs) generates (Result retval);
+
+    /**
+     * Gets echo delay value in milliseconds.
+     */
+    getEchoDelay() generates (Result retval, uint32_t echoDelayMs);
+};
diff --git a/audio/effect/6.0/IAutomaticGainControlEffect.hal b/audio/effect/6.0/IAutomaticGainControlEffect.hal
new file mode 100644
index 0000000..d264cd4
--- /dev/null
+++ b/audio/effect/6.0/IAutomaticGainControlEffect.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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IAutomaticGainControlEffect extends IEffect {
+    /**
+     * Sets target level in millibels.
+     */
+    setTargetLevel(int16_t targetLevelMb) generates (Result retval);
+
+    /**
+     * Gets target level.
+     */
+    getTargetLevel() generates (Result retval, int16_t targetLevelMb);
+
+    /**
+     * Sets gain in the compression range in millibels.
+     */
+    setCompGain(int16_t compGainMb) generates (Result retval);
+
+    /**
+     * Gets gain in the compression range.
+     */
+    getCompGain() generates (Result retval, int16_t compGainMb);
+
+    /**
+     * Enables or disables limiter.
+     */
+    setLimiterEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Returns whether limiter is enabled.
+     */
+    isLimiterEnabled() generates (Result retval, bool enabled);
+
+    struct AllProperties {
+        int16_t targetLevelMb;
+        int16_t compGainMb;
+        bool limiterEnabled;
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IBassBoostEffect.hal b/audio/effect/6.0/IBassBoostEffect.hal
new file mode 100644
index 0000000..91c4092
--- /dev/null
+++ b/audio/effect/6.0/IBassBoostEffect.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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IBassBoostEffect extends IEffect {
+    /**
+     * Returns whether setting bass boost strength is supported.
+     */
+    isStrengthSupported() generates (Result retval, bool strengthSupported);
+
+    enum StrengthRange : uint16_t {
+        MIN = 0,
+        MAX = 1000
+    };
+
+    /**
+     * Sets bass boost strength.
+     *
+     * @param strength strength of the effect. The valid range for strength
+     *                 strength is [0, 1000], where 0 per mille designates the
+     *                 mildest effect and 1000 per mille designates the
+     *                 strongest.
+     * @return retval operation completion status.
+     */
+    setStrength(uint16_t strength) generates (Result retval);
+
+    /**
+     * Gets virtualization strength.
+     */
+    getStrength() generates (Result retval, uint16_t strength);
+};
diff --git a/audio/effect/6.0/IDownmixEffect.hal b/audio/effect/6.0/IDownmixEffect.hal
new file mode 100644
index 0000000..e3a38e2
--- /dev/null
+++ b/audio/effect/6.0/IDownmixEffect.hal
@@ -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.
+ */
+
+package android.hardware.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IDownmixEffect extends IEffect {
+    enum Type : int32_t {
+        STRIP, // throw away the extra channels
+        FOLD   // mix the extra channels with FL/FR
+    };
+
+    /**
+     * Sets the current downmix preset.
+     */
+    setType(Type preset) generates (Result retval);
+
+    /**
+     * Gets the current downmix preset.
+     */
+    getType() generates (Result retval, Type preset);
+};
diff --git a/audio/effect/6.0/IEffect.hal b/audio/effect/6.0/IEffect.hal
new file mode 100644
index 0000000..b35afee
--- /dev/null
+++ b/audio/effect/6.0/IEffect.hal
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffectBufferProviderCallback;
+
+interface IEffect {
+    /**
+     * Initialize effect engine--all configurations return to default.
+     *
+     * @return retval operation completion status.
+     */
+    @entry
+    init() generates (Result retval);
+
+    /**
+     * Apply new audio parameters configurations for input and output buffers.
+     * The provider callbacks may be empty, but in this case the buffer
+     * must be provided in the EffectConfig structure.
+     *
+     * @param config configuration descriptor.
+     * @param inputBufferProvider optional buffer provider reference.
+     * @param outputBufferProvider optional buffer provider reference.
+     * @return retval operation completion status.
+     */
+    setConfig(EffectConfig config,
+            IEffectBufferProviderCallback inputBufferProvider,
+            IEffectBufferProviderCallback outputBufferProvider)
+            generates (Result retval);
+
+    /**
+     * Reset the effect engine. Keep configuration but resets state and buffer
+     * content.
+     *
+     * @return retval operation completion status.
+     */
+    reset() generates (Result retval);
+
+    /**
+     * Enable processing.
+     *
+     * @return retval operation completion status.
+     */
+    @callflow(next={"prepareForProcessing"})
+    enable() generates (Result retval);
+
+    /**
+     * Disable processing.
+     *
+     * @return retval operation completion status.
+     */
+    @callflow(next={"close"})
+    disable() generates (Result retval);
+
+    /**
+     * Set the rendering device the audio output path is connected to.  The
+     * effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its
+     * descriptor to receive this command when the device changes.
+     *
+     * Note: this method is only supported for effects inserted into
+     *       the output chain.
+     *
+     * @param device output device specification.
+     * @return retval operation completion status.
+     */
+    setDevice(bitfield<AudioDevice> device) generates (Result retval);
+
+    /**
+     * Set and get volume. Used by audio framework to delegate volume control to
+     * effect engine. The effect implementation must set EFFECT_FLAG_VOLUME_CTRL
+     * flag in its descriptor to receive this command. The effect engine must
+     * return the volume that should be applied before the effect is
+     * processed. The overall volume (the volume actually applied by the effect
+     * engine multiplied by the returned value) should match the value indicated
+     * in the command.
+     *
+     * @param volumes vector containing volume for each channel defined in
+     *                EffectConfig for output buffer expressed in 8.24 fixed
+     *                point format.
+     * @return result updated volume values.
+     * @return retval operation completion status.
+     */
+    setAndGetVolume(vec<uint32_t> volumes)
+            generates (Result retval, vec<uint32_t> result);
+
+    /**
+     * Notify the effect of the volume change. The effect implementation must
+     * set EFFECT_FLAG_VOLUME_IND flag in its descriptor to receive this
+     * command.
+     *
+     * @param volumes vector containing volume for each channel defined in
+     *                EffectConfig for output buffer expressed in 8.24 fixed
+     *                point format.
+     * @return retval operation completion status.
+     */
+    volumeChangeNotification(vec<uint32_t> volumes)
+            generates (Result retval);
+
+    /**
+     * Set the audio mode. The effect implementation must set
+     * EFFECT_FLAG_AUDIO_MODE_IND flag in its descriptor to receive this command
+     * when the audio mode changes.
+     *
+     * @param mode desired audio mode.
+     * @return retval operation completion status.
+     */
+    setAudioMode(AudioMode mode) generates (Result retval);
+
+    /**
+     * Apply new audio parameters configurations for input and output buffers of
+     * reverse stream.  An example of reverse stream is the echo reference
+     * supplied to an Acoustic Echo Canceler.
+     *
+     * @param config configuration descriptor.
+     * @param inputBufferProvider optional buffer provider reference.
+     * @param outputBufferProvider optional buffer provider reference.
+     * @return retval operation completion status.
+     */
+    setConfigReverse(EffectConfig config,
+            IEffectBufferProviderCallback inputBufferProvider,
+            IEffectBufferProviderCallback outputBufferProvider)
+            generates (Result retval);
+
+    /**
+     * Set the capture device the audio input path is connected to. The effect
+     * implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to
+     * receive this command when the device changes.
+     *
+     * Note: this method is only supported for effects inserted into
+     *       the input chain.
+     *
+     * @param device input device specification.
+     * @return retval operation completion status.
+     */
+    setInputDevice(bitfield<AudioDevice> device) generates (Result retval);
+
+    /**
+     * Read audio parameters configurations for input and output buffers.
+     *
+     * @return retval operation completion status.
+     * @return config configuration descriptor.
+     */
+    getConfig() generates (Result retval, EffectConfig config);
+
+    /**
+     * Read audio parameters configurations for input and output buffers of
+     * reverse stream.
+     *
+     * @return retval operation completion status.
+     * @return config configuration descriptor.
+     */
+    getConfigReverse() generates (Result retval, EffectConfig config);
+
+    /**
+     * Queries for supported combinations of main and auxiliary channels
+     * (e.g. for a multi-microphone noise suppressor).
+     *
+     * @param maxConfigs maximum number of the combinations to return.
+     * @return retval absence of the feature support is indicated using
+     *                NOT_SUPPORTED code. RESULT_TOO_BIG is returned if
+     *                the number of supported combinations exceeds 'maxConfigs'.
+     * @return result list of configuration descriptors.
+     */
+    getSupportedAuxChannelsConfigs(uint32_t maxConfigs)
+            generates (Result retval, vec<EffectAuxChannelsConfig> result);
+
+    /**
+     * Retrieves the current configuration of main and auxiliary channels.
+     *
+     * @return retval absence of the feature support is indicated using
+     *                NOT_SUPPORTED code.
+     * @return result configuration descriptor.
+     */
+    getAuxChannelsConfig()
+            generates (Result retval, EffectAuxChannelsConfig result);
+
+    /**
+     * Sets the current configuration of main and auxiliary channels.
+     *
+     * @return retval operation completion status; absence of the feature
+     *                support is indicated using NOT_SUPPORTED code.
+     */
+    setAuxChannelsConfig(EffectAuxChannelsConfig config)
+            generates (Result retval);
+
+    /**
+     * Set the audio source the capture path is configured for (Camcorder, voice
+     * recognition...).
+     *
+     * Note: this method is only supported for effects inserted into
+     *       the input chain.
+     *
+     * @param source source descriptor.
+     * @return retval operation completion status.
+     */
+    setAudioSource(AudioSource source) generates (Result retval);
+
+    /**
+     * This command indicates if the playback thread the effect is attached to
+     * is offloaded or not, and updates the I/O handle of the playback thread
+     * the effect is attached to.
+     *
+     * @param param effect offload descriptor.
+     * @return retval operation completion status.
+     */
+    offload(EffectOffloadParameter param) generates (Result retval);
+
+    /**
+     * Returns the effect descriptor.
+     *
+     * @return retval operation completion status.
+     * @return descriptor effect descriptor.
+     */
+    getDescriptor() generates (Result retval, EffectDescriptor descriptor);
+
+    /**
+     * Set up required transports for passing audio buffers to the effect.
+     *
+     * The transport consists of shared memory and a message queue for reporting
+     * effect processing operation status. The shared memory is set up
+     * separately using 'setProcessBuffers' method.
+     *
+     * Processing is requested by setting 'REQUEST_PROCESS' or
+     * 'REQUEST_PROCESS_REVERSE' EventFlags associated with the status message
+     * queue. The result of processing may be one of the following:
+     *   OK if there were no errors during processing;
+     *   INVALID_ARGUMENTS if audio buffers are invalid;
+     *   INVALID_STATE if the engine has finished the disable phase;
+     *   NOT_INITIALIZED if the audio buffers were not set;
+     *   NOT_SUPPORTED if the requested processing type is not supported by
+     *                 the effect.
+     *
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queue.
+     * @return statusMQ a message queue used for passing status from the effect.
+     */
+    @callflow(next={"setProcessBuffers"})
+    prepareForProcessing() generates (Result retval, fmq_sync<Result> statusMQ);
+
+    /**
+     * Set up input and output buffers for processing audio data. The effect
+     * may modify both the input and the output buffer during the operation.
+     * Buffers may be set multiple times during effect lifetime.
+     *
+     * The input and the output buffer may be reused between different effects,
+     * and the input buffer may be used as an output buffer. Buffers are
+     * distinguished using 'AudioBuffer.id' field.
+     *
+     * @param inBuffer input audio buffer.
+     * @param outBuffer output audio buffer.
+     * @return retval OK if both buffers were mapped successfully.
+     *                INVALID_ARGUMENTS if there was a problem with mapping
+     *                                  any of the buffers.
+     */
+    setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer)
+            generates (Result retval);
+
+    /**
+     * Execute a vendor specific command on the effect. The command code
+     * and data, as well as result data are not interpreted by Android
+     * Framework and are passed as-is between the application and the effect.
+     *
+     * The effect must use standard POSIX.1-2001 error codes for the operation
+     * completion status.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it. This method only works for effects
+     * implemented in software.
+     *
+     * @param commandId the ID of the command.
+     * @param data command data.
+     * @param resultMaxSize maximum size in bytes of the result; can be 0.
+     * @return status command completion status.
+     * @return result result data.
+     */
+    command(uint32_t commandId, vec<uint8_t> data, uint32_t resultMaxSize)
+            generates (int32_t status, vec<uint8_t> result);
+
+    /**
+     * Set a vendor-specific parameter and apply it immediately. The parameter
+     * code and data are not interpreted by Android Framework and are passed
+     * as-is between the application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+     * unknown or if provided parameter data is invalid. If the effect does not
+     * support setting vendor-specific parameters, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it. This method only works for effects
+     * implemented in software.
+     *
+     * @param parameter identifying data of the parameter.
+     * @param value the value of the parameter.
+     * @return retval operation completion status.
+     */
+    setParameter(vec<uint8_t> parameter, vec<uint8_t> value)
+            generates (Result retval);
+
+    /**
+     * Get a vendor-specific parameter value. The parameter code and returned
+     * data are not interpreted by Android Framework and are passed as-is
+     * between the application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+     * unknown. If the effect does not support setting vendor-specific
+     * parameters, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param parameter identifying data of the parameter.
+     * @param valueMaxSize maximum size in bytes of the value.
+     * @return retval operation completion status.
+     * @return result the value of the parameter.
+     */
+    getParameter(vec<uint8_t> parameter, uint32_t valueMaxSize)
+            generates (Result retval, vec<uint8_t> value);
+
+    /**
+     * Get supported configs for a vendor-specific feature. The configs returned
+     * are not interpreted by Android Framework and are passed as-is between the
+     * application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+     * unknown. If the effect does not support getting vendor-specific feature
+     * configs, it must return NOT_SUPPORTED. If the feature is supported but
+     * the total number of supported configurations exceeds the maximum number
+     * indicated by the caller, the method must return RESULT_TOO_BIG.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param featureId feature identifier.
+     * @param maxConfigs maximum number of configs to return.
+     * @param configSize size of each config in bytes.
+     * @return retval operation completion status.
+     * @return configsCount number of configs returned.
+     * @return configsData data for all the configs returned.
+     */
+    getSupportedConfigsForFeature(
+            uint32_t featureId,
+            uint32_t maxConfigs,
+            uint32_t configSize) generates (
+                    Result retval,
+                    uint32_t configsCount,
+                    vec<uint8_t> configsData);
+
+    /**
+     * Get the current config for a vendor-specific feature. The config returned
+     * is not interpreted by Android Framework and is passed as-is between the
+     * application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+     * unknown. If the effect does not support getting vendor-specific
+     * feature configs, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param featureId feature identifier.
+     * @param configSize size of the config in bytes.
+     * @return retval operation completion status.
+     * @return configData config data.
+     */
+    getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize)
+            generates (Result retval, vec<uint8_t> configData);
+
+    /**
+     * Set the current config for a vendor-specific feature. The config data
+     * is not interpreted by Android Framework and is passed as-is between the
+     * application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+     * unknown. If the effect does not support getting vendor-specific
+     * feature configs, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param featureId feature identifier.
+     * @param configData config data.
+     * @return retval operation completion status.
+     */
+    setCurrentConfigForFeature(uint32_t featureId, vec<uint8_t> configData)
+            generates (Result retval);
+
+    /**
+     * Called by the framework to deinitialize the effect and free up
+     * all the currently allocated resources. It is recommended to close
+     * the effect on the client side as soon as it is becomes unused.
+     *
+     * @return retval OK in case the success.
+     *                INVALID_STATE if the effect was already closed.
+     */
+    @exit
+    close() generates (Result retval);
+};
diff --git a/audio/effect/6.0/IEffectBufferProviderCallback.hal b/audio/effect/6.0/IEffectBufferProviderCallback.hal
new file mode 100644
index 0000000..097528d
--- /dev/null
+++ b/audio/effect/6.0/IEffectBufferProviderCallback.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.audio.effect@6.0;
+
+/**
+ * This callback interface contains functions that can be used by the effect
+ * engine 'process' function to exchange input and output audio buffers.
+ */
+interface IEffectBufferProviderCallback {
+    /**
+     * Called to retrieve a buffer where data should read from by 'process'
+     * function.
+     *
+     * @return buffer audio buffer for processing
+     */
+    getBuffer() generates (AudioBuffer buffer);
+
+    /**
+     * Called to provide a buffer with the data written by 'process' function.
+     *
+     * @param buffer audio buffer for processing
+     */
+    putBuffer(AudioBuffer buffer);
+};
diff --git a/audio/effect/6.0/IEffectsFactory.hal b/audio/effect/6.0/IEffectsFactory.hal
new file mode 100644
index 0000000..e08b2de
--- /dev/null
+++ b/audio/effect/6.0/IEffectsFactory.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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEffectsFactory {
+    /**
+     * Returns descriptors of different effects in all loaded libraries.
+     *
+     * @return retval operation completion status.
+     * @return result list of effect descriptors.
+     */
+    getAllDescriptors() generates(Result retval, vec<EffectDescriptor> result);
+
+    /**
+     * Returns a descriptor of a particular effect.
+     *
+     * @return retval operation completion status.
+     * @return result effect descriptor.
+     */
+    getDescriptor(Uuid uid) generates(Result retval, EffectDescriptor result);
+
+    /**
+     * Creates an effect engine of the specified type.  To release the effect
+     * engine, it is necessary to release references to the returned effect
+     * object.
+     *
+     * @param uid effect uuid.
+     * @param session audio session to which this effect instance will be
+     *                attached.  All effects created with the same session ID
+     *                are connected in series and process the same signal
+     *                stream.
+     * @param ioHandle identifies the output or input stream this effect is
+     *                 directed to in 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)
+        generates (Result retval, IEffect result, uint64_t effectId);
+};
diff --git a/audio/effect/6.0/IEnvironmentalReverbEffect.hal b/audio/effect/6.0/IEnvironmentalReverbEffect.hal
new file mode 100644
index 0000000..8887533
--- /dev/null
+++ b/audio/effect/6.0/IEnvironmentalReverbEffect.hal
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEnvironmentalReverbEffect extends IEffect {
+    /**
+     * Sets whether the effect should be bypassed.
+     */
+    setBypass(bool bypass) generates (Result retval);
+
+    /**
+     * Gets whether the effect should be bypassed.
+     */
+    getBypass() generates (Result retval, bool bypass);
+
+    enum ParamRange : int16_t {
+        ROOM_LEVEL_MIN = -6000,
+        ROOM_LEVEL_MAX = 0,
+        ROOM_HF_LEVEL_MIN = -4000,
+        ROOM_HF_LEVEL_MAX = 0,
+        DECAY_TIME_MIN = 100,
+        DECAY_TIME_MAX = 20000,
+        DECAY_HF_RATIO_MIN = 100,
+        DECAY_HF_RATIO_MAX = 1000,
+        REFLECTIONS_LEVEL_MIN = -6000,
+        REFLECTIONS_LEVEL_MAX = 0,
+        REFLECTIONS_DELAY_MIN = 0,
+        REFLECTIONS_DELAY_MAX = 65,
+        REVERB_LEVEL_MIN = -6000,
+        REVERB_LEVEL_MAX = 0,
+        REVERB_DELAY_MIN = 0,
+        REVERB_DELAY_MAX = 65,
+        DIFFUSION_MIN = 0,
+        DIFFUSION_MAX = 1000,
+        DENSITY_MIN = 0,
+        DENSITY_MAX = 1000
+    };
+
+    /**
+     * Sets the room level.
+     */
+    setRoomLevel(int16_t roomLevel) generates (Result retval);
+
+    /**
+     * Gets the room level.
+     */
+    getRoomLevel() generates (Result retval, int16_t roomLevel);
+
+    /**
+     * Sets the room high frequencies level.
+     */
+    setRoomHfLevel(int16_t roomHfLevel) generates (Result retval);
+
+    /**
+     * Gets the room high frequencies level.
+     */
+    getRoomHfLevel() generates (Result retval, int16_t roomHfLevel);
+
+    /**
+     * Sets the room decay time.
+     */
+    setDecayTime(uint32_t decayTime) generates (Result retval);
+
+    /**
+     * Gets the room decay time.
+     */
+    getDecayTime() generates (Result retval, uint32_t decayTime);
+
+    /**
+     * Sets the ratio of high frequencies decay.
+     */
+    setDecayHfRatio(int16_t decayHfRatio) generates (Result retval);
+
+    /**
+     * Gets the ratio of high frequencies decay.
+     */
+    getDecayHfRatio() generates (Result retval, int16_t decayHfRatio);
+
+    /**
+     * Sets the level of reflections in the room.
+     */
+    setReflectionsLevel(int16_t reflectionsLevel) generates (Result retval);
+
+    /**
+     * Gets the level of reflections in the room.
+     */
+    getReflectionsLevel() generates (Result retval, int16_t reflectionsLevel);
+
+    /**
+     * Sets the reflections delay in the room.
+     */
+    setReflectionsDelay(uint32_t reflectionsDelay) generates (Result retval);
+
+    /**
+     * Gets the reflections delay in the room.
+     */
+    getReflectionsDelay() generates (Result retval, uint32_t reflectionsDelay);
+
+    /**
+     * Sets the reverb level of the room.
+     */
+    setReverbLevel(int16_t reverbLevel) generates (Result retval);
+
+    /**
+     * Gets the reverb level of the room.
+     */
+    getReverbLevel() generates (Result retval, int16_t reverbLevel);
+
+    /**
+     * Sets the reverb delay of the room.
+     */
+    setReverbDelay(uint32_t reverDelay) generates (Result retval);
+
+    /**
+     * Gets the reverb delay of the room.
+     */
+    getReverbDelay() generates (Result retval, uint32_t reverbDelay);
+
+    /**
+     * Sets room diffusion.
+     */
+    setDiffusion(int16_t diffusion) generates (Result retval);
+
+    /**
+     * Gets room diffusion.
+     */
+    getDiffusion() generates (Result retval, int16_t diffusion);
+
+    /**
+     * Sets room wall density.
+     */
+    setDensity(int16_t density) generates (Result retval);
+
+    /**
+     * Gets room wall density.
+     */
+    getDensity() generates (Result retval, int16_t density);
+
+    struct AllProperties {
+        int16_t  roomLevel;         // in millibels,    range -6000 to 0
+        int16_t  roomHfLevel;       // in millibels,    range -4000 to 0
+        uint32_t decayTime;         // in milliseconds, range 100 to 20000
+        int16_t  decayHfRatio;      // in permilles,    range 100 to 1000
+        int16_t  reflectionsLevel;  // in millibels,    range -6000 to 0
+        uint32_t reflectionsDelay;  // in milliseconds, range 0 to 65
+        int16_t  reverbLevel;       // in millibels,    range -6000 to 0
+        uint32_t reverbDelay;       // in milliseconds, range 0 to 65
+        int16_t  diffusion;         // in permilles,    range 0 to 1000
+        int16_t  density;           // in permilles,    range 0 to 1000
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IEqualizerEffect.hal b/audio/effect/6.0/IEqualizerEffect.hal
new file mode 100644
index 0000000..962d518
--- /dev/null
+++ b/audio/effect/6.0/IEqualizerEffect.hal
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IEqualizerEffect extends IEffect {
+    /**
+     * Gets the number of frequency bands that the equalizer supports.
+     */
+    getNumBands() generates (Result retval, uint16_t numBands);
+
+    /**
+     * Returns the minimum and maximum band levels supported.
+     */
+    getLevelRange()
+            generates (Result retval, int16_t minLevel, int16_t maxLevel);
+
+    /**
+     * Sets the gain for the given equalizer band.
+     */
+    setBandLevel(uint16_t band, int16_t level) generates (Result retval);
+
+    /**
+     * Gets the gain for the given equalizer band.
+     */
+    getBandLevel(uint16_t band) generates (Result retval, int16_t level);
+
+    /**
+     * Gets the center frequency of the given band, in milliHertz.
+     */
+    getBandCenterFrequency(uint16_t band)
+            generates (Result retval, uint32_t centerFreqmHz);
+
+    /**
+     * Gets the frequency range of the given frequency band, in milliHertz.
+     */
+    getBandFrequencyRange(uint16_t band)
+            generates (Result retval, uint32_t minFreqmHz, uint32_t maxFreqmHz);
+
+    /**
+     * Gets the band that has the most effect on the given frequency
+     * in milliHertz.
+     */
+    getBandForFrequency(uint32_t freqmHz)
+            generates (Result retval, uint16_t band);
+
+    /**
+     * Gets the names of all presets the equalizer supports.
+     */
+    getPresetNames() generates (Result retval, vec<string> names);
+
+    /**
+     * Sets the current preset using the index of the preset in the names
+     * vector returned via 'getPresetNames'.
+     */
+    setCurrentPreset(uint16_t preset) generates (Result retval);
+
+    /**
+     * Gets the current preset.
+     */
+    getCurrentPreset() generates (Result retval, uint16_t preset);
+
+    struct AllProperties {
+        uint16_t curPreset;
+        vec<int16_t> bandLevels;
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/ILoudnessEnhancerEffect.hal b/audio/effect/6.0/ILoudnessEnhancerEffect.hal
new file mode 100644
index 0000000..73dc818
--- /dev/null
+++ b/audio/effect/6.0/ILoudnessEnhancerEffect.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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface ILoudnessEnhancerEffect extends IEffect {
+    /**
+     * Sets target gain expressed in millibels.
+     */
+    setTargetGain(int32_t targetGainMb) generates (Result retval);
+
+    /**
+     * Gets target gain expressed in millibels.
+     */
+    getTargetGain() generates (Result retval, int32_t targetGainMb);
+};
diff --git a/audio/effect/6.0/INoiseSuppressionEffect.hal b/audio/effect/6.0/INoiseSuppressionEffect.hal
new file mode 100644
index 0000000..16dee57
--- /dev/null
+++ b/audio/effect/6.0/INoiseSuppressionEffect.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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface INoiseSuppressionEffect extends IEffect {
+    enum Level : int32_t {
+        LOW,
+        MEDIUM,
+        HIGH
+    };
+
+    /**
+     * Sets suppression level.
+     */
+    setSuppressionLevel(Level level) generates (Result retval);
+
+    /**
+     * Gets suppression level.
+     */
+    getSuppressionLevel() generates (Result retval, Level level);
+
+    enum Type : int32_t {
+        SINGLE_CHANNEL,
+        MULTI_CHANNEL
+    };
+
+    /**
+     * Set suppression type.
+     */
+    setSuppressionType(Type type) generates (Result retval);
+
+    /**
+     * Get suppression type.
+     */
+    getSuppressionType() generates (Result retval, Type type);
+
+    struct AllProperties {
+        Level level;
+        Type type;
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/6.0/IPresetReverbEffect.hal b/audio/effect/6.0/IPresetReverbEffect.hal
new file mode 100644
index 0000000..d00c8af
--- /dev/null
+++ b/audio/effect/6.0/IPresetReverbEffect.hal
@@ -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.
+ */
+
+package android.hardware.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IPresetReverbEffect extends IEffect {
+    enum Preset : int32_t {
+        NONE,        // no reverb or reflections
+        SMALLROOM,   // a small room less than five meters in length
+        MEDIUMROOM,  // a medium room with a length of ten meters or less
+        LARGEROOM,   // a large-sized room suitable for live performances
+        MEDIUMHALL,  // a medium-sized hall
+        LARGEHALL,   // a large-sized hall suitable for a full orchestra
+        PLATE,       // synthesis of the traditional plate reverb
+        LAST = PLATE
+    };
+
+    /**
+     * Sets the current preset.
+     */
+    setPreset(Preset preset) generates (Result retval);
+
+    /**
+     * Gets the current preset.
+     */
+    getPreset() generates (Result retval, Preset preset);
+};
diff --git a/audio/effect/6.0/IVirtualizerEffect.hal b/audio/effect/6.0/IVirtualizerEffect.hal
new file mode 100644
index 0000000..5967b33
--- /dev/null
+++ b/audio/effect/6.0/IVirtualizerEffect.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.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IVirtualizerEffect extends IEffect {
+    /**
+     * Returns whether setting virtualization strength is supported.
+     */
+    isStrengthSupported() generates (bool strengthSupported);
+
+    enum StrengthRange : uint16_t {
+        MIN = 0,
+        MAX = 1000
+    };
+
+    /**
+     * Sets virtualization strength.
+     *
+     * @param strength strength of the effect. The valid range for strength
+     *                 strength is [0, 1000], where 0 per mille designates the
+     *                 mildest effect and 1000 per mille designates the
+     *                 strongest.
+     * @return retval operation completion status.
+     */
+    setStrength(uint16_t strength) generates (Result retval);
+
+    /**
+     * Gets virtualization strength.
+     */
+    getStrength() generates (Result retval, uint16_t strength);
+
+    struct SpeakerAngle {
+        /** Speaker channel mask */
+        bitfield<AudioChannelMask> mask;
+        // all angles are expressed in degrees and
+        // are relative to the listener.
+        int16_t azimuth; // 0 is the direction the listener faces
+                         // 180 is behind the listener
+                         // -90 is to their left
+        int16_t elevation; // 0 is the horizontal plane
+                           // +90 is above the listener, -90 is below
+    };
+    /**
+     * Retrieves virtual speaker angles for the given channel mask on the
+     * specified device.
+     */
+    getVirtualSpeakerAngles(bitfield<AudioChannelMask> mask, AudioDevice device)
+            generates (Result retval, vec<SpeakerAngle> speakerAngles);
+
+    /**
+     * Forces the virtualizer effect for the given output device.
+     */
+    forceVirtualizationMode(AudioDevice device) generates (Result retval);
+
+    /**
+     * Returns audio device reflecting the current virtualization mode,
+     * AUDIO_DEVICE_NONE when not virtualizing.
+     */
+    getVirtualizationMode() generates (Result retval, AudioDevice device);
+};
diff --git a/audio/effect/6.0/IVisualizerEffect.hal b/audio/effect/6.0/IVisualizerEffect.hal
new file mode 100644
index 0000000..3df3e6f
--- /dev/null
+++ b/audio/effect/6.0/IVisualizerEffect.hal
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+import IEffect;
+
+interface IVisualizerEffect extends IEffect {
+    enum CaptureSizeRange : int32_t {
+        MAX = 1024,  // maximum capture size in samples
+        MIN = 128    // minimum capture size in samples
+    };
+
+    /**
+     * Sets the number PCM samples in the capture.
+     */
+    setCaptureSize(uint16_t captureSize) generates (Result retval);
+
+    /**
+     * Gets the number PCM samples in the capture.
+     */
+    getCaptureSize() generates (Result retval, uint16_t captureSize);
+
+    enum ScalingMode : int32_t {
+        // Keep in sync with SCALING_MODE_... in
+        // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+        NORMALIZED = 0,
+        AS_PLAYED = 1
+    };
+
+    /**
+     * Specifies the way the captured data is scaled.
+     */
+    setScalingMode(ScalingMode scalingMode) generates (Result retval);
+
+    /**
+     * Retrieves the way the captured data is scaled.
+     */
+    getScalingMode() generates (Result retval, ScalingMode scalingMode);
+
+    /**
+     * Informs the visualizer about the downstream latency.
+     */
+    setLatency(uint32_t latencyMs) generates (Result retval);
+
+    /**
+     * Gets the downstream latency.
+     */
+    getLatency() generates (Result retval, uint32_t latencyMs);
+
+    enum MeasurementMode : int32_t {
+        // Keep in sync with MEASUREMENT_MODE_... in
+        // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+        NONE = 0x0,
+        PEAK_RMS = 0x1
+    };
+
+    /**
+     * Specifies which measurements are to be made.
+     */
+    setMeasurementMode(MeasurementMode measurementMode)
+            generates (Result retval);
+
+    /**
+     * Retrieves which measurements are to be made.
+     */
+    getMeasurementMode() generates (
+            Result retval, MeasurementMode measurementMode);
+
+    /**
+     * Retrieves the latest PCM snapshot captured by the visualizer engine.  The
+     * number of samples to capture is specified by 'setCaptureSize' parameter.
+     *
+     * @return retval operation completion status.
+     * @return samples samples in 8 bit unsigned format (0 = 0x80)
+     */
+    capture() generates (Result retval, vec<uint8_t> samples);
+
+    struct Measurement {
+        MeasurementMode mode;    // discriminator
+        union Values {
+            struct PeakAndRms {
+                int32_t peakMb;  // millibels
+                int32_t rmsMb;   // millibels
+            } peakAndRms;
+        } value;
+    };
+    /**
+     * Retrieves the latest measurements. The measurements to be made
+     * are specified by 'setMeasurementMode' parameter.
+     *
+     * @return retval operation completion status.
+     * @return result measurement.
+     */
+    measure() generates (Result retval, Measurement result);
+};
diff --git a/audio/effect/6.0/types.hal b/audio/effect/6.0/types.hal
new file mode 100644
index 0000000..dd5a4ad
--- /dev/null
+++ b/audio/effect/6.0/types.hal
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@6.0;
+
+import android.hardware.audio.common@6.0;
+
+enum Result : int32_t {
+    OK,
+    NOT_INITIALIZED,
+    INVALID_ARGUMENTS,
+    INVALID_STATE,
+    NOT_SUPPORTED,
+    RESULT_TOO_BIG
+};
+
+/**
+ * Effect engine capabilities/requirements flags.
+ *
+ * Definitions for flags field of effect descriptor.
+ *
+ * +----------------+--------+--------------------------------------------------
+ * | description    | bits   | values
+ * +----------------+--------+--------------------------------------------------
+ * | connection     | 0..2   | 0 insert: after track process
+ * | mode           |        | 1 auxiliary: connect to track auxiliary
+ * |                |        |  output and use send level
+ * |                |        | 2 replace: replaces track process function;
+ * |                |        |   must implement SRC, volume and mono to stereo.
+ * |                |        | 3 pre processing: applied below audio HAL on in
+ * |                |        | 4 post processing: applied below audio HAL on out
+ * |                |        | 5 - 7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | insertion      | 3..5   | 0 none
+ * | preference     |        | 1 first of the chain
+ * |                |        | 2 last of the chain
+ * |                |        | 3 exclusive (only effect in the insert chain)
+ * |                |        | 4..7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Volume         | 6..8   | 0 none
+ * | management     |        | 1 implements volume control
+ * |                |        | 2 requires volume indication
+ * |                |        | 3 monitors requested volume
+ * |                |        | 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Device         | 9..11  | 0 none
+ * | indication     |        | 1 requires device updates
+ * |                |        | 2, 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Sample input   | 12..13 | 1 direct: process() function or
+ * | mode           |        |   EFFECT_CMD_SET_CONFIG command must specify
+ * |                |        |   a buffer descriptor
+ * |                |        | 2 provider: process() function uses the
+ * |                |        |   bufferProvider indicated by the
+ * |                |        |   EFFECT_CMD_SET_CONFIG command to request input.
+ * |                |        |   buffers.
+ * |                |        | 3 both: both input modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Sample output  | 14..15 | 1 direct: process() function or
+ * | mode           |        |   EFFECT_CMD_SET_CONFIG command must specify
+ * |                |        |   a buffer descriptor
+ * |                |        | 2 provider: process() function uses the
+ * |                |        |   bufferProvider indicated by the
+ * |                |        |   EFFECT_CMD_SET_CONFIG command to request output
+ * |                |        |   buffers.
+ * |                |        | 3 both: both output modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Hardware       | 16..17 | 0 No hardware acceleration
+ * | acceleration   |        | 1 non tunneled hw acceleration: the process()
+ * |                |        |   function reads the samples, send them to HW
+ * |                |        |   accelerated effect processor, reads back
+ * |                |        |   the processed samples and returns them
+ * |                |        |   to the output buffer.
+ * |                |        | 2 tunneled hw acceleration: the process()
+ * |                |        |   function is transparent. The effect interface
+ * |                |        |   is only used to control the effect engine.
+ * |                |        |   This mode is relevant for global effects
+ * |                |        |   actually applied by the audio hardware on
+ * |                |        |   the output stream.
+ * +----------------+--------+--------------------------------------------------
+ * | Audio Mode     | 18..19 | 0 none
+ * | indication     |        | 1 requires audio mode updates
+ * |                |        | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Audio source   | 20..21 | 0 none
+ * | indication     |        | 1 requires audio source updates
+ * |                |        | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Effect offload | 22     | 0 The effect cannot be offloaded to an audio DSP
+ * | supported      |        | 1 The effect can be offloaded to an audio DSP
+ * +----------------+--------+--------------------------------------------------
+ * | Process        | 23     | 0 The effect implements a process function.
+ * | function       |        | 1 The effect does not implement a process
+ * | not            |        |   function: enabling the effect has no impact
+ * | implemented    |        |   on latency or CPU load.
+ * |                |        |   Effect implementations setting this flag do not
+ * |                |        |   have to implement a process function.
+ * +----------------+--------+--------------------------------------------------
+ */
+@export(name="", value_prefix="EFFECT_FLAG_")
+enum EffectFlags : int32_t {
+    // Insert mode
+    TYPE_SHIFT = 0,
+    TYPE_SIZE = 3,
+    TYPE_MASK = ((1 << TYPE_SIZE) -1) << TYPE_SHIFT,
+    TYPE_INSERT = 0 << TYPE_SHIFT,
+    TYPE_AUXILIARY = 1 << TYPE_SHIFT,
+    TYPE_REPLACE = 2 << TYPE_SHIFT,
+    TYPE_PRE_PROC = 3 << TYPE_SHIFT,
+    TYPE_POST_PROC = 4 << TYPE_SHIFT,
+
+    // Insert preference
+    INSERT_SHIFT = TYPE_SHIFT + TYPE_SIZE,
+    INSERT_SIZE = 3,
+    INSERT_MASK = ((1 << INSERT_SIZE) -1) << INSERT_SHIFT,
+    INSERT_ANY = 0 << INSERT_SHIFT,
+    INSERT_FIRST = 1 << INSERT_SHIFT,
+    INSERT_LAST = 2 << INSERT_SHIFT,
+    INSERT_EXCLUSIVE = 3 << INSERT_SHIFT,
+
+    // Volume control
+    VOLUME_SHIFT = INSERT_SHIFT + INSERT_SIZE,
+    VOLUME_SIZE = 3,
+    VOLUME_MASK = ((1 << VOLUME_SIZE) -1) << VOLUME_SHIFT,
+    VOLUME_CTRL = 1 << VOLUME_SHIFT,
+    VOLUME_IND = 2 << VOLUME_SHIFT,
+    VOLUME_MONITOR = 3 << VOLUME_SHIFT,
+    VOLUME_NONE = 0 << VOLUME_SHIFT,
+
+    // Device indication
+    DEVICE_SHIFT = VOLUME_SHIFT + VOLUME_SIZE,
+    DEVICE_SIZE = 3,
+    DEVICE_MASK = ((1 << DEVICE_SIZE) -1) << DEVICE_SHIFT,
+    DEVICE_IND = 1 << DEVICE_SHIFT,
+    DEVICE_NONE = 0 << DEVICE_SHIFT,
+
+    // Sample input modes
+    INPUT_SHIFT = DEVICE_SHIFT + DEVICE_SIZE,
+    INPUT_SIZE = 2,
+    INPUT_MASK = ((1 << INPUT_SIZE) -1) << INPUT_SHIFT,
+    INPUT_DIRECT = 1 << INPUT_SHIFT,
+    INPUT_PROVIDER = 2 << INPUT_SHIFT,
+    INPUT_BOTH = 3 << INPUT_SHIFT,
+
+    // Sample output modes
+    OUTPUT_SHIFT = INPUT_SHIFT + INPUT_SIZE,
+    OUTPUT_SIZE = 2,
+    OUTPUT_MASK = ((1 << OUTPUT_SIZE) -1) << OUTPUT_SHIFT,
+    OUTPUT_DIRECT = 1 << OUTPUT_SHIFT,
+    OUTPUT_PROVIDER = 2 << OUTPUT_SHIFT,
+    OUTPUT_BOTH = 3 << OUTPUT_SHIFT,
+
+    // Hardware acceleration mode
+    HW_ACC_SHIFT = OUTPUT_SHIFT + OUTPUT_SIZE,
+    HW_ACC_SIZE = 2,
+    HW_ACC_MASK = ((1 << HW_ACC_SIZE) -1) << HW_ACC_SHIFT,
+    HW_ACC_SIMPLE = 1 << HW_ACC_SHIFT,
+    HW_ACC_TUNNEL = 2 << HW_ACC_SHIFT,
+
+    // Audio mode indication
+    AUDIO_MODE_SHIFT = HW_ACC_SHIFT + HW_ACC_SIZE,
+    AUDIO_MODE_SIZE = 2,
+    AUDIO_MODE_MASK = ((1 << AUDIO_MODE_SIZE) -1) << AUDIO_MODE_SHIFT,
+    AUDIO_MODE_IND = 1 << AUDIO_MODE_SHIFT,
+    AUDIO_MODE_NONE = 0 << AUDIO_MODE_SHIFT,
+
+    // Audio source indication
+    AUDIO_SOURCE_SHIFT = AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE,
+    AUDIO_SOURCE_SIZE = 2,
+    AUDIO_SOURCE_MASK = ((1 << AUDIO_SOURCE_SIZE) -1) << AUDIO_SOURCE_SHIFT,
+    AUDIO_SOURCE_IND = 1 << AUDIO_SOURCE_SHIFT,
+    AUDIO_SOURCE_NONE = 0 << AUDIO_SOURCE_SHIFT,
+
+    // Effect offload indication
+    OFFLOAD_SHIFT = AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE,
+    OFFLOAD_SIZE = 1,
+    OFFLOAD_MASK = ((1 << OFFLOAD_SIZE) -1) << OFFLOAD_SHIFT,
+    OFFLOAD_SUPPORTED = 1 << OFFLOAD_SHIFT,
+
+    // Effect has no process indication
+    NO_PROCESS_SHIFT = OFFLOAD_SHIFT + OFFLOAD_SIZE,
+    NO_PROCESS_SIZE = 1,
+    NO_PROCESS_MASK = ((1 << NO_PROCESS_SIZE) -1) << NO_PROCESS_SHIFT,
+    NO_PROCESS = 1 << NO_PROCESS_SHIFT
+};
+
+/**
+ * The effect descriptor contains necessary information to facilitate the
+ * enumeration of the effect engines present in a library.
+ */
+struct EffectDescriptor {
+    Uuid type;                   // UUID of to the OpenSL ES interface implemented
+                                 // by this effect
+    Uuid uuid;                   // UUID for this particular implementation
+    bitfield<EffectFlags> flags; // effect engine capabilities/requirements flags
+    uint16_t cpuLoad;            // CPU load indication expressed in 0.1 MIPS units
+                                 // as estimated on an ARM9E core (ARMv5TE) with 0 WS
+    uint16_t memoryUsage;        // data memory usage expressed in KB and includes
+                                 // only dynamically allocated memory
+    uint8_t[64] name;            // human readable effect name
+    uint8_t[64] implementor;     // human readable effect implementor name
+};
+
+/**
+ * A buffer is a chunk of audio data for processing.  Multi-channel audio is
+ * always interleaved. The channel order is from LSB to MSB with regard to the
+ * channel mask definition in audio.h, audio_channel_mask_t, e.g.:
+ * Stereo: L, R; 5.1: FL, FR, FC, LFE, BL, BR.
+ *
+ * The buffer size is expressed in frame count, a frame being composed of
+ * samples for all channels at a given time. Frame size for unspecified format
+ * (AUDIO_FORMAT_OTHER) is 8 bit by definition.
+ */
+struct AudioBuffer {
+    uint64_t id;
+    uint32_t frameCount;
+    memory data;
+};
+
+@export(name="effect_buffer_access_e", value_prefix="EFFECT_BUFFER_")
+enum EffectBufferAccess : int32_t {
+    ACCESS_WRITE,
+    ACCESS_READ,
+    ACCESS_ACCUMULATE
+};
+
+/**
+ * Determines what fields of EffectBufferConfig need to be considered.
+ */
+@export(name="", value_prefix="EFFECT_CONFIG_")
+enum EffectConfigParameters : int32_t {
+    BUFFER = 0x0001,    // buffer field
+    SMP_RATE = 0x0002,  // samplingRate
+    CHANNELS = 0x0004,  // channels
+    FORMAT = 0x0008,    // format
+    ACC_MODE = 0x0010,  // accessMode
+    // Note that the 2.0 ALL have been moved to an helper function
+};
+
+/**
+ * The buffer config structure specifies the input or output audio format
+ * to be used by the effect engine.
+ */
+struct EffectBufferConfig {
+    AudioBuffer buffer;
+    uint32_t samplingRateHz;
+    bitfield<AudioChannelMask> channels;
+    AudioFormat format;
+    EffectBufferAccess accessMode;
+    bitfield<EffectConfigParameters> mask;
+};
+
+struct EffectConfig {
+    EffectBufferConfig inputCfg;
+    EffectBufferConfig outputCfg;
+};
+
+@export(name="effect_feature_e", value_prefix="EFFECT_FEATURE_")
+enum EffectFeature : int32_t {
+    AUX_CHANNELS, // supports auxiliary channels
+                  // (e.g. dual mic noise suppressor)
+    CNT
+};
+
+struct EffectAuxChannelsConfig {
+    bitfield<AudioChannelMask> mainChannels;  // channel mask for main channels
+    bitfield<AudioChannelMask> auxChannels;   // channel mask for auxiliary channels
+};
+
+struct EffectOffloadParameter {
+    bool isOffload;          // true if the playback thread the effect
+                             // is attached to is offloaded
+    AudioIoHandle ioHandle;  // io handle of the playback thread
+                             // the effect is attached to
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * the status message queue used by effects.
+ */
+enum MessageQueueFlagBits : uint32_t {
+    DONE_PROCESSING = 1 << 0,
+    REQUEST_PROCESS = 1 << 1,
+    REQUEST_PROCESS_REVERSE = 1 << 2,
+    REQUEST_QUIT = 1 << 3,
+    REQUEST_PROCESS_ALL =
+        REQUEST_PROCESS | REQUEST_PROCESS_REVERSE | REQUEST_QUIT
+};
diff --git a/audio/effect/6.0/xml/Android.bp b/audio/effect/6.0/xml/Android.bp
new file mode 100644
index 0000000..353686b
--- /dev/null
+++ b/audio/effect/6.0/xml/Android.bp
@@ -0,0 +1,6 @@
+
+xsd_config {
+    name: "audio_effects_conf_V6_0",
+    srcs: ["audio_effects_conf.xsd"],
+    package_name: "audio.effects.V6_0",
+}
diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt
new file mode 100644
index 0000000..2021639
--- /dev/null
+++ b/audio/effect/6.0/xml/api/current.txt
@@ -0,0 +1,132 @@
+// Signature format: 2.0
+package audio.effects.V6_0 {
+
+  public class AudioEffectsConf {
+    ctor public AudioEffectsConf();
+    method public audio.effects.V6_0.EffectsType getEffects();
+    method public audio.effects.V6_0.LibrariesType getLibraries();
+    method public audio.effects.V6_0.AudioEffectsConf.Postprocess getPostprocess();
+    method public audio.effects.V6_0.AudioEffectsConf.Preprocess getPreprocess();
+    method public audio.effects.V6_0.VersionType getVersion();
+    method public void setEffects(audio.effects.V6_0.EffectsType);
+    method public void setLibraries(audio.effects.V6_0.LibrariesType);
+    method public void setPostprocess(audio.effects.V6_0.AudioEffectsConf.Postprocess);
+    method public void setPreprocess(audio.effects.V6_0.AudioEffectsConf.Preprocess);
+    method public void setVersion(audio.effects.V6_0.VersionType);
+  }
+
+  public static class AudioEffectsConf.Postprocess {
+    ctor public AudioEffectsConf.Postprocess();
+    method public java.util.List<audio.effects.V6_0.StreamPostprocessType> getStream();
+  }
+
+  public static class AudioEffectsConf.Preprocess {
+    ctor public AudioEffectsConf.Preprocess();
+    method public java.util.List<audio.effects.V6_0.StreamPreprocessType> getStream();
+  }
+
+  public class EffectImplType {
+    ctor public EffectImplType();
+    method public String getLibrary();
+    method public String getUuid();
+    method public void setLibrary(String);
+    method public void setUuid(String);
+  }
+
+  public class EffectProxyType extends audio.effects.V6_0.EffectType {
+    ctor public EffectProxyType();
+    method public audio.effects.V6_0.EffectImplType getLibhw();
+    method public audio.effects.V6_0.EffectImplType getLibsw();
+    method public void setLibhw(audio.effects.V6_0.EffectImplType);
+    method public void setLibsw(audio.effects.V6_0.EffectImplType);
+  }
+
+  public class EffectType extends audio.effects.V6_0.EffectImplType {
+    ctor public EffectType();
+    method public String getName();
+    method public void setName(String);
+  }
+
+  public class EffectsType {
+    ctor public EffectsType();
+    method public java.util.List<audio.effects.V6_0.EffectProxyType> getEffectProxy_optional();
+    method public java.util.List<audio.effects.V6_0.EffectType> getEffect_optional();
+  }
+
+  public class LibrariesType {
+    ctor public LibrariesType();
+    method public java.util.List<audio.effects.V6_0.LibrariesType.Library> getLibrary();
+  }
+
+  public static class LibrariesType.Library {
+    ctor public LibrariesType.Library();
+    method public String getName();
+    method public String getPath();
+    method public void setName(String);
+    method public void setPath(String);
+  }
+
+  public enum StreamInputType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V6_0.StreamInputType camcorder;
+    enum_constant public static final audio.effects.V6_0.StreamInputType mic;
+    enum_constant public static final audio.effects.V6_0.StreamInputType unprocessed;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_call;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_communication;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_downlink;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_performance;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_recognition;
+    enum_constant public static final audio.effects.V6_0.StreamInputType voice_uplink;
+  }
+
+  public enum StreamOutputType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V6_0.StreamOutputType alarm;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType bluetooth_sco;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType dtmf;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType enforced_audible;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType music;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType notification;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType ring;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType system;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType tts;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType voice_call;
+  }
+
+  public class StreamPostprocessType extends audio.effects.V6_0.StreamProcessingType {
+    ctor public StreamPostprocessType();
+    method public audio.effects.V6_0.StreamOutputType getType();
+    method public void setType(audio.effects.V6_0.StreamOutputType);
+  }
+
+  public class StreamPreprocessType extends audio.effects.V6_0.StreamProcessingType {
+    ctor public StreamPreprocessType();
+    method public audio.effects.V6_0.StreamInputType getType();
+    method public void setType(audio.effects.V6_0.StreamInputType);
+  }
+
+  public class StreamProcessingType {
+    ctor public StreamProcessingType();
+    method public java.util.List<audio.effects.V6_0.StreamProcessingType.Apply> getApply();
+  }
+
+  public static class StreamProcessingType.Apply {
+    ctor public StreamProcessingType.Apply();
+    method public String getEffect();
+    method public void setEffect(String);
+  }
+
+  public enum VersionType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V6_0.VersionType _2_0;
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static audio.effects.V6_0.AudioEffectsConf read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/audio/effect/6.0/xml/api/last_current.txt b/audio/effect/6.0/xml/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/effect/6.0/xml/api/last_current.txt
diff --git a/audio/effect/6.0/xml/api/last_removed.txt b/audio/effect/6.0/xml/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/effect/6.0/xml/api/last_removed.txt
diff --git a/audio/effect/6.0/xml/api/removed.txt b/audio/effect/6.0/xml/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/effect/6.0/xml/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
new file mode 120000
index 0000000..9d85fa7
--- /dev/null
+++ b/audio/effect/6.0/xml/audio_effects_conf.xsd
@@ -0,0 +1 @@
+../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/audio/effect/all-versions/default/Android.bp b/audio/effect/all-versions/default/Android.bp
index 653b30c..d9bb78b 100644
--- a/audio/effect/all-versions/default/Android.bp
+++ b/audio/effect/all-versions/default/Android.bp
@@ -52,7 +52,6 @@
         "android.hardware.audio.common@2.0-util",
         "android.hardware.audio.effect@2.0",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=2",
         "-DMINOR_VERSION=0",
@@ -68,7 +67,6 @@
         "android.hardware.audio.common@4.0-util",
         "android.hardware.audio.effect@4.0",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=4",
         "-DMINOR_VERSION=0",
@@ -84,10 +82,24 @@
         "android.hardware.audio.common@5.0-util",
         "android.hardware.audio.effect@5.0",
     ],
-
     cflags: [
         "-DMAJOR_VERSION=5",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
     ]
 }
+
+cc_library_shared {
+    name: "android.hardware.audio.effect@6.0-impl",
+    defaults: ["android.hardware.audio.effect-impl_default"],
+    shared_libs: [
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.common@6.0-util",
+        "android.hardware.audio.effect@6.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp
index cccb5c8..edc9076 100644
--- a/audio/effect/all-versions/vts/functional/Android.bp
+++ b/audio/effect/all-versions/vts/functional/Android.bp
@@ -76,3 +76,16 @@
     ]
 }
 
+cc_test {
+    name: "VtsHalAudioEffectV6_0TargetTest",
+    defaults: ["VtsHalAudioEffectTargetTest_default"],
+    static_libs: [
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.effect@6.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index c4c7f7c..3c712b5 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -28,8 +28,14 @@
 
 #include <common/all-versions/VersionUtils.h>
 
+#if MAJOR_VERSION <= 5
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
+#elif MAJOR_VERSION >= 6
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#endif
 
 using ::android::sp;
 using ::android::hardware::hidl_handle;
@@ -49,6 +55,11 @@
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 #endif
 
+#if MAJOR_VERSION <= 5
+// For HAL versions 2..5 Vts Environment and Test base classes are used.
+// The tests are non-parametrized.
+#define EFFECT_TEST TEST_F
+
 // Test environment for Audio Effects Factory HIDL HAL.
 class AudioEffectsFactoryHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
    public:
@@ -71,6 +82,18 @@
         ASSERT_NE(effectsFactory, nullptr);
     }
 
+#elif MAJOR_VERSION >= 6
+// For HAL version 6 and above, standard GTest Environment and Test base classes are used.
+// The tests are parametrized by the IEffectsFactory instance name.
+#define EFFECT_TEST TEST_P
+
+class AudioEffectsFactoryHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        effectsFactory = IEffectsFactory::getService(GetParam());
+        ASSERT_NE(effectsFactory, nullptr);
+    }
+#endif  // The rest of the AudioEffectsFactoryHidlTest class definition is the same.
     void TearDown() override { effectsFactory.clear(); }
 
    protected:
@@ -81,7 +104,7 @@
     sp<IEffectsFactory> effectsFactory;
 };
 
-TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, EnumerateEffects) {
     description("Verify that EnumerateEffects returns at least one effect");
     Result retval = Result::NOT_INITIALIZED;
     size_t effectCount = 0;
@@ -95,7 +118,7 @@
     EXPECT_GT(effectCount, 0u);
 }
 
-TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, CreateEffect) {
     description("Verify that an effect can be created via CreateEffect");
     bool gotEffect = false;
     Uuid effectUuid;
@@ -123,7 +146,7 @@
     EXPECT_NE(nullptr, effect.get());
 }
 
-TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, GetDescriptor) {
     description(
         "Verify that effects factory can provide an effect descriptor via "
         "GetDescriptor");
@@ -146,7 +169,7 @@
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) {
+EFFECT_TEST(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) {
     description("Verify that debugDump doesn't crash on invalid arguments");
 #if MAJOR_VERSION == 2
     Return<void> ret = effectsFactory->debugDump(hidl_handle());
@@ -168,10 +191,17 @@
     std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}};
 
 // The main test class for Audio Effect HIDL HAL.
+#if MAJOR_VERSION <= 5
 class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    public:
     void SetUp() override {
         effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>();
+#elif MAJOR_VERSION >= 6
+class AudioEffectHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        effectsFactory = IEffectsFactory::getService(GetParam());
+#endif
         ASSERT_NE(nullptr, effectsFactory.get());
 
         findAndCreateEffect(getEffectType());
@@ -250,14 +280,14 @@
         static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels));
 }
 
-TEST_F(AudioEffectHidlTest, Close) {
+EFFECT_TEST(AudioEffectHidlTest, Close) {
     description("Verify that an effect can be closed");
     Return<Result> ret = effect->close();
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
 
-TEST_F(AudioEffectHidlTest, GetDescriptor) {
+EFFECT_TEST(AudioEffectHidlTest, GetDescriptor) {
     description("Verify that an effect can return its own descriptor via GetDescriptor");
     Result retval = Result::NOT_INITIALIZED;
     Uuid actualType;
@@ -272,7 +302,7 @@
     EXPECT_EQ(getEffectType(), actualType);
 }
 
-TEST_F(AudioEffectHidlTest, GetSetConfig) {
+EFFECT_TEST(AudioEffectHidlTest, GetSetConfig) {
     description(
         "Verify that it is possible to manipulate effect config via Get / "
         "SetConfig");
@@ -291,26 +321,26 @@
     EXPECT_EQ(Result::OK, ret2);
 }
 
-TEST_F(AudioEffectHidlTest, GetConfigReverse) {
+EFFECT_TEST(AudioEffectHidlTest, GetConfigReverse) {
     description("Verify that GetConfigReverse does not crash");
     Return<void> ret = effect->getConfigReverse([&](Result, const EffectConfig&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) {
+EFFECT_TEST(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) {
     description("Verify that GetSupportedAuxChannelsConfigs does not crash");
     Return<void> ret = effect->getSupportedAuxChannelsConfigs(
         0, [&](Result, const hidl_vec<EffectAuxChannelsConfig>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) {
+EFFECT_TEST(AudioEffectHidlTest, GetAuxChannelsConfig) {
     description("Verify that GetAuxChannelsConfig does not crash");
     Return<void> ret = effect->getAuxChannelsConfig([&](Result, const EffectAuxChannelsConfig&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) {
+EFFECT_TEST(AudioEffectHidlTest, SetAuxChannelsConfig) {
     description("Verify that SetAuxChannelsConfig does not crash");
     Return<Result> ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig());
     EXPECT_TRUE(ret.isOk());
@@ -349,7 +379,7 @@
 }  // namespace hardware
 }  // namespace android
 
-TEST_F(AudioEffectHidlTest, Reset) {
+EFFECT_TEST(AudioEffectHidlTest, Reset) {
     description("Verify that Reset preserves effect configuration");
     Result retval = Result::NOT_INITIALIZED;
     EffectConfig originalConfig;
@@ -374,7 +404,7 @@
     EXPECT_EQ(originalConfig, configAfterReset);
 }
 
-TEST_F(AudioEffectHidlTest, DisableEnableDisable) {
+EFFECT_TEST(AudioEffectHidlTest, DisableEnableDisable) {
     description("Verify Disable -> Enable -> Disable sequence for an effect");
     Return<Result> ret = effect->disable();
     EXPECT_TRUE(ret.isOk());
@@ -387,14 +417,14 @@
     EXPECT_EQ(Result::OK, ret);
 }
 
-TEST_F(AudioEffectHidlTest, SetDevice) {
+EFFECT_TEST(AudioEffectHidlTest, SetDevice) {
     description("Verify that SetDevice works for an output chain effect");
     Return<Result> ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER));
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
 
-TEST_F(AudioEffectHidlTest, SetAndGetVolume) {
+EFFECT_TEST(AudioEffectHidlTest, SetAndGetVolume) {
     description("Verify that SetAndGetVolume method works for an effect");
     uint32_t channelCount;
     getChannelCount(&channelCount);
@@ -410,7 +440,7 @@
     EXPECT_EQ(Result::OK, retval);
 }
 
-TEST_F(AudioEffectHidlTest, VolumeChangeNotification) {
+EFFECT_TEST(AudioEffectHidlTest, VolumeChangeNotification) {
     description("Verify that effect accepts VolumeChangeNotification");
     uint32_t channelCount;
     getChannelCount(&channelCount);
@@ -424,32 +454,32 @@
     EXPECT_EQ(Result::OK, ret);
 }
 
-TEST_F(AudioEffectHidlTest, SetAudioMode) {
+EFFECT_TEST(AudioEffectHidlTest, SetAudioMode) {
     description("Verify that SetAudioMode works for an effect");
     Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL);
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
 
-TEST_F(AudioEffectHidlTest, SetConfigReverse) {
+EFFECT_TEST(AudioEffectHidlTest, SetConfigReverse) {
     description("Verify that SetConfigReverse does not crash");
     Return<Result> ret = effect->setConfigReverse(EffectConfig(), nullptr, nullptr);
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, SetInputDevice) {
+EFFECT_TEST(AudioEffectHidlTest, SetInputDevice) {
     description("Verify that SetInputDevice does not crash");
     Return<Result> ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC));
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, SetAudioSource) {
+EFFECT_TEST(AudioEffectHidlTest, SetAudioSource) {
     description("Verify that SetAudioSource does not crash");
     Return<Result> ret = effect->setAudioSource(AudioSource::MIC);
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, Offload) {
+EFFECT_TEST(AudioEffectHidlTest, Offload) {
     description("Verify that calling Offload method does not crash");
     EffectOffloadParameter offloadParam;
     offloadParam.isOffload = false;
@@ -458,7 +488,7 @@
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, PrepareForProcessing) {
+EFFECT_TEST(AudioEffectHidlTest, PrepareForProcessing) {
     description("Verify that PrepareForProcessing method works for an effect");
     Result retval = Result::NOT_INITIALIZED;
     Return<void> ret = effect->prepareForProcessing(
@@ -467,7 +497,7 @@
     EXPECT_EQ(Result::OK, retval);
 }
 
-TEST_F(AudioEffectHidlTest, SetProcessBuffers) {
+EFFECT_TEST(AudioEffectHidlTest, SetProcessBuffers) {
     description("Verify that SetProcessBuffers works for an effect");
     sp<IAllocator> ashmem = IAllocator::getService("ashmem");
     ASSERT_NE(nullptr, ashmem.get());
@@ -486,41 +516,41 @@
     EXPECT_EQ(Result::OK, ret2);
 }
 
-TEST_F(AudioEffectHidlTest, Command) {
+EFFECT_TEST(AudioEffectHidlTest, Command) {
     description("Verify that Command does not crash");
     Return<void> ret =
         effect->command(0, hidl_vec<uint8_t>(), 0, [&](int32_t, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, SetParameter) {
+EFFECT_TEST(AudioEffectHidlTest, SetParameter) {
     description("Verify that SetParameter does not crash");
     Return<Result> ret = effect->setParameter(hidl_vec<uint8_t>(), hidl_vec<uint8_t>());
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, GetParameter) {
+EFFECT_TEST(AudioEffectHidlTest, GetParameter) {
     description("Verify that GetParameter does not crash");
     Return<void> ret =
         effect->getParameter(hidl_vec<uint8_t>(), 0, [&](Result, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
+EFFECT_TEST(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
     description("Verify that GetSupportedConfigsForFeature does not crash");
     Return<void> ret = effect->getSupportedConfigsForFeature(
         0, 0, 0, [&](Result, uint32_t, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) {
+EFFECT_TEST(AudioEffectHidlTest, GetCurrentConfigForFeature) {
     description("Verify that GetCurrentConfigForFeature does not crash");
     Return<void> ret =
         effect->getCurrentConfigForFeature(0, 0, [&](Result, const hidl_vec<uint8_t>&) {});
     EXPECT_TRUE(ret.isOk());
 }
 
-TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) {
+EFFECT_TEST(AudioEffectHidlTest, SetCurrentConfigForFeature) {
     description("Verify that SetCurrentConfigForFeature does not crash");
     Return<Result> ret = effect->setCurrentConfigForFeature(0, hidl_vec<uint8_t>());
     EXPECT_TRUE(ret.isOk());
@@ -606,21 +636,21 @@
     ASSERT_EQ(Result::OK, retval);
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetNumBands) {
     description("Verify that Equalizer effect reports at least one band");
     uint16_t numBands = 0;
     getNumBands(&numBands);
     EXPECT_GT(numBands, 0);
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetLevelRange) {
     description("Verify that Equalizer effect reports adequate band level range");
     int16_t minLevel = 0x7fff, maxLevel = 0;
     getLevelRange(&minLevel, &maxLevel);
     EXPECT_GT(maxLevel, minLevel);
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
     description("Verify that manipulating band levels works for Equalizer effect");
     uint16_t numBands = 0;
     getNumBands(&numBands);
@@ -649,7 +679,7 @@
     }
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
     description("Verify that Equalizer effect reports adequate band frequency range");
     uint16_t numBands = 0;
     getNumBands(&numBands);
@@ -664,7 +694,7 @@
     }
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
     description("Verify that Equalizer effect supports GetBandForFrequency correctly");
     uint16_t numBands = 0;
     getNumBands(&numBands);
@@ -693,14 +723,14 @@
     }
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetPresetNames) {
     description("Verify that Equalizer effect reports at least one preset");
     size_t presetCount;
     getPresetCount(&presetCount);
     EXPECT_GT(presetCount, 0u);
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
     description("Verify that manipulating the current preset for Equalizer effect");
     size_t presetCount;
     getPresetCount(&presetCount);
@@ -723,7 +753,7 @@
     }
 }
 
-TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
+EFFECT_TEST(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
     description(
         "Verify that setting band levels and presets works via Get / "
         "SetAllProperties for Equalizer effect");
@@ -787,7 +817,7 @@
     sp<ILoudnessEnhancerEffect> enhancer;
 };
 
-TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
+EFFECT_TEST(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
     description(
         "Verify that manipulating the target gain works for Loudness Enhancer "
         "effect");
@@ -808,6 +838,7 @@
     EXPECT_EQ(gain, actualGain);
 }
 
+#if MAJOR_VERSION <= 5
 int main(int argc, char** argv) {
     ::testing::AddGlobalTestEnvironment(AudioEffectsFactoryHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
@@ -816,3 +847,17 @@
     LOG(INFO) << "Test result = " << status;
     return status;
 }
+#elif MAJOR_VERSION >= 6
+INSTANTIATE_TEST_SUITE_P(
+        EffectsFactory, AudioEffectsFactoryHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(
+        Equalizer, EqualizerAudioEffectHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+INSTANTIATE_TEST_SUITE_P(
+        LoudnessEnhancer, LoudnessEnhancerAudioEffectHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+#endif
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/can/1.0/Android.bp b/automotive/can/1.0/Android.bp
new file mode 100644
index 0000000..fe2a2be
--- /dev/null
+++ b/automotive/can/1.0/Android.bp
@@ -0,0 +1,20 @@
+// 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",
+        "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..6ed89f3
--- /dev/null
+++ b/automotive/can/1.0/ICanBus.hal
@@ -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.
+ */
+package android.hardware.automotive.can@1.0;
+
+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);
+};
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/ICanMessageListener.hal b/automotive/can/1.0/ICanMessageListener.hal
new file mode 100644
index 0000000..992d1c7
--- /dev/null
+++ b/automotive/can/1.0/ICanMessageListener.hal
@@ -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.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);
+
+    /**
+     * Called on error event.
+     *
+     * @param error Error type
+     */
+    onError(ErrorEvent error);
+};
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..8aa1d6b
--- /dev/null
+++ b/automotive/can/1.0/default/Android.bp
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+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",
+        "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..65da291
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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>
+
+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(mListenersGuard);
+
+    sp<CloseHandle> closeHandle = new CloseHandle([this, listenerCb]() {
+        std::lock_guard<std::mutex> lck(mListenersGuard);
+        std::erase_if(mListeners, [&](const auto& e) { return e.callback == listenerCb; });
+    });
+    mListeners.emplace_back(CanMessageListener{listenerCb, filter, closeHandle});
+    auto& listener = mListeners.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(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(mListenersGuard);
+    CHECK(mListeners.empty()) << "Listeners list is not empty while interface is being destroyed";
+}
+
+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;
+    }
+    mWasUpInitially = *isUp;
+
+    if (!mWasUpInitially && !netdevice::up(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " up";
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    using namespace std::placeholders;
+    CanSocket::ReadCallback rdcb = std::bind(&CanBus::onRead, this, _1, _2);
+    CanSocket::ErrorCallback errcb = std::bind(&CanBus::onError, this);
+    mSocket = CanSocket::open(mIfname, rdcb, errcb);
+    if (!mSocket) {
+        if (!mWasUpInitially) netdevice::down(mIfname);
+        return ICanController::Result::UNKNOWN_ERROR;
+    }
+
+    mIsUp = true;
+    return ICanController::Result::OK;
+}
+
+void CanBus::clearListeners() {
+    std::vector<wp<ICloseHandle>> listenersToClose;
+    {
+        std::lock_guard<std::mutex> lck(mListenersGuard);
+        std::transform(mListeners.begin(), mListeners.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 mListeners 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(mListenersGuard);
+    CHECK(mListeners.empty()) << "Listeners list wasn't emptied";
+}
+
+bool CanBus::down() {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+    if (!mIsUp) {
+        LOG(WARNING) << "Interface is already down";
+        return false;
+    }
+    mIsUp = false;
+
+    clearListeners();
+    mSocket.reset();
+
+    bool success = true;
+
+    if (!mWasUpInitially && !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;
+}
+
+/**
+ * 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) {
+    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;
+        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::onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp) {
+    CanMessage message = {};
+    message.id = frame.can_id;
+    message.payload = hidl_vec<uint8_t>(frame.data, frame.data + frame.len);
+    message.timestamp = timestamp.count();
+
+    if (UNLIKELY(kSuperVerbose)) {
+        LOG(VERBOSE) << "Got message " << toString(message);
+    }
+
+    std::lock_guard<std::mutex> lck(mListenersGuard);
+    for (auto& listener : mListeners) {
+        if (!match(listener.filter, message.id)) continue;
+        if (!listener.callback->onReceive(message).isOk()) {
+            LOG(WARNING) << "Failed to notify listener about message";
+        }
+    }
+}
+
+void CanBus::onError() {
+    std::lock_guard<std::mutex> lck(mListenersGuard);
+    for (auto& listener : mListeners) {
+        if (!listener.callback->onError(ErrorEvent::HARDWARE_ERROR).isOk()) {
+            LOG(WARNING) << "Failed to notify listener about error";
+        }
+    }
+}
+
+}  // 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..81a83c8
--- /dev/null
+++ b/automotive/can/1.0/default/CanBus.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 {
+    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;
+
+    ICanController::Result up();
+    bool down();
+
+  protected:
+    CanBus(const std::string& ifname);
+
+    /**
+     * Prepare the SocketCAN interface.
+     *
+     * After calling this method, mIfname network interface is available and ready to be brought up.
+     */
+    virtual ICanController::Result preUp();
+
+    /**
+     * Cleanup after bringing the interface down.
+     *
+     * This is a counterpart to preUp().
+     */
+    virtual bool postDown();
+
+    /** Network interface name. */
+    const std::string mIfname;
+
+  private:
+    struct CanMessageListener {
+        sp<ICanMessageListener> callback;
+        hidl_vec<CanMessageFilter> filter;
+        wp<ICloseHandle> closeHandle;
+    };
+    void clearListeners();
+
+    void onRead(const struct canfd_frame& frame, std::chrono::nanoseconds timestamp);
+    void onError();
+
+    std::mutex mListenersGuard;
+    std::vector<CanMessageListener> mListeners GUARDED_BY(mListenersGuard);
+
+    std::unique_ptr<CanSocket> mSocket;
+    bool mWasUpInitially;
+
+    /**
+     * 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;
+};
+
+}  // 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/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..20adbe1
--- /dev/null
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanController.h"
+
+#include "CanBusNative.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,
+    });
+    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 {
+        return ICanController::Result::NOT_SUPPORTED;
+    }
+
+    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;
+}
+
+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;
+
+    auto manager = hidl::manager::V1_2::IServiceManager::getService();
+    if (!manager || !manager->tryUnregister(ICanBus::descriptor, 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..4d86de6
--- /dev/null
+++ b/automotive/can/1.0/default/CanSocket.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanSocket.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+#include <linux/can.h>
+#include <utils/SystemClock.h>
+
+#include <chrono>
+
+namespace android {
+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;
+    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";
+
+    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;
+
+            LOG(ERROR) << "Failed to read CAN packet: " << errno;
+            break;
+        }
+
+        mReadCallback(frame, ts);
+    }
+
+    if (!mStopReaderThread) mErrorCallback();
+
+    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..cd7162d
--- /dev/null
+++ b/automotive/can/1.0/default/CanSocket.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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()>;
+
+    /**
+     * 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;
+
+    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..13693d2 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 {};
+
+    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..94972e0
--- /dev/null
+++ b/automotive/can/1.0/default/CloseHandle.h
@@ -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.
+ */
+
+#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);
+    virtual ~CloseHandle();
+
+    Return<void> close() override;
+
+  private:
+    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..21202e3
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+    }
+
+    /** Returns 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..81d6224
--- /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..87617dd
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/netlink.h>
+
+namespace android {
+namespace netdevice {
+namespace can {
+
+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 (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..ec3f962
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <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.
+ */
+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..33d5de5
--- /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..7ef44fc
--- /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...";
+
+    CanController 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..bc8ff13
--- /dev/null
+++ b/automotive/can/1.0/hidl-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@hidl-utils-lib",
+    export_include_dirs: ["include"],
+}
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..5713d17
--- /dev/null
+++ b/automotive/can/1.0/tools/canhaldump.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/hardware/automotive/can/1.0/ICanMessageListener.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl-utils/hidl-utils.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) {
+        std::cout << "  " << name << "  " << std::hex << std::uppercase << std::setw(3)
+                  << std::setfill('0') << message.id << std::setw(0);
+        if (message.remoteTransmissionRequest) {
+            std::cout << " RTR";
+        } else {
+            std::cout << "   [" << message.payload.size() << "] ";
+            for (const auto byte : message.payload) {
+                std::cout << " " << 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..37877c6
--- /dev/null
+++ b/automotive/can/1.0/types.hal
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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;
+};
+
+/**
+ * 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.
+ */
+struct CanMessageFilter {
+    CanMessageId id;
+    uint32_t mask;
+    bool inverted;
+};
+
+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,
+
+    /** 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..215328e
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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&) { return {}; }
+    virtual Return<void> onError(can::V1_0::ErrorEvent) { 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<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};
+}
+
+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},
+            {0x001, 0x00F, true},
+            {0x200, 0x100, false},
+    };
+
+    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, DoubleCloseListen) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+
+    closeHandle->close().assertOk();
+    closeHandle->close().assertOk();
+}
+
+TEST_F(CanBusHalTest, DontCloseListen) {
+    const auto [result, closeHandle] = listen({}, new CanMessageListener());
+    ASSERT_EQ(Result::OK, result);
+}
+
+}  // 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..699c138
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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) {
+        std::unique_lock<std::mutex> lk(mMessagesGuard);
+        mMessages.push_back(msg);
+        mMessagesUpdated.notify_one();
+        return {};
+    }
+
+    virtual Return<void> onError(can::V1_0::ErrorEvent event) {
+        EXPECT_TRUE(false) << "Got error: " << event;
+        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},
+            {0x010, 0x0F0, false},
+    };
+    auto listenerPositive = bus2.listen(filterPositive);
+
+    hidl_vec<CanMessageFilter> filterNegative = {
+            {0x123, 0x0FF, true},
+            {0x004, 0x00F, true},
+    };
+    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..70f9fe4
--- /dev/null
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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..7734f5c
--- /dev/null
+++ b/automotive/evs/common/utils/default/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_library_static {
+    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/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..f41b33c 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}}},
 
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..dc051d8 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -131,6 +131,36 @@
 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);
         if (status != StatusCode::OK) {
@@ -198,12 +228,19 @@
         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.
+     * Google HAL will just add a timestamp for the value and triggle the callback to android.
+     */
+    VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(propValue);
+    updatedPropValue->timestamp = elapsedRealtimeNano();
+    if (!mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
+        return StatusCode::INTERNAL_ERROR;
     }
 
-    getEmulatorOrDie()->doSetValueFromClient(propValue);
-    doHalEvent(getValuePool()->obtain(propValue));
+    getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
+    doHalEvent(std::move(updatedPropValue));
 
     return StatusCode::OK;
 }
@@ -455,7 +492,7 @@
 
     VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
     if (updatedPropValue) {
-        updatedPropValue->timestamp = elapsedRealtimeNano();
+        updatedPropValue->timestamp = value.timestamp;
         updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
         mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
         auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 0f20dd1..bc0b4d3 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
      *
@@ -2458,9 +2486,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 +2537,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 +2569,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 +2766,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 +3586,3 @@
 enum VmsPublisherInformationIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex {
     PUBLISHER_ID = 1,
 };
-
diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
index d3d7387..a4e95ed 100644
--- a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
+++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
@@ -64,7 +64,7 @@
     // The error passed to the last onError() callback.
     FaceError error;
 
-    // The userId passed to the last onRemoved() callback.
+    // The userId passed to the last callback.
     int32_t userId;
 };
 
@@ -74,24 +74,32 @@
 class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
                      public IBiometricsFaceClientCallback {
   public:
-    Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override {
-        NotifyFromCallback(kCallbackNameOnEnrollResult);
+    Return<void> onEnrollResult(uint64_t, uint32_t, int32_t userId, uint32_t) override {
+        FaceCallbackArgs args = {};
+        args.userId = userId;
+        NotifyFromCallback(kCallbackNameOnEnrollResult, args);
         return Void();
     }
 
-    Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
-        NotifyFromCallback(kCallbackNameOnAuthenticated);
+    Return<void> onAuthenticated(uint64_t, uint32_t, int32_t userId,
+                                 const hidl_vec<uint8_t>&) override {
+        FaceCallbackArgs args = {};
+        args.userId = userId;
+        NotifyFromCallback(kCallbackNameOnAuthenticated, args);
         return Void();
     }
 
-    Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
-        NotifyFromCallback(kCallbackNameOnAcquired);
+    Return<void> onAcquired(uint64_t, int32_t userId, FaceAcquiredInfo, int32_t) override {
+        FaceCallbackArgs args = {};
+        args.userId = userId;
+        NotifyFromCallback(kCallbackNameOnAcquired, args);
         return Void();
     }
 
-    Return<void> onError(uint64_t, int32_t, FaceError error, int32_t) override {
+    Return<void> onError(uint64_t, int32_t userId, FaceError error, int32_t) override {
         FaceCallbackArgs args = {};
         args.error = error;
+        args.userId = userId;
         NotifyFromCallback(kCallbackNameOnError, args);
         return Void();
     }
@@ -103,8 +111,10 @@
         return Void();
     }
 
-    Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
-        NotifyFromCallback(kCallbackNameOnEnumerate);
+    Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t userId) override {
+        FaceCallbackArgs args = {};
+        args.userId = userId;
+        NotifyFromCallback(kCallbackNameOnEnumerate, args);
         return Void();
     }
 
@@ -185,6 +195,7 @@
     // onError should be called with a meaningful (nonzero) error.
     auto res = mCallback->WaitForCallback(kCallbackNameOnError);
     EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
     EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
 }
 
@@ -205,6 +216,7 @@
     // onError should be called with a meaningful (nonzero) error.
     auto res = mCallback->WaitForCallback(kCallbackNameOnError);
     EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
     EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
 }
 
@@ -271,6 +283,7 @@
     Return<Status> ret = mService->enumerate();
     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
     auto res = mCallback->WaitForCallback(kCallbackNameOnEnumerate);
+    EXPECT_EQ(kUserId, res.args->userId);
     EXPECT_TRUE(res.no_timeout);
 }
 
@@ -330,6 +343,7 @@
     auto res = mCallback->WaitForCallback(kCallbackNameOnError);
     // make sure callback was invoked within kRevokeChallengeTimeout
     EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
     EXPECT_EQ(FaceError::CANCELED, res.args->error);
 }
 
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..76f9778 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,27 @@
         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, const auto& /*bytesPerPixel*/,
+                            const auto& /*bytesPerStride*/) {
+                            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 +300,10 @@
         initializeLocked();
     }
 
+    if (mMapperV4 != nullptr) {
+        return lockYCbCrInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf, cpuUsage, accessRegion);
+    }
+
     if (mMapperV3 != nullptr) {
         return lockYCbCrInternal<IMapperV3, MapperErrorV3>(
                 mMapperV3, buf, cpuUsage, accessRegion);
@@ -279,11 +314,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 +329,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..5fe7b19 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -43,9 +43,11 @@
         "android.hardware.camera.provider@2.5",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hidl.allocator@1.0",
         "libgrallocusage",
         "libhidlmemory",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index a5369e7..1b0d7cb 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -55,9 +55,11 @@
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <android/hardware/graphics/mapper/2.0/types.h>
 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.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>
@@ -622,7 +624,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 +641,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 +778,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 +802,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 +868,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 +883,8 @@
         // return from HAL but framework.
         ::android::Vector<StreamBuffer> resultOutputBuffers;
 
+        std::unordered_set<string> expectedPhysicalResults;
+
         InFlightRequest() :
                 shutterTimestamp(0),
                 errorCodeValid(false),
@@ -907,6 +914,24 @@
                 partialResultCount(0),
                 errorStreamId(-1),
                 hasInputBuffer(hasInput) {}
+
+        InFlightRequest(ssize_t numBuffers, bool hasInput,
+                bool partialResults, uint32_t partialCount,
+                const std::unordered_set<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 +1149,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 +1283,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 +1325,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 +1332,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 +1425,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 +1449,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 +1458,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));
     }
 
@@ -1430,7 +1498,7 @@
     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
@@ -4157,7 +4225,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 +4304,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);
         }
 
@@ -4789,7 +4857,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 +5383,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 +5561,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 +5840,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,
@@ -6148,13 +6311,44 @@
         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();
+    sp<android::hardware::graphics::allocator::V4_0::IAllocator> allocatorV4 =
+            android::hardware::graphics::allocator::V4_0::IAllocator::getService();
 
+    sp<android::hardware::graphics::mapper::V4_0::IMapper> mapperV4 =
+            android::hardware::graphics::mapper::V4_0::IMapper::getService();
     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) {
+    if (mapperV4 != nullptr && allocatorV4 != nullptr) {
+        android::hardware::graphics::mapper::V4_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;
+
+        auto ret = mapperV4->createDescriptor(
+                descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V4_0::Error err,
+                                              ::android::hardware::hidl_vec<uint32_t> desc) {
+                    ASSERT_EQ(err, android::hardware::graphics::mapper::V4_0::Error::NONE);
+                    descriptor = desc;
+                });
+        ASSERT_TRUE(ret.isOk());
+
+        ret = allocatorV4->allocate(
+                descriptor, 1u,
+                [&](android::hardware::graphics::mapper::V4_0::Error err, uint32_t /*stride*/,
+                    const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>&
+                            buffers) {
+                    ASSERT_EQ(android::hardware::graphics::mapper::V4_0::Error::NONE, err);
+                    ASSERT_EQ(buffers.size(), 1u);
+                    *buffer_handle = buffers[0];
+                });
+        ASSERT_TRUE(ret.isOk());
+    } else if (mapperV3 != nullptr && allocatorV3 != nullptr) {
         android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo descriptorInfo {};
         descriptorInfo.width = width;
         descriptorInfo.height = height;
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/Android.bp b/cas/1.2/Android.bp
new file mode 100644
index 0000000..af98b2e
--- /dev/null
+++ b/cas/1.2/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.cas@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "ICas.hal",
+        "ICasListener.hal",
+        "IMediaCasService.hal",
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hardware.cas@1.0",
+        "android.hardware.cas@1.1",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/cas/1.2/ICas.hal b/cas/1.2/ICas.hal
new file mode 100644
index 0000000..23edc50
--- /dev/null
+++ b/cas/1.2/ICas.hal
@@ -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.
+ */
+
+package android.hardware.cas@1.2;
+
+import @1.0::HidlCasSessionId;
+import @1.1::ICas;
+import ScramblingMode;
+import SessionIntent;
+import Status;
+
+/**
+ * ICas is the API to control the cas system and is accessible from both
+ * Java and native level. It is used to manage sessions, provision/refresh
+ * the cas system, and process the EMM/ECM messages. It also allows bi-directional,
+ * scheme-specific communications between the client and the cas system.
+ */
+interface ICas extends @1.1::ICas {
+    /**
+     * Open a session to descramble one or more streams by specifying intention
+     * and scrambling mode.
+     *
+     * @param intent the intention of the session to be opened.
+     * @param mode the scrambling mode the session will use.
+     * @return status the status of the call.
+     * @return sessionId the id of the newly opened session.
+     */
+    openSession_1_2(SessionIntent intent, ScramblingMode mode)
+        generates (Status status, HidlCasSessionId sessionId);
+};
diff --git a/cas/1.2/ICasListener.hal b/cas/1.2/ICasListener.hal
new file mode 100644
index 0000000..9a8be20
--- /dev/null
+++ b/cas/1.2/ICasListener.hal
@@ -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.
+ */
+
+package android.hardware.cas@1.2;
+
+import @1.1::ICasListener;
+import StatusEvent;
+
+interface ICasListener extends @1.1::ICasListener {
+    /**
+     * Notify the listener that the status of CAS system has changed.
+     *
+     * @param event the event type of status change.
+     * @param number value for status event.
+     *               For PLUGIN_PHYSICAL_MODULE_CHANGED event:
+     *               the positive number presents how many plugins are inserted;
+     *               the negative number presents how many plugins are removed.
+     *               Client must enumerate plugins after receive the event.
+     *               For PLUGIN_SESSION_NUMBER_CHANGED event:
+     *               the number presents how many sessions are supported
+     *               in the plugin.
+     */
+    onStatusUpdate(StatusEvent event, int32_t number);
+};
diff --git a/cas/1.2/IMediaCasService.hal b/cas/1.2/IMediaCasService.hal
new file mode 100644
index 0000000..a0bec7e
--- /dev/null
+++ b/cas/1.2/IMediaCasService.hal
@@ -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.cas@1.2;
+
+import ICas;
+import ICasListener;
+import @1.1::IMediaCasService;
+
+/**
+ * IMediaCasService is the main entry point for interacting with a vendor's
+ * cas HAL to create cas and descrambler plugin instances. A cas plugin instance
+ * opens cas sessions which are used to obtain keys for a descrambler session,
+ * which can in turn be used to descramble protected video content.
+ *
+ * The 1.2 must always create 1.2 ICas interfaces, which are
+ * returned via the 1.1 createPluginExt method.
+ *
+ * To use 1.2 features the caller must cast the returned interface to a
+ * 1.2 HAL, using V1_2::ICas::castFrom().
+ */
+interface IMediaCasService extends @1.1::IMediaCasService {};
diff --git a/cas/1.2/default/Android.bp b/cas/1.2/default/Android.bp
new file mode 100644
index 0000000..9e53148
--- /dev/null
+++ b/cas/1.2/default/Android.bp
@@ -0,0 +1,49 @@
+cc_defaults {
+    name: "cas_service_defaults@1.2",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+      "CasImpl.cpp",
+      "DescramblerImpl.cpp",
+      "MediaCasService.cpp",
+      "service.cpp",
+      "SharedLibrary.cpp",
+      "TypeConvert.cpp",
+    ],
+
+    compile_multilib: "32",
+
+    shared_libs: [
+      "android.hardware.cas@1.0",
+      "android.hardware.cas@1.1",
+      "android.hardware.cas@1.2",
+      "android.hardware.cas.native@1.0",
+      "android.hidl.memory@1.0",
+      "libbinder",
+      "libhidlbase",
+      "libhidlmemory",
+      "liblog",
+      "libutils",
+    ],
+    header_libs: [
+      "libstagefright_foundation_headers",
+      "media_plugin_headers",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.cas@1.2-service",
+    vintf_fragments: ["android.hardware.cas@1.2-service.xml"],
+    defaults: ["cas_service_defaults@1.2"],
+    init_rc: ["android.hardware.cas@1.2-service.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.cas@1.2-service-lazy",
+    vintf_fragments: ["android.hardware.cas@1.2-service-lazy.xml"],
+    overrides: ["android.hardware.cas@1.2-service"],
+    defaults: ["cas_service_defaults@1.2"],
+    init_rc: ["android.hardware.cas@1.2-service-lazy.rc"],
+    cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/cas/1.2/default/CasImpl.cpp b/cas/1.2/default/CasImpl.cpp
new file mode 100644
index 0000000..46dd251
--- /dev/null
+++ b/cas/1.2/default/CasImpl.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ icensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-CasImpl"
+
+#include <android/hardware/cas/1.1/ICasListener.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "SharedLibrary.h"
+#include "TypeConvert.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+CasImpl::CasImpl(const sp<ICasListener>& listener) : mListener(listener) {
+    ALOGV("CTOR");
+}
+
+CasImpl::~CasImpl() {
+    ALOGV("DTOR");
+    release();
+}
+
+// static
+void CasImpl::OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onEvent(event, arg, data, size);
+}
+
+// static
+void CasImpl::CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+                          const CasSessionId* sessionId) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onEvent(sessionId, event, arg, data, size);
+}
+
+// static
+void CasImpl::StatusUpdate(void* appData, int32_t event, int32_t arg) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl* casImpl = static_cast<CasImpl*>(appData);
+    casImpl->onStatusUpdate(event, arg);
+}
+
+void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin* plugin) {
+    mLibrary = library;
+    std::shared_ptr<CasPlugin> holder(plugin);
+    std::atomic_store(&mPluginHolder, holder);
+}
+
+void CasImpl::onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    HidlCasData eventData;
+    if (data != NULL) {
+        eventData.setToExternal(data, size);
+    }
+
+    mListener->onEvent(event, arg, eventData);
+}
+
+void CasImpl::onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+                      size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    HidlCasData eventData;
+    if (data != NULL) {
+        eventData.setToExternal(data, size);
+    }
+
+    if (sessionId != NULL) {
+        mListener->onSessionEvent(*sessionId, event, arg, eventData);
+    } else {
+        mListener->onEvent(event, arg, eventData);
+    }
+}
+
+void CasImpl::onStatusUpdate(int32_t event, int32_t arg) {
+    if (mListener == NULL) {
+        return;
+    }
+    sp<V1_2::ICasListener> listenerV1_2 = V1_2::ICasListener::castFrom(mListener);
+
+    if (listenerV1_2 != NULL) {
+        listenerV1_2->onStatusUpdate(static_cast<StatusEvent>(event), arg);
+    }
+}
+
+Return<Status> CasImpl::setPluginStatusUpdateCallback() {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setStatusCallback(&CasImpl::StatusUpdate));
+}
+
+Return<Status> CasImpl::setPrivateData(const HidlCasData& pvtData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setPrivateData(pvtData));
+}
+
+Return<void> CasImpl::openSession(openSession_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+    CasSessionId sessionId;
+
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    status_t err = INVALID_OPERATION;
+    if (holder.get() != nullptr) {
+        err = holder->openSession(&sessionId);
+        holder.reset();
+    }
+
+    _hidl_cb(toStatus(err), sessionId);
+
+    return Void();
+}
+
+Return<void> CasImpl::openSession_1_2(const SessionIntent intent, const ScramblingMode mode,
+                                      openSession_1_2_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+    CasSessionId sessionId;
+
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    status_t err = INVALID_OPERATION;
+    if (holder.get() != nullptr) {
+        err = holder->openSession(static_cast<uint32_t>(intent), static_cast<uint32_t>(mode),
+                                  &sessionId);
+        holder.reset();
+    }
+
+    _hidl_cb(toStatus_1_2(err), sessionId);
+
+    return Void();
+}
+
+Return<Status> CasImpl::setSessionPrivateData(const HidlCasSessionId& sessionId,
+                                              const HidlCasData& pvtData) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->setSessionPrivateData(sessionId, pvtData));
+}
+
+Return<Status> CasImpl::closeSession(const HidlCasSessionId& sessionId) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->closeSession(sessionId));
+}
+
+Return<Status> CasImpl::processEcm(const HidlCasSessionId& sessionId, const HidlCasData& ecm) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->processEcm(sessionId, ecm));
+}
+
+Return<Status> CasImpl::processEmm(const HidlCasData& emm) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->processEmm(emm));
+}
+
+Return<Status> CasImpl::sendEvent(int32_t event, int32_t arg, const HidlCasData& eventData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->sendEvent(event, arg, eventData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event,
+                                         int32_t arg, const HidlCasData& eventData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->sendSessionEvent(sessionId, event, arg, eventData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::provision(const hidl_string& provisionString) {
+    ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->provision(String8(provisionString.c_str())));
+}
+
+Return<Status> CasImpl::refreshEntitlements(int32_t refreshType, const HidlCasData& refreshData) {
+    ALOGV("%s", __FUNCTION__);
+    std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->refreshEntitlements(refreshType, refreshData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::release() {
+    ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+    std::shared_ptr<CasPlugin> holder(nullptr);
+    std::atomic_store(&mPluginHolder, holder);
+
+    return Status::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.2/default/CasImpl.h b/cas/1.2/default/CasImpl.h
new file mode 100644
index 0000000..4325c20
--- /dev/null
+++ b/cas/1.2/default/CasImpl.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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
+#define ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
+
+#include <android/hardware/cas/1.1/ICas.h>
+#include <android/hardware/cas/1.2/ICas.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+struct CasPlugin;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+struct ICasListener;
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasData;
+using ::android::hardware::cas::V1_0::HidlCasSessionId;
+using ::android::hardware::cas::V1_0::Status;
+using ::android::hardware::cas::V1_2::ScramblingMode;
+using ::android::hardware::cas::V1_2::SessionIntent;
+using ::android::hardware::cas::V1_2::StatusEvent;
+
+class SharedLibrary;
+
+class CasImpl : public V1_2::ICas {
+  public:
+    CasImpl(const sp<ICasListener>& listener);
+    virtual ~CasImpl();
+
+    static void OnEvent(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+    static void CallBackExt(void* appData, int32_t event, int32_t arg, uint8_t* data, size_t size,
+                            const CasSessionId* sessionId);
+
+    static void StatusUpdate(void* appData, int32_t event, int32_t arg);
+
+    void init(const sp<SharedLibrary>& library, CasPlugin* plugin);
+    void onEvent(int32_t event, int32_t arg, uint8_t* data, size_t size);
+
+    void onEvent(const CasSessionId* sessionId, int32_t event, int32_t arg, uint8_t* data,
+                 size_t size);
+
+    void onStatusUpdate(int32_t event, int32_t arg);
+
+    // ICas inherits
+
+    Return<Status> setPluginStatusUpdateCallback();
+
+    virtual Return<Status> setPrivateData(const HidlCasData& pvtData) override;
+
+    virtual Return<void> openSession(openSession_cb _hidl_cb) override;
+
+    virtual Return<void> openSession_1_2(const SessionIntent intent, const ScramblingMode mode,
+                                         openSession_1_2_cb _hidl_cb) override;
+
+    virtual Return<Status> closeSession(const HidlCasSessionId& sessionId) override;
+
+    virtual Return<Status> setSessionPrivateData(const HidlCasSessionId& sessionId,
+                                                 const HidlCasData& pvtData) override;
+
+    virtual Return<Status> processEcm(const HidlCasSessionId& sessionId,
+                                      const HidlCasData& ecm) override;
+
+    virtual Return<Status> processEmm(const HidlCasData& emm) override;
+
+    virtual Return<Status> sendEvent(int32_t event, int32_t arg,
+                                     const HidlCasData& eventData) override;
+
+    virtual Return<Status> sendSessionEvent(const HidlCasSessionId& sessionId, int32_t event,
+                                            int32_t arg, const HidlCasData& eventData) override;
+
+    virtual Return<Status> provision(const hidl_string& provisionString) override;
+
+    virtual Return<Status> refreshEntitlements(int32_t refreshType,
+                                               const HidlCasData& refreshData) override;
+
+    virtual Return<Status> release() override;
+
+  private:
+    struct PluginHolder;
+    sp<SharedLibrary> mLibrary;
+    std::shared_ptr<CasPlugin> mPluginHolder;
+    sp<ICasListener> mListener;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_CAS_IMPL_H_
diff --git a/cas/1.2/default/DescramblerImpl.cpp b/cas/1.2/default/DescramblerImpl.cpp
new file mode 100644
index 0000000..36dc1a5
--- /dev/null
+++ b/cas/1.2/default/DescramblerImpl.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-DescramblerImpl"
+
+#include <hidlmemory/mapping.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <utils/Log.h>
+
+#include "DescramblerImpl.h"
+#include "SharedLibrary.h"
+#include "TypeConvert.h"
+
+namespace android {
+using hidl::memory::V1_0::IMemory;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+#define CHECK_SUBSAMPLE_DEF(type)                                                                 \
+    static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \
+    static_assert(offsetof(SubSample, numBytesOfClearData) ==                                     \
+                          offsetof(type::SubSample, mNumBytesOfClearData),                        \
+                  "SubSample: numBytesOfClearData offset doesn't match");                         \
+    static_assert(offsetof(SubSample, numBytesOfEncryptedData) ==                                 \
+                          offsetof(type::SubSample, mNumBytesOfEncryptedData),                    \
+                  "SubSample: numBytesOfEncryptedData offset doesn't match")
+
+CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
+CHECK_SUBSAMPLE_DEF(CryptoPlugin);
+
+DescramblerImpl::DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin* plugin)
+    : mLibrary(library), mPluginHolder(plugin) {
+    ALOGV("CTOR: plugin=%p", mPluginHolder.get());
+}
+
+DescramblerImpl::~DescramblerImpl() {
+    ALOGV("DTOR: plugin=%p", mPluginHolder.get());
+    release();
+}
+
+Return<Status> DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
+
+    std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->setMediaCasSession(sessionId));
+}
+
+Return<bool> DescramblerImpl::requiresSecureDecoderComponent(const hidl_string& mime) {
+    std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        return false;
+    }
+
+    return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
+}
+
+static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) {
+    return isInRange<uint64_t, uint64_t>(0, size, offset, length);
+}
+
+Return<void> DescramblerImpl::descramble(ScramblingControl scramblingControl,
+                                         const hidl_vec<SubSample>& subSamples,
+                                         const SharedBuffer& srcBuffer, uint64_t srcOffset,
+                                         const DestinationBuffer& dstBuffer, uint64_t dstOffset,
+                                         descramble_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    // hidl_memory's size is stored in uint64_t, but mapMemory's mmap will map
+    // size in size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed
+    // but the mapped memory's actual size will be smaller than the reported size.
+    if (srcBuffer.heapBase.size() > SIZE_MAX) {
+        ALOGE("Invalid hidl_memory size: %llu", srcBuffer.heapBase.size());
+        android_errorWriteLog(0x534e4554, "79376389");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+
+    sp<IMemory> srcMem = mapMemory(srcBuffer.heapBase);
+
+    // Validate if the offset and size in the SharedBuffer is consistent with the
+    // mapped ashmem, since the offset and size is controlled by client.
+    if (srcMem == NULL) {
+        ALOGE("Failed to map src buffer.");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+    if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize())) {
+        ALOGE("Invalid src buffer range: offset %llu, size %llu, srcMem size %llu",
+              srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize());
+        android_errorWriteLog(0x534e4554, "67962232");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+
+    // use 64-bit here to catch bad subsample size that might be overflowing.
+    uint64_t totalBytesInSubSamples = 0;
+    for (size_t i = 0; i < subSamples.size(); i++) {
+        totalBytesInSubSamples +=
+                (uint64_t)subSamples[i].numBytesOfClearData + subSamples[i].numBytesOfEncryptedData;
+    }
+    // Further validate if the specified srcOffset and requested total subsample size
+    // is consistent with the source shared buffer size.
+    if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) {
+        ALOGE("Invalid srcOffset and subsample size: "
+              "srcOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
+              srcOffset, totalBytesInSubSamples, srcBuffer.size);
+        android_errorWriteLog(0x534e4554, "67962232");
+        _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+        return Void();
+    }
+
+    void* srcPtr = (uint8_t*)(void*)srcMem->getPointer() + srcBuffer.offset;
+    void* dstPtr = NULL;
+    if (dstBuffer.type == BufferType::SHARED_MEMORY) {
+        // When using shared memory, src buffer is also used as dst,
+        // we don't map it again here.
+        dstPtr = srcPtr;
+
+        // In this case the dst and src would be the same buffer, need to validate
+        // dstOffset against the buffer size too.
+        if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) {
+            ALOGE("Invalid dstOffset and subsample size: "
+                  "dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
+                  dstOffset, totalBytesInSubSamples, srcBuffer.size);
+            android_errorWriteLog(0x534e4554, "67962232");
+            _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
+            return Void();
+        }
+    } else {
+        native_handle_t* handle =
+                const_cast<native_handle_t*>(dstBuffer.secureMemory.getNativeHandle());
+        dstPtr = static_cast<void*>(handle);
+    }
+
+    // Get a local copy of the shared_ptr for the plugin. Note that before
+    // calling the HIDL callback, this shared_ptr must be manually reset,
+    // since the client side could proceed as soon as the callback is called
+    // without waiting for this method to go out of scope.
+    std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+    if (holder.get() == nullptr) {
+        _hidl_cb(toStatus(INVALID_OPERATION), 0, NULL);
+        return Void();
+    }
+
+    // Casting hidl SubSample to DescramblerPlugin::SubSample, but need
+    // to ensure structs are actually idential
+
+    int32_t result =
+            holder->descramble(dstBuffer.type != BufferType::SHARED_MEMORY,
+                               (DescramblerPlugin::ScramblingControl)scramblingControl,
+                               subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
+                               srcPtr, srcOffset, dstPtr, dstOffset, NULL);
+
+    holder.reset();
+    _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL);
+    return Void();
+}
+
+Return<Status> DescramblerImpl::release() {
+    ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+    std::shared_ptr<DescramblerPlugin> holder(nullptr);
+    std::atomic_store(&mPluginHolder, holder);
+
+    return Status::OK;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.2/default/DescramblerImpl.h b/cas/1.2/default/DescramblerImpl.h
new file mode 100644
index 0000000..011eace
--- /dev/null
+++ b/cas/1.2/default/DescramblerImpl.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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
+#define ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
+
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+struct DescramblerPlugin;
+using namespace hardware::cas::native::V1_0;
+
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasSessionId;
+using ::android::hardware::cas::V1_0::Status;
+
+class SharedLibrary;
+
+class DescramblerImpl : public IDescrambler {
+  public:
+    DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin* plugin);
+    virtual ~DescramblerImpl();
+
+    virtual Return<Status> setMediaCasSession(const HidlCasSessionId& sessionId) override;
+
+    virtual Return<bool> requiresSecureDecoderComponent(const hidl_string& mime) override;
+
+    virtual Return<void> descramble(ScramblingControl scramblingControl,
+                                    const hidl_vec<SubSample>& subSamples,
+                                    const SharedBuffer& srcBuffer, uint64_t srcOffset,
+                                    const DestinationBuffer& dstBuffer, uint64_t dstOffset,
+                                    descramble_cb _hidl_cb) override;
+
+    virtual Return<Status> release() override;
+
+  private:
+    sp<SharedLibrary> mLibrary;
+    std::shared_ptr<DescramblerPlugin> mPluginHolder;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_DESCRAMBLER_IMPL_H_
diff --git a/cas/1.2/default/FactoryLoader.h b/cas/1.2/default/FactoryLoader.h
new file mode 100644
index 0000000..7403f86
--- /dev/null
+++ b/cas/1.2/default/FactoryLoader.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_CAS_V1_1_FACTORY_LOADER_H_
+#define ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/cas/CasAPI.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+#include "SharedLibrary.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+
+template <class T>
+class FactoryLoader {
+  public:
+    FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+    virtual ~FactoryLoader() { closeFactory(); }
+
+    bool findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library = NULL,
+                              T** factory = NULL);
+
+    bool enumeratePlugins(vector<HidlCasPluginDescriptor>* results);
+
+  private:
+    typedef T* (*CreateFactoryFunc)();
+
+    Mutex mMapLock;
+    T* mFactory;
+    const char* mCreateFactoryFuncName;
+    sp<SharedLibrary> mLibrary;
+    KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+    KeyedVector<String8, wp<SharedLibrary>> mLibraryPathToOpenLibraryMap;
+
+    bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+                                      sp<SharedLibrary>* library, T** factory);
+
+    bool queryPluginsFromPath(const String8& path, vector<HidlCasPluginDescriptor>* results);
+
+    bool openFactory(const String8& path);
+    void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id, sp<SharedLibrary>* library,
+                                            T** factory) {
+    if (library != NULL) {
+        library->clear();
+    }
+    if (factory != NULL) {
+        *factory = NULL;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    // first check cache
+    ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+    if (index >= 0) {
+        return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
+                                            library, factory);
+    }
+
+    // no luck, have to search
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
+                mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+                closedir(pDir);
+
+                return true;
+            }
+        }
+    }
+
+    closedir(pDir);
+
+    ALOGE("Failed to find plugin");
+    return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(vector<HidlCasPluginDescriptor>* results) {
+    ALOGI("enumeratePlugins");
+
+    results->clear();
+
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            queryPluginsFromPath(pluginPath, results);
+        }
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
+                                                    sp<SharedLibrary>* library, T** factory) {
+    closeFactory();
+
+    if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+        closeFactory();
+        return false;
+    }
+
+    if (library != NULL) {
+        *library = mLibrary;
+    }
+    if (factory != NULL) {
+        *factory = mFactory;
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
+                                            vector<HidlCasPluginDescriptor>* results) {
+    closeFactory();
+
+    vector<CasPluginDescriptor> descriptors;
+    if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+        closeFactory();
+        return false;
+    }
+
+    for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+        results->push_back(
+                HidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8& path) {
+    // get strong pointer to open shared library
+    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+    if (index >= 0) {
+        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+    } else {
+        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+    }
+
+    if (!mLibrary.get()) {
+        mLibrary = new SharedLibrary(path);
+        if (!*mLibrary) {
+            return false;
+        }
+
+        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+    }
+
+    CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+    if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+        return false;
+    }
+    return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+    delete mFactory;
+    mFactory = NULL;
+    mLibrary.clear();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_FACTORY_LOADER_H_
diff --git a/cas/1.2/default/MediaCasService.cpp b/cas/1.2/default/MediaCasService.cpp
new file mode 100644
index 0000000..4ecd52b
--- /dev/null
+++ b/cas/1.2/default/MediaCasService.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-MediaCasService"
+
+#include <android/hardware/cas/1.1/ICasListener.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "DescramblerImpl.h"
+#include "MediaCasService.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+class Wrapper : public V1_1::ICasListener {
+  public:
+    static sp<V1_1::ICasListener> wrap(sp<V1_0::ICasListener> impl) {
+        sp<V1_1::ICasListener> cast = V1_1::ICasListener::castFrom(impl);
+        if (cast == NULL) {
+            cast = new Wrapper(impl);
+        }
+        return cast;
+    }
+
+    virtual Return<void> onEvent(int32_t event, int32_t arg,
+                                 const hidl_vec<uint8_t>& data) override {
+        mImpl->onEvent(event, arg, data);
+        return Void();
+    }
+
+    virtual Return<void> onSessionEvent(const hidl_vec<uint8_t>& /* sessionId */,
+                                        int32_t /* event */, int32_t /* arg */,
+                                        const hidl_vec<uint8_t>& /*data*/) override {
+        ALOGV("Do nothing on Session Event for cas@1.0 client in cas@1.1");
+        return Void();
+    }
+
+  private:
+    Wrapper(sp<V1_0::ICasListener> impl) : mImpl(impl){};
+    sp<V1_0::ICasListener> mImpl;
+};
+
+MediaCasService::MediaCasService()
+    : mCasLoader("createCasFactory"), mDescramblerLoader("createDescramblerFactory") {}
+
+MediaCasService::~MediaCasService() {}
+
+Return<void> MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<HidlCasPluginDescriptor> results;
+    mCasLoader.enumeratePlugins(&results);
+
+    _hidl_cb(results);
+    return Void();
+}
+
+Return<bool> MediaCasService::isSystemIdSupported(int32_t CA_system_id) {
+    ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+    return mCasLoader.findFactoryForScheme(CA_system_id);
+}
+
+Return<sp<V1_0::ICas>> MediaCasService::createPlugin(int32_t CA_system_id,
+                                                     const sp<V1_0::ICasListener>& listener) {
+    ALOGV("%s:Use createPluginExt to create plugin in cas@1.1", __FUNCTION__);
+
+    sp<ICas> result;
+
+    sp<V1_1::ICasListener> listenerV1_1 = Wrapper::wrap(listener);
+
+    result = createPluginExt(CA_system_id, listenerV1_1);
+
+    return result;
+}
+
+Return<sp<ICas>> MediaCasService::createPluginExt(int32_t CA_system_id,
+                                                  const sp<ICasListener>& listener) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+    if (listener == NULL) ALOGV("%s: Listener is NULL", __FUNCTION__);
+
+    sp<V1_2::ICas> result;
+
+    CasFactory* factory;
+    sp<SharedLibrary> library;
+    if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+        CasPlugin* plugin = NULL;
+        sp<CasImpl> casImpl = new CasImpl(listener);
+        if (factory->createPlugin(CA_system_id, casImpl.get(), &CasImpl::CallBackExt, &plugin) ==
+                    OK &&
+            plugin != NULL) {
+            casImpl->init(library, plugin);
+            result = casImpl;
+
+            sp<V1_2::ICasListener> listenerV1_2 = V1_2::ICasListener::castFrom(listener);
+            if (listenerV1_2 != NULL) {
+                casImpl->setPluginStatusUpdateCallback();
+            }
+        }
+    }
+
+    return result;
+}
+
+Return<bool> MediaCasService::isDescramblerSupported(int32_t CA_system_id) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    return mDescramblerLoader.findFactoryForScheme(CA_system_id);
+}
+
+Return<sp<IDescramblerBase>> MediaCasService::createDescrambler(int32_t CA_system_id) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    sp<IDescrambler> result;
+
+    DescramblerFactory* factory;
+    sp<SharedLibrary> library;
+    if (mDescramblerLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+        DescramblerPlugin* plugin = NULL;
+        if (factory->createPlugin(CA_system_id, &plugin) == OK && plugin != NULL) {
+            result = new DescramblerImpl(library, plugin);
+        }
+    }
+
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.2/default/MediaCasService.h b/cas/1.2/default/MediaCasService.h
new file mode 100644
index 0000000..01e11db
--- /dev/null
+++ b/cas/1.2/default/MediaCasService.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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
+#define ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
+
+#include <android/hardware/cas/1.1/IMediaCasService.h>
+#include <android/hardware/cas/1.2/IMediaCasService.h>
+
+#include "FactoryLoader.h"
+
+namespace android {
+struct CasFactory;
+struct DescramblerFactory;
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+using ::android::hardware::cas::V1_0::IDescramblerBase;
+
+class MediaCasService : public V1_2::IMediaCasService {
+  public:
+    MediaCasService();
+
+    virtual Return<void> enumeratePlugins(enumeratePlugins_cb _hidl_cb) override;
+
+    virtual Return<bool> isSystemIdSupported(int32_t CA_system_id) override;
+
+    virtual Return<sp<V1_0::ICas>> createPlugin(int32_t CA_system_id,
+                                                const sp<V1_0::ICasListener>& listener) override;
+
+    virtual Return<sp<ICas>> createPluginExt(int32_t CA_system_id,
+                                             const sp<ICasListener>& listener) override;
+
+    virtual Return<bool> isDescramblerSupported(int32_t CA_system_id) override;
+
+    virtual Return<sp<IDescramblerBase>> createDescrambler(int32_t CA_system_id) override;
+
+  private:
+    FactoryLoader<CasFactory> mCasLoader;
+    FactoryLoader<DescramblerFactory> mDescramblerLoader;
+
+    virtual ~MediaCasService();
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_MEDIA_CAS_SERVICE_H_
diff --git a/cas/1.2/default/SharedLibrary.cpp b/cas/1.2/default/SharedLibrary.cpp
new file mode 100644
index 0000000..ffe4bb9
--- /dev/null
+++ b/cas/1.2/default/SharedLibrary.cpp
@@ -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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-SharedLibrary"
+
+#include "SharedLibrary.h"
+#include <dlfcn.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+SharedLibrary::SharedLibrary(const String8& path) {
+    mLibHandle = dlopen(path.string(), RTLD_NOW);
+}
+
+SharedLibrary::~SharedLibrary() {
+    if (mLibHandle != NULL) {
+        dlclose(mLibHandle);
+        mLibHandle = NULL;
+    }
+}
+
+bool SharedLibrary::operator!() const {
+    return mLibHandle == NULL;
+}
+
+void* SharedLibrary::lookup(const char* symbol) const {
+    if (!mLibHandle) {
+        return NULL;
+    }
+    // Clear last error before we load the symbol again,
+    // in case the caller didn't retrieve it.
+    (void)dlerror();
+    return dlsym(mLibHandle, symbol);
+}
+
+const char* SharedLibrary::lastError() const {
+    const char* error = dlerror();
+    return error ? error : "No errors or unknown error";
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.2/default/SharedLibrary.h b/cas/1.2/default/SharedLibrary.h
new file mode 100644
index 0000000..b85f557
--- /dev/null
+++ b/cas/1.2/default/SharedLibrary.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.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
+#define ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+class SharedLibrary : public RefBase {
+  public:
+    explicit SharedLibrary(const String8& path);
+    ~SharedLibrary();
+
+    bool operator!() const;
+    void* lookup(const char* symbol) const;
+    const char* lastError() const;
+
+  private:
+    void* mLibHandle;
+    DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_SHARED_LIBRARY_H_
diff --git a/cas/1.2/default/TypeConvert.cpp b/cas/1.2/default/TypeConvert.cpp
new file mode 100644
index 0000000..c4bd0dd
--- /dev/null
+++ b/cas/1.2/default/TypeConvert.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.1-TypeConvert"
+
+#include "TypeConvert.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+Status toStatus(status_t legacyStatus) {
+    Status status;
+    switch (legacyStatus) {
+        case android::OK:
+            status = Status::OK;
+            break;
+        case android::ERROR_CAS_NO_LICENSE:
+            status = Status::ERROR_CAS_NO_LICENSE;
+            break;
+        case android::ERROR_CAS_LICENSE_EXPIRED:
+            status = Status::ERROR_CAS_LICENSE_EXPIRED;
+            break;
+        case android::ERROR_CAS_SESSION_NOT_OPENED:
+            status = Status::ERROR_CAS_SESSION_NOT_OPENED;
+            break;
+        case android::ERROR_CAS_CANNOT_HANDLE:
+            status = Status::ERROR_CAS_CANNOT_HANDLE;
+            break;
+        case android::ERROR_CAS_TAMPER_DETECTED:
+            status = Status::ERROR_CAS_INVALID_STATE;
+            break;
+        case android::BAD_VALUE:
+            status = Status::BAD_VALUE;
+            break;
+        case android::ERROR_CAS_NOT_PROVISIONED:
+            status = Status::ERROR_CAS_NOT_PROVISIONED;
+            break;
+        case android::ERROR_CAS_RESOURCE_BUSY:
+            status = Status::ERROR_CAS_RESOURCE_BUSY;
+            break;
+        case android::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
+            status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION;
+            break;
+        case android::ERROR_CAS_DEVICE_REVOKED:
+            status = Status::ERROR_CAS_DEVICE_REVOKED;
+            break;
+        case android::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
+            status = Status::ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
+            break;
+        case android::ERROR_CAS_DECRYPT:
+            status = Status::ERROR_CAS_DECRYPT;
+            break;
+        default:
+            ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", legacyStatus);
+            status = Status::ERROR_CAS_UNKNOWN;
+            break;
+    }
+    return status;
+}
+
+V1_2::Status toStatus_1_2(status_t legacyStatus) {
+    V1_2::Status status = static_cast<V1_2::Status>(toStatus(legacyStatus));
+    if (status == V1_2::Status::ERROR_CAS_UNKNOWN) {
+        switch (legacyStatus) {
+            case android::ERROR_CAS_NEED_ACTIVATION:
+                status = V1_2::Status::ERROR_CAS_NEED_ACTIVATION;
+                break;
+            case android::ERROR_CAS_NEED_PAIRING:
+                status = V1_2::Status::ERROR_CAS_NEED_PAIRING;
+                break;
+            case android::ERROR_CAS_NO_CARD:
+                status = V1_2::Status::ERROR_CAS_NO_CARD;
+                break;
+            case android::ERROR_CAS_CARD_MUTE:
+                status = V1_2::Status::ERROR_CAS_CARD_MUTE;
+                break;
+            case android::ERROR_CAS_CARD_INVALID:
+                status = V1_2::Status::ERROR_CAS_CARD_INVALID;
+                break;
+            case android::ERROR_CAS_BLACKOUT:
+                status = V1_2::Status::ERROR_CAS_BLACKOUT;
+                break;
+        }
+    }
+    return status;
+}
+
+String8 sessionIdToString(const CasSessionId& sessionId) {
+    String8 result;
+    for (size_t i = 0; i < sessionId.size(); i++) {
+        result.appendFormat("%02x ", sessionId[i]);
+    }
+    if (result.isEmpty()) {
+        result.append("(null)");
+    }
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.2/default/TypeConvert.h b/cas/1.2/default/TypeConvert.h
new file mode 100644
index 0000000..018f310
--- /dev/null
+++ b/cas/1.2/default/TypeConvert.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
+#define ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
+
+#include <android/hardware/cas/1.0/types.h>
+#include <android/hardware/cas/1.2/types.h>
+#include <media/cas/CasAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::cas::V1_0::Status;
+
+Status toStatus(status_t legacyStatus);
+
+V1_2::Status toStatus_1_2(status_t legacyStatus);
+
+String8 sessionIdToString(const CasSessionId& sessionId);
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAS_V1_1_TYPE_CONVERT_H
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
new file mode 100644
index 0000000..1c75100
--- /dev/null
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
@@ -0,0 +1,11 @@
+service vendor.cas-hal-1-2 /vendor/bin/hw/android.hardware.cas@1.2-service-lazy
+    interface android.hardware.cas@1.0::IMediaCasService default
+    interface android.hardware.cas@1.1::IMediaCasService default
+    interface android.hardware.cas@1.2::IMediaCasService default
+    oneshot
+    disabled
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
new file mode 100644
index 0000000..9b36406
--- /dev/null
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.cas</name>
+        <transport>hwbinder</transport>
+        <version>1.2</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.rc b/cas/1.2/default/android.hardware.cas@1.2-service.rc
new file mode 100644
index 0000000..d1c853e
--- /dev/null
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.rc
@@ -0,0 +1,6 @@
+service vendor.cas-hal-1-2 /vendor/bin/hw/android.hardware.cas@1.2-service
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.xml b/cas/1.2/default/android.hardware.cas@1.2-service.xml
new file mode 100644
index 0000000..9b36406
--- /dev/null
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.cas</name>
+        <transport>hwbinder</transport>
+        <version>1.2</version>
+        <interface>
+            <name>IMediaCasService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/cas/1.2/default/service.cpp b/cas/1.2/default/service.cpp
new file mode 100644
index 0000000..a623447
--- /dev/null
+++ b/cas/1.2/default/service.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.cas@1.1-service-lazy"
+#else
+#define LOG_TAG "android.hardware.cas@1.1-service"
+#endif
+
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+#include "MediaCasService.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::cas::V1_1::implementation::MediaCasService;
+using android::hardware::cas::V1_2::IMediaCasService;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main() {
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    android::sp<IMediaCasService> service = new MediaCasService();
+    android::status_t status;
+    if (kLazyService) {
+        auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(service);
+    } else {
+        status = service->registerAsService();
+    }
+    LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering cas service: %d", status);
+
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/cas/1.2/types.hal b/cas/1.2/types.hal
new file mode 100644
index 0000000..40c06cf
--- /dev/null
+++ b/cas/1.2/types.hal
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas@1.2;
+
+import android.hardware.cas@1.0;
+import android.hardware.cas@1.1;
+
+enum Status : @1.0::Status {
+    /**
+     * ERROR_CAS_NEED_ACTIVATION is used to trigger device activation process.
+     */
+    ERROR_CAS_NEED_ACTIVATION,
+    /**
+     * ERROR_CAS_NEED_PAIRING is used to trigger pairing process.
+     */
+    ERROR_CAS_NEED_PAIRING,
+    /**
+     * ERROR_CAS_NO_CARD is used to report no smart card for descrambling.
+     */
+    ERROR_CAS_NO_CARD,
+    /**
+     * ERROR_CAS_CARD_MUTE is used to report smart card is muted for
+     * descrambling.
+     */
+    ERROR_CAS_CARD_MUTE,
+    /**
+     *  ERROR_CAS_CARD_INVALID is used to report smart card isn't valid.
+     */
+    ERROR_CAS_CARD_INVALID,
+    /**
+     *  ERROR_CAS_BLACKOUT is used to report geographical blackout.
+     */
+    ERROR_CAS_BLACKOUT,
+};
+
+/**
+ * The intented usage for the session.
+ */
+enum SessionIntent : uint32_t {
+    /**
+     * Live Stream.
+     */
+    LIVE,
+    /**
+     * Playback Recorded Stream.
+     */
+    PLAYBACK,
+    /**
+     * Record Live Stream.
+     */
+    RECORD,
+    /**
+     * View the content with Time Shift capability
+     */
+    TIMESHIFT,
+};
+
+/**
+ * The Scrambling Mode.
+ */
+enum ScramblingMode : uint32_t {
+    RESERVED = 0,
+    /**
+     * DVB (Digital Video Broadcasting) CSA1 (Common Scrambling Algorithm 1) is
+     * the default mode and shall be used when the scrambling descriptor
+     * is not present in the program map section. DVB scrambling mode is
+     * specified in ETSI EN 300 468 specification.
+     */
+    DVB_CSA1,
+    DVB_CSA2,
+    /**
+     * DVB-CSA3 in standard mode.
+     */
+    DVB_CSA3_STANDARD,
+    /**
+     * DVB-CSA3 in minimally enhanced mode.
+     */
+    DVB_CSA3_MINIMAL,
+    /**
+     * DVB-CSA3 in fully enhanced mode.
+     */
+    DVB_CSA3_ENHANCE,
+    /**
+     * DVB-CISSA version 1.
+     */
+    DVB_CISSA_V1,
+    /**
+     * ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
+     */
+    DVB_IDSA,
+    /**
+     * a symmetric key algorithm.
+     */
+    MULTI2,
+    /**
+     * Advanced Encryption System (AES) 128-bit Encryption mode.
+     */
+    AES128,
+    /**
+     * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
+     */
+    AES_ECB,
+    /**
+     * Advanced Encryption System (AES) Society of Cable Telecommunications
+     * Engineers (SCTE) 52 mode.
+     */
+    AES_SCTE52,
+    /**
+     * Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
+     */
+    TDES_ECB,
+    /**
+     * Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications
+     * Engineers (SCTE) 52 mode.
+     */
+    TDES_SCTE52,
+ };
+
+/**
+ * The Event Type for status change.
+ */
+enum StatusEvent : uint8_t {
+    /**
+     * The status of CAS plugin was changed due to physical module insertion or
+     * removal. Client must call enumeratePlugins to update plugins' status.
+     */
+    PLUGIN_PHYSICAL_MODULE_CHANGED,
+    /**
+     * The status of supported session number was changed due to physical module
+     * insertion or removal. Client must update session resource according to
+     * latest StatusMessage from the StatusEvent. The plugin supports unlimited
+     * sesssion by default.
+     */
+    PLUGIN_SESSION_NUMBER_CHANGED,
+};
diff --git a/cas/1.2/vts/functional/Android.bp b/cas/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..9bc372c
--- /dev/null
+++ b/cas/1.2/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalCasV1_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalCasV1_2TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.cas@1.0",
+        "android.hardware.cas@1.1",
+        "android.hardware.cas@1.2",
+        "android.hardware.cas.native@1.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlallocatorutils",
+        "libhidlmemory",
+    ],
+    shared_libs: [
+        "libbinder",
+    ],
+    test_suites: ["general-tests"],
+}
+
diff --git a/cas/1.2/vts/functional/OWNERS b/cas/1.2/vts/functional/OWNERS
new file mode 100644
index 0000000..29246ed
--- /dev/null
+++ b/cas/1.2/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+nchalko@google.com
+chz@google.com
+quxiangfang@google.com
diff --git a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
new file mode 100644
index 0000000..8439ceb
--- /dev/null
+++ b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "mediacas_hidl_hal_test"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/cas/1.0/IDescramblerBase.h>
+#include <android/hardware/cas/1.0/types.h>
+#include <android/hardware/cas/1.2/ICas.h>
+#include <android/hardware/cas/1.2/ICasListener.h>
+#include <android/hardware/cas/1.2/IMediaCasService.h>
+#include <android/hardware/cas/1.2/types.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/cas/native/1.0/types.h>
+#include <binder/MemoryDealer.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#define CLEAR_KEY_SYSTEM_ID 0xF6D8
+#define INVALID_SYSTEM_ID 0
+#define WAIT_TIMEOUT 3000000000
+
+#define PROVISION_STR                                      \
+    "{                                                   " \
+    "  \"id\": 21140844,                                 " \
+    "  \"name\": \"Test Title\",                         " \
+    "  \"lowercase_organization_name\": \"Android\",     " \
+    "  \"asset_key\": {                                  " \
+    "  \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\"  " \
+    "  },                                                " \
+    "  \"cas_type\": 1,                                  " \
+    "  \"track_types\": [ ]                              " \
+    "}                                                   "
+
+using android::Condition;
+using android::IMemory;
+using android::IMemoryHeap;
+using android::MemoryDealer;
+using android::Mutex;
+using android::sp;
+using android::hardware::fromHeap;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::HidlMemory;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::cas::native::V1_0::BufferType;
+using android::hardware::cas::native::V1_0::DestinationBuffer;
+using android::hardware::cas::native::V1_0::IDescrambler;
+using android::hardware::cas::native::V1_0::ScramblingControl;
+using android::hardware::cas::native::V1_0::SharedBuffer;
+using android::hardware::cas::native::V1_0::SubSample;
+using android::hardware::cas::V1_0::HidlCasPluginDescriptor;
+using android::hardware::cas::V1_0::IDescramblerBase;
+using android::hardware::cas::V1_0::Status;
+using android::hardware::cas::V1_2::ICas;
+using android::hardware::cas::V1_2::ICasListener;
+using android::hardware::cas::V1_2::IMediaCasService;
+using android::hardware::cas::V1_2::ScramblingMode;
+using android::hardware::cas::V1_2::SessionIntent;
+using android::hardware::cas::V1_2::StatusEvent;
+
+namespace {
+
+const uint8_t kEcmBinaryBuffer[] = {
+        0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x46, 0x00,
+        0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00,
+        0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60, 0x4f,
+        0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+        0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c,
+        0x62, 0x19, 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48,
+};
+
+const SubSample kSubSamples[] = {{162, 0}, {0, 184}, {0, 184}};
+
+const uint8_t kInBinaryBuffer[] = {
+        0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+        0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+        0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+        0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+        0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+        0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+        0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+        0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+        0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+        0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+        0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x6e, 0x45, 0x21,
+        0x82, 0x38, 0xf0, 0x9d, 0x7d, 0x96, 0xe6, 0x94, 0xae, 0xe2, 0x87, 0x8f, 0x04, 0x49, 0xe5,
+        0xf6, 0x8c, 0x8b, 0x9a, 0x10, 0x18, 0xba, 0x94, 0xe9, 0x22, 0x31, 0x04, 0x7e, 0x60, 0x5b,
+        0xc4, 0x24, 0x00, 0x90, 0x62, 0x0d, 0xdc, 0x85, 0x74, 0x75, 0x78, 0xd0, 0x14, 0x08, 0xcb,
+        0x02, 0x1d, 0x7d, 0x9d, 0x34, 0xe8, 0x81, 0xb9, 0xf7, 0x09, 0x28, 0x79, 0x29, 0x8d, 0xe3,
+        0x14, 0xed, 0x5f, 0xca, 0xaf, 0xf4, 0x1c, 0x49, 0x15, 0xe1, 0x80, 0x29, 0x61, 0x76, 0x80,
+        0x43, 0xf8, 0x58, 0x53, 0x40, 0xd7, 0x31, 0x6d, 0x61, 0x81, 0x41, 0xe9, 0x77, 0x9f, 0x9c,
+        0xe1, 0x6d, 0xf2, 0xee, 0xd9, 0xc8, 0x67, 0xd2, 0x5f, 0x48, 0x73, 0xe3, 0x5c, 0xcd, 0xa7,
+        0x45, 0x58, 0xbb, 0xdd, 0x28, 0x1d, 0x68, 0xfc, 0xb4, 0xc6, 0xf6, 0x92, 0xf6, 0x30, 0x03,
+        0xaa, 0xe4, 0x32, 0xf6, 0x34, 0x51, 0x4b, 0x0f, 0x8c, 0xf9, 0xac, 0x98, 0x22, 0xfb, 0x49,
+        0xc8, 0xbf, 0xca, 0x8c, 0x80, 0x86, 0x5d, 0xd7, 0xa4, 0x52, 0xb1, 0xd9, 0xa6, 0x04, 0x4e,
+        0xb3, 0x2d, 0x1f, 0xb8, 0x35, 0xcc, 0x45, 0x6d, 0x9c, 0x20, 0xa7, 0xa4, 0x34, 0x59, 0x72,
+        0xe3, 0xae, 0xba, 0x49, 0xde, 0xd1, 0xaa, 0xee, 0x3d, 0x77, 0xfc, 0x5d, 0xc6, 0x1f, 0x9d,
+        0xac, 0xc2, 0x15, 0x66, 0xb8, 0xe1, 0x54, 0x4e, 0x74, 0x93, 0xdb, 0x9a, 0x24, 0x15, 0x6e,
+        0x20, 0xa3, 0x67, 0x3e, 0x5a, 0x24, 0x41, 0x5e, 0xb0, 0xe6, 0x35, 0x87, 0x1b, 0xc8, 0x7a,
+        0xf9, 0x77, 0x65, 0xe0, 0x01, 0xf2, 0x4c, 0xe4, 0x2b, 0xa9, 0x64, 0x96, 0x96, 0x0b, 0x46,
+        0xca, 0xea, 0x79, 0x0e, 0x78, 0xa3, 0x5f, 0x43, 0xfc, 0x47, 0x6a, 0x12, 0xfa, 0xc4, 0x33,
+        0x0e, 0x88, 0x1c, 0x19, 0x3a, 0x00, 0xc3, 0x4e, 0xb5, 0xd8, 0xfa, 0x8e, 0xf1, 0xbc, 0x3d,
+        0xb2, 0x7e, 0x50, 0x8d, 0x67, 0xc3, 0x6b, 0xed, 0xe2, 0xea, 0xa6, 0x1f, 0x25, 0x24, 0x7c,
+        0x94, 0x74, 0x50, 0x49, 0xe3, 0xc6, 0x58, 0x2e, 0xfd, 0x28, 0xb4, 0xc6, 0x73, 0xb1, 0x53,
+        0x74, 0x27, 0x94, 0x5c, 0xdf, 0x69, 0xb7, 0xa1, 0xd7, 0xf5, 0xd3, 0x8a, 0x2c, 0x2d, 0xb4,
+        0x5e, 0x8a, 0x16, 0x14, 0x54, 0x64, 0x6e, 0x00, 0x6b, 0x11, 0x59, 0x8a, 0x63, 0x38, 0x80,
+        0x76, 0xc3, 0xd5, 0x59, 0xf7, 0x3f, 0xd2, 0xfa, 0xa5, 0xca, 0x82, 0xff, 0x4a, 0x62, 0xf0,
+        0xe3, 0x42, 0xf9, 0x3b, 0x38, 0x27, 0x8a, 0x89, 0xaa, 0x50, 0x55, 0x4b, 0x29, 0xf1, 0x46,
+        0x7c, 0x75, 0xef, 0x65, 0xaf, 0x9b, 0x0d, 0x6d, 0xda, 0x25, 0x94, 0x14, 0xc1, 0x1b, 0xf0,
+        0xc5, 0x4c, 0x24, 0x0e, 0x65,
+};
+
+const uint8_t kOutRefBinaryBuffer[] = {
+        0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
+        0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
+        0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
+        0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
+        0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
+        0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
+        0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
+        0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
+        0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+        0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
+        0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
+        0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
+        0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
+        0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
+        0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
+        0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
+        0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
+        0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
+        0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
+        0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
+        0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
+        0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
+        0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
+        0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
+        0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
+        0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
+        0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
+        0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
+        0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
+        0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
+        0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
+        0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
+        0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
+        0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
+        0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
+        0x73, 0x63, 0x65, 0x6e, 0x65,
+};
+
+class MediaCasListener : public ICasListener {
+  public:
+    virtual Return<void> onEvent(int32_t event, int32_t arg,
+                                 const hidl_vec<uint8_t>& data) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mEvent = event;
+        mEventArg = arg;
+        mEventData = data;
+
+        mEventReceived = true;
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    virtual Return<void> onSessionEvent(const hidl_vec<uint8_t>& sessionId, int32_t event,
+                                        int32_t arg, const hidl_vec<uint8_t>& data) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mSessionId = sessionId;
+        mEvent = event;
+        mEventArg = arg;
+        mEventData = data;
+
+        mEventReceived = true;
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    virtual Return<void> onStatusUpdate(StatusEvent event, int32_t arg) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mStatusEvent = event;
+        mEventArg = arg;
+
+        mEventReceived = true;
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    void testEventEcho(sp<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+                       hidl_vec<uint8_t>& eventData);
+
+    void testSessionEventEcho(sp<ICas>& mediaCas, const hidl_vec<uint8_t>& sessionId,
+                              int32_t& event, int32_t& eventArg, hidl_vec<uint8_t>& eventData);
+
+    void testStatusUpdate(sp<ICas>& mediaCas, std::vector<uint8_t>* sessionId, SessionIntent intent,
+                          ScramblingMode mode);
+
+  private:
+    int32_t mEvent = -1;
+    int32_t mEventArg = -1;
+    StatusEvent mStatusEvent;
+    bool mEventReceived = false;
+    hidl_vec<uint8_t> mEventData;
+    hidl_vec<uint8_t> mSessionId;
+    android::Mutex mMsgLock;
+    android::Condition mMsgCondition;
+};
+
+void MediaCasListener::testEventEcho(sp<ICas>& mediaCas, int32_t& event, int32_t& eventArg,
+                                     hidl_vec<uint8_t>& eventData) {
+    mEventReceived = false;
+    auto returnStatus = mediaCas->sendEvent(event, eventArg, eventData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "event not received within timeout";
+            return;
+        }
+    }
+
+    EXPECT_EQ(mEvent, event);
+    EXPECT_EQ(mEventArg, eventArg);
+    EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testSessionEventEcho(sp<ICas>& mediaCas, const hidl_vec<uint8_t>& sessionId,
+                                            int32_t& event, int32_t& eventArg,
+                                            hidl_vec<uint8_t>& eventData) {
+    mEventReceived = false;
+    auto returnStatus = mediaCas->sendSessionEvent(sessionId, event, eventArg, eventData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "event not received within timeout";
+            return;
+        }
+    }
+
+    EXPECT_TRUE(mSessionId == sessionId);
+    EXPECT_EQ(mEvent, event);
+    EXPECT_EQ(mEventArg, eventArg);
+    EXPECT_TRUE(mEventData == eventData);
+}
+
+void MediaCasListener::testStatusUpdate(sp<ICas>& mediaCas, std::vector<uint8_t>* sessionId,
+                                        SessionIntent intent, ScramblingMode mode) {
+    mEventReceived = false;
+    android::hardware::cas::V1_2::Status sessionStatus;
+    auto returnVoid = mediaCas->openSession_1_2(
+            intent, mode,
+            [&](android::hardware::cas::V1_2::Status status, const hidl_vec<uint8_t>& id) {
+                sessionStatus = status;
+                *sessionId = id;
+            });
+    EXPECT_TRUE(returnVoid.isOk());
+    EXPECT_EQ(android::hardware::cas::V1_2::Status::OK, sessionStatus);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mEventReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "event not received within timeout";
+            return;
+        }
+    }
+    EXPECT_EQ(mStatusEvent, static_cast<StatusEvent>(intent));
+    EXPECT_EQ(mEventArg, static_cast<int32_t>(mode));
+}
+
+// Test environment for Cas HIDL HAL.
+class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    // get the test environment singleton
+    static CasHidlEnvironment* Instance() {
+        static CasHidlEnvironment* instance = new CasHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
+};
+
+class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+  public:
+    virtual void SetUp() override {
+        mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
+                CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+        ASSERT_NE(mService, nullptr);
+    }
+
+    sp<IMediaCasService> mService;
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<ICas> mMediaCas;
+    sp<IDescramblerBase> mDescramblerBase;
+    sp<MediaCasListener> mCasListener;
+    typedef struct _OobInputTestParams {
+        const SubSample* subSamples;
+        uint32_t numSubSamples;
+        size_t imemSizeActual;
+        uint64_t imemOffset;
+        uint64_t imemSize;
+        uint64_t srcOffset;
+        uint64_t dstOffset;
+    } OobInputTestParams;
+
+    ::testing::AssertionResult createCasPlugin(int32_t caSystemId);
+    ::testing::AssertionResult openCasSession(std::vector<uint8_t>* sessionId);
+    ::testing::AssertionResult openCasSession_1_2(std::vector<uint8_t>* sessionId,
+                                                  SessionIntent intent, ScramblingMode mode);
+    ::testing::AssertionResult descrambleTestInputBuffer(const sp<IDescrambler>& descrambler,
+                                                         Status* descrambleStatus,
+                                                         sp<IMemory>* hidlInMemory);
+    ::testing::AssertionResult descrambleTestOobInput(const sp<IDescrambler>& descrambler,
+                                                      Status* descrambleStatus,
+                                                      const OobInputTestParams& params);
+};
+
+::testing::AssertionResult MediaCasHidlTest::createCasPlugin(int32_t caSystemId) {
+    auto status = mService->isSystemIdSupported(caSystemId);
+    if (!status.isOk() || !status) {
+        return ::testing::AssertionFailure();
+    }
+    status = mService->isDescramblerSupported(caSystemId);
+    if (!status.isOk() || !status) {
+        return ::testing::AssertionFailure();
+    }
+
+    mCasListener = new MediaCasListener();
+    auto pluginStatus = mService->createPluginExt(caSystemId, mCasListener);
+    if (!pluginStatus.isOk()) {
+        return ::testing::AssertionFailure();
+    }
+    mMediaCas = ICas::castFrom(pluginStatus);
+    if (mMediaCas == nullptr) {
+        return ::testing::AssertionFailure();
+    }
+
+    auto descramblerStatus = mService->createDescrambler(caSystemId);
+    if (!descramblerStatus.isOk()) {
+        return ::testing::AssertionFailure();
+    }
+    mDescramblerBase = descramblerStatus;
+    return ::testing::AssertionResult(mDescramblerBase != nullptr);
+}
+
+::testing::AssertionResult MediaCasHidlTest::openCasSession(std::vector<uint8_t>* sessionId) {
+    Status sessionStatus;
+    auto returnVoid = mMediaCas->openSession([&](Status status, const hidl_vec<uint8_t>& id) {
+        sessionStatus = status;
+        *sessionId = id;
+    });
+    return ::testing::AssertionResult(returnVoid.isOk() && (Status::OK == sessionStatus));
+}
+
+::testing::AssertionResult MediaCasHidlTest::descrambleTestInputBuffer(
+        const sp<IDescrambler>& descrambler, Status* descrambleStatus, sp<IMemory>* inMemory) {
+    hidl_vec<SubSample> hidlSubSamples;
+    hidlSubSamples.setToExternal(const_cast<SubSample*>(kSubSamples),
+                                 (sizeof(kSubSamples) / sizeof(SubSample)), false /*own*/);
+
+    sp<MemoryDealer> dealer = new MemoryDealer(sizeof(kInBinaryBuffer), "vts-cas");
+    if (nullptr == dealer.get()) {
+        ALOGE("couldn't get MemoryDealer!");
+        return ::testing::AssertionFailure();
+    }
+
+    sp<IMemory> mem = dealer->allocate(sizeof(kInBinaryBuffer));
+    if (nullptr == mem.get()) {
+        ALOGE("couldn't allocate IMemory!");
+        return ::testing::AssertionFailure();
+    }
+    *inMemory = mem;
+
+    // build HidlMemory from memory heap
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+    if (nullptr == heap.get()) {
+        ALOGE("couldn't get memory heap!");
+        return ::testing::AssertionFailure();
+    }
+
+    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!
+    sp<HidlMemory> hidlMemory = fromHeap(heap);
+
+    SharedBuffer srcBuffer = {
+            .heapBase = *hidlMemory, .offset = (uint64_t)offset, .size = (uint64_t)size};
+
+    DestinationBuffer dstBuffer;
+    dstBuffer.type = BufferType::SHARED_MEMORY;
+    dstBuffer.nonsecureMemory = srcBuffer;
+
+    uint32_t outBytes;
+    hidl_string detailedError;
+    auto returnVoid = descrambler->descramble(
+            ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, 0, dstBuffer, 0,
+            [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) {
+                *descrambleStatus = status;
+                outBytes = bytesWritten;
+                detailedError = detailedErr;
+            });
+    if (!returnVoid.isOk() || *descrambleStatus != Status::OK) {
+        ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s",
+              returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str());
+    }
+    return ::testing::AssertionResult(returnVoid.isOk());
+}
+
+::testing::AssertionResult MediaCasHidlTest::descrambleTestOobInput(
+        const sp<IDescrambler>& descrambler, Status* descrambleStatus,
+        const OobInputTestParams& params) {
+    hidl_vec<SubSample> hidlSubSamples;
+    hidlSubSamples.setToExternal(const_cast<SubSample*>(params.subSamples), params.numSubSamples,
+                                 false /*own*/);
+
+    sp<MemoryDealer> dealer = new MemoryDealer(params.imemSizeActual, "vts-cas");
+    if (nullptr == dealer.get()) {
+        ALOGE("couldn't get MemoryDealer!");
+        return ::testing::AssertionFailure();
+    }
+
+    sp<IMemory> mem = dealer->allocate(params.imemSizeActual);
+    if (nullptr == mem.get()) {
+        ALOGE("couldn't allocate IMemory!");
+        return ::testing::AssertionFailure();
+    }
+
+    // build HidlMemory from memory heap
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+    if (nullptr == heap.get()) {
+        ALOGE("couldn't get memory heap!");
+        return ::testing::AssertionFailure();
+    }
+
+    // hidlMemory is not to be passed out of scope!
+    sp<HidlMemory> hidlMemory = fromHeap(heap);
+
+    SharedBuffer srcBuffer = {
+            .heapBase = *hidlMemory,
+            .offset = (uint64_t)offset + params.imemOffset,
+            .size = (uint64_t)params.imemSize,
+    };
+
+    DestinationBuffer dstBuffer;
+    dstBuffer.type = BufferType::SHARED_MEMORY;
+    dstBuffer.nonsecureMemory = srcBuffer;
+
+    uint32_t outBytes;
+    hidl_string detailedError;
+    auto returnVoid = descrambler->descramble(
+            ScramblingControl::EVENKEY /*2*/, hidlSubSamples, srcBuffer, params.srcOffset,
+            dstBuffer, params.dstOffset,
+            [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) {
+                *descrambleStatus = status;
+                outBytes = bytesWritten;
+                detailedError = detailedErr;
+            });
+    if (!returnVoid.isOk() || *descrambleStatus != Status::OK) {
+        ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s",
+              returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str());
+    }
+    return ::testing::AssertionResult(returnVoid.isOk());
+}
+
+TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) {
+    description("Test that valid call sequences with SessionEvent send and receive");
+
+    ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+    auto returnStatus = mMediaCas->provision(hidl_string(PROVISION_STR));
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    hidl_vec<uint8_t> hidlPvtData;
+    hidlPvtData.resize(256);
+    returnStatus = mMediaCas->setPrivateData(hidlPvtData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    std::vector<uint8_t> sessionId;
+    ASSERT_TRUE(openCasSession(&sessionId));
+    returnStatus = mMediaCas->setSessionPrivateData(sessionId, hidlPvtData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    std::vector<uint8_t> streamSessionId;
+    ASSERT_TRUE(openCasSession(&streamSessionId));
+    returnStatus = mMediaCas->setSessionPrivateData(streamSessionId, hidlPvtData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    returnStatus = mDescramblerBase->setMediaCasSession(sessionId);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    returnStatus = mDescramblerBase->setMediaCasSession(streamSessionId);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    hidl_vec<uint8_t> hidlNullPtr;
+    hidlNullPtr.setToExternal(static_cast<uint8_t*>(nullptr), 0);
+    returnStatus = mMediaCas->refreshEntitlements(3, hidlNullPtr);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    uint8_t refreshData[] = {0, 1, 2, 3};
+    hidl_vec<uint8_t> hidlRefreshData;
+    hidlRefreshData.setToExternal(static_cast<uint8_t*>(refreshData), sizeof(refreshData));
+    returnStatus = mMediaCas->refreshEntitlements(10, hidlRefreshData);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    int32_t eventID = 1;
+    int32_t eventArg = 2;
+    mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlNullPtr);
+    mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, hidlNullPtr);
+
+    eventID = 3;
+    eventArg = 4;
+    uint8_t eventData[] = {'e', 'v', 'e', 'n', 't', 'd', 'a', 't', 'a'};
+    hidl_vec<uint8_t> hidlEventData;
+    hidlEventData.setToExternal(static_cast<uint8_t*>(eventData), sizeof(eventData));
+    mCasListener->testEventEcho(mMediaCas, eventID, eventArg, hidlEventData);
+    mCasListener->testSessionEventEcho(mMediaCas, sessionId, eventID, eventArg, hidlEventData);
+
+    SessionIntent intent = SessionIntent::LIVE;
+    ScramblingMode mode = ScramblingMode::DVB_CSA1;
+    mCasListener->testStatusUpdate(mMediaCas, &sessionId, intent, mode);
+
+    uint8_t clearKeyEmmData[] = {'c', 'l', 'e', 'a', 'r', 'k', 'e', 'y', 'e', 'm', 'm'};
+    hidl_vec<uint8_t> hidlClearKeyEmm;
+    hidlClearKeyEmm.setToExternal(static_cast<uint8_t*>(clearKeyEmmData), sizeof(clearKeyEmmData));
+    returnStatus = mMediaCas->processEmm(hidlClearKeyEmm);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    hidl_vec<uint8_t> hidlEcm;
+    hidlEcm.setToExternal(const_cast<uint8_t*>(kEcmBinaryBuffer), sizeof(kEcmBinaryBuffer));
+    returnStatus = mMediaCas->processEcm(sessionId, hidlEcm);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+    returnStatus = mMediaCas->processEcm(streamSessionId, hidlEcm);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("video/avc"));
+
+    sp<IDescrambler> descrambler;
+    descrambler = IDescrambler::castFrom(mDescramblerBase);
+    ASSERT_NE(descrambler, nullptr);
+
+    Status descrambleStatus = Status::OK;
+    sp<IMemory> dataMemory;
+
+    ASSERT_TRUE(descrambleTestInputBuffer(descrambler, &descrambleStatus, &dataMemory));
+    EXPECT_EQ(Status::OK, descrambleStatus);
+
+    ASSERT_NE(nullptr, dataMemory.get());
+    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), sizeof(kOutRefBinaryBuffer));
+    EXPECT_EQ(0, compareResult);
+
+    returnStatus = mDescramblerBase->release();
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    returnStatus = mMediaCas->release();
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+}
+
+}  // 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;
+}
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 9d68264..8ffed4b 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -10,6 +10,7 @@
     <hal format="hidl" optional="false">
         <name>android.hardware.audio</name>
         <version>5.0</version>
+        <version>6.0</version>
         <interface>
             <name>IDevicesFactory</name>
             <instance>default</instance>
@@ -18,6 +19,7 @@
     <hal format="hidl" optional="false">
         <name>android.hardware.audio.effect</name>
         <version>5.0</version>
+        <version>6.0</version>
         <interface>
             <name>IEffectsFactory</name>
             <instance>default</instance>
@@ -195,8 +197,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>
@@ -204,7 +206,7 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.graphics.composer</name>
-        <version>2.1-3</version>
+        <version>2.1-4</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>
@@ -212,8 +214,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>
@@ -498,7 +500,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>
@@ -514,7 +516,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 8953d51..e22db18 100644
--- a/current.txt
+++ b/current.txt
@@ -572,6 +572,7 @@
 cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardware.wifi.supplicant@1.2::types
 
 # ABI preserving changes to HALs during Android R
+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
@@ -594,6 +595,12 @@
 544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator
 5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback
 033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types
+3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
+a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
+0a7ff83fd0326b82232e1609da98f34960be11335df72fc407ad238d7bd0e081 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
+619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
+c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
+b0f8c9cd61a45a8c1b4a8e40913ecaea0921011cbe2305a6fa5a2feaa0d36c30 android.hardware.wifi.supplicant@1.3::types
 41c602462ccd1b19cfd645994be4de4c07fc197ff58a54e84476b31908e61e21 android.hardware.radio@1.5::types
 a8691c71747c3f14f7a043598e856425077f755e55990507a9132ad62f8ab3f7 android.hardware.radio@1.5::IRadio
 a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication
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.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 f3b376e..2c8a7b1 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,60 +175,41 @@
     return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
 }
 
-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 84a9f84..169cd62 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -19,46 +19,26 @@
 
 #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::GnssLocationFlags;
 using android::hardware::gnss::V1_1::IGnss;
 using android::hardware::gnss::V1_1::IGnssCallback;
-using android::hardware::gnss::V1_0::GnssLocationFlags;
 
 using android::sp;
 
 #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;
@@ -72,32 +52,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;
     };
 
     /*
@@ -152,26 +140,7 @@
     bool IsGnssHalVersion_1_1() const;
 
     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 ee236ba..79da84a 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,7 +361,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 (!IsGnssHalVersion_1_1()) {
         ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
         return;
@@ -347,16 +369,22 @@
 
     const int kLocationsToAwait = 3;
 
+    gnss_cb_->location_cbq_.reset();
     StartAndCheckLocations(kLocationsToAwait);
+    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, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", sv_status_cbq_size,
+          kLocationsToAwait, location_called_count);
 
     // Find first non-GPS constellation to blacklist
+    const int kGnssSvStatusTimeout = 2;
     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, kGnssSvStatusTimeout);
         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) &&
@@ -395,16 +423,19 @@
     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(),
+    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) &&
@@ -425,9 +456,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);
@@ -444,10 +475,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/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp
index 278d87b..9aa1334 100644
--- a/gnss/2.0/vts/functional/Android.bp
+++ b/gnss/2.0/vts/functional/Android.bp
@@ -30,4 +30,5 @@
         "android.hardware.gnss@2.0",
         "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/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..9931685
--- /dev/null
+++ b/graphics/allocator/4.0/IAllocator.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.allocator@4.0;
+
+import android.hardware.graphics.mapper@4.0;
+
+interface IAllocator {
+    /**
+     * Retrieves implementation-defined debug information, which will be
+     * displayed during, for example, `dumpsys SurfaceFlinger`.
+     *
+     * @return debugInfo is a string of debug information.
+     */
+    dumpDebugInfo() generates (string debugInfo);
+
+    /**
+     * 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/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..a0745ce 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,17 @@
 
 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;
+        int32_t bytesPerPixel;
+        int32_t bytesPerStride;
+        return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel,
+                               &bytesPerStride);
+    } else if (mGralloc3) {
         IMapper3::Rect accessRegion;
         accessRegion.left = accessRegionRect.left;
         accessRegion.top = accessRegionRect.top;
@@ -371,7 +394,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 +404,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/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/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..21ba9f3 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,6 +49,9 @@
         "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",
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 02c4c9c..6a6f7de 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.
@@ -18,13 +18,17 @@
 
 #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 <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
 
 namespace android {
 namespace hardware {
@@ -34,21 +38,17 @@
 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;
-
-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};
+using vts::Gralloc;
 
 // Test environment for graphics.composer
 class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
@@ -65,93 +65,8 @@
     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 GraphicsCompositionTest : public ::testing::VtsHalHidlTargetTestBase {
+  protected:
     using PowerMode = V2_1::IComposerClient::PowerMode;
     void SetUp() override {
         VtsHalHidlTargetTestBase::SetUp();
@@ -173,6 +88,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 +99,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 {
@@ -217,10 +140,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 +147,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 +159,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,734 +182,776 @@
             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 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_F(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_F(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_F(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_F(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_F(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_F(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_F(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_F(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_F(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 GraphicsCompositionTest,
+                                         public ::testing::WithParamInterface<float> {
+  public:
     void SetUp() override {
-        GraphicsComposerReadbackTest::SetUp();
+        GraphicsCompositionTest::SetUp();
+        mTestColorModes = {ColorMode::SRGB};  // TODO: add more color mode support
         mBackgroundColor = BLACK;
         mTopLayerColor = RED;
     }
 
-    void TearDown() override { GraphicsComposerReadbackTest::TearDown(); }
+    void TearDown() override { GraphicsCompositionTest::TearDown(); }
 
     void setBackgroundColor(IComposerClient::Color color) { mBackgroundColor = color; }
 
@@ -1029,8 +960,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,6 +973,7 @@
                                                        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);
@@ -1053,7 +985,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 +1023,180 @@
     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"
+TEST_P(GraphicsBlendModeCompositionTest, 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,
+INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsBlendModeCompositionTest,
                         ::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 +1215,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,110 +1229,170 @@
     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_F(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_F(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_F(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));
 }
 
 }  // anonymous namespace
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/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/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index e421889..b729062 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,6 +41,8 @@
         "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",
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..5c3f8bd
--- /dev/null
+++ b/graphics/composer/2.4/IComposerCallback.hal
@@ -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.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);
+};
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
new file mode 100644
index 0000000..c2102d5
--- /dev/null
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -0,0 +1,159 @@
+/*
+ * 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.3::IComposerClient;
+
+interface IComposerClient extends @2.3::IComposerClient {
+    /**
+     * 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.
+     */
+    @entry
+    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);
+
+    /**
+     * Provides a list of the vsync periods supported by the display in the given configuration
+     *
+     * @param display is the display for which the vsync periods are queried.
+     * @param config is the display configuration for which the vsync periods are queried.
+     *
+     * @return error is NONE upon success. Otherwise,
+     *     BAD_DISPLAY when an invalid display handle was passed in.
+     *     BAD_CONFIG when an invalid config handle was passed in.
+     * @return supportedVsyncPeriods is a list of supported vsync periods.
+     */
+    getSupportedDisplayVsyncPeriods(Display display, Config config)
+        generates (Error error, vec<VsyncPeriodNanos> supportedVsyncPeriods);
+
+    /**
+     * 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
+     * setActiveConfigAndVsyncPeriod 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 config is the same 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 vsyncPeriodNanos is the new display vsync period.
+     * @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.
+     *         BAD_VSYNC_PERIOD when an invalid vsync period is passed in.
+     *         SEAMLESS_NOT_POSSIBLE when seamlessRequired was true but the display cannot achieve
+     *                               the vsync period change without a noticeable visual artifact.
+     * @return newVsyncAppliedTime is the time in CLOCK_MONOTONIC when the new display will start to
+     *                             refresh at the new vsync period.
+     */
+    setActiveConfigAndVsyncPeriod(Display display, Config config,
+        VsyncPeriodNanos vsyncPeriodNanos,
+        VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints)
+        generates (Error error, int64_t newVsyncAppliedTime);
+};
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..b45d7a6
--- /dev/null
+++ b/graphics/composer/2.4/types.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 @2.1::Error;
+
+enum Error : @2.1::Error {
+    /**
+     * Invalid vsync period
+     */
+    BAD_VSYNC_PERIOD = 9,
+    /**
+     * Seamless requirements cannot be met
+     */
+    SEAMLESS_NOT_POSSIBLE = 10,
+};
+
+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..ddf209b
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -0,0 +1,159 @@
+/*
+ * 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());
+        }
+
+      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> getSupportedDisplayVsyncPeriods(
+            Display display, Config config,
+            IComposerClient::getSupportedDisplayVsyncPeriods_cb hidl_cb) override {
+        std::vector<VsyncPeriodNanos> supportedVsyncPeriods;
+        Error error =
+                mHal->getSupportedDisplayVsyncPeriods(display, config, &supportedVsyncPeriods);
+        hidl_cb(error, supportedVsyncPeriods);
+        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> setActiveConfigAndVsyncPeriod(
+            Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos,
+            const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+            IComposerClient::setActiveConfigAndVsyncPeriod_cb hidl_cb) override {
+        int64_t newVsyncAppliedTime = 0;
+        Error error = mHal->setActiveConfigAndVsyncPeriod(display, config, vsyncPeriodNanos,
+                                                          vsyncPeriodChangeConstraints,
+                                                          &newVsyncAppliedTime);
+        hidl_cb(error, newVsyncAppliedTime);
+        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..0739f62
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -0,0 +1,74 @@
+/*
+ * 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 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 getSupportedDisplayVsyncPeriods(
+            Display display, Config config, std::vector<VsyncPeriodNanos>* outVsyncPeriod) = 0;
+    virtual Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) = 0;
+    virtual Error setActiveConfigAndVsyncPeriod(
+            Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos,
+            const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+            int64_t* outNewVsyncAppliedTime) = 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..3420c8c
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -0,0 +1,233 @@
+/*
+ * 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>
+
+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;
+
+        mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this,
+                                   reinterpret_cast<hwc2_function_pointer_t>(hotplugHook));
+        mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this,
+                                   reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
+        mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,
+                                   reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
+        mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this,
+                                   reinterpret_cast<hwc2_function_pointer_t>(vsync_2_4_Hook));
+    }
+
+    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
+        mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, nullptr);
+        mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, nullptr);
+        mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, nullptr);
+        mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, 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 getSupportedDisplayVsyncPeriods(Display display, Config config,
+                                          std::vector<VsyncPeriodNanos>* outVsyncPeriods) override {
+        if (!mDispatch.getSupportedDisplayVsyncPeriods) {
+            return Error::UNSUPPORTED;
+        }
+
+        uint32_t count = 0;
+        int32_t error = mDispatch.getSupportedDisplayVsyncPeriods(mDevice, display, config, &count,
+                                                                  nullptr);
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+        outVsyncPeriods->resize(count);
+        error = mDispatch.getSupportedDisplayVsyncPeriods(mDevice, display, config, &count,
+                                                          outVsyncPeriods->data());
+        if (error != HWC2_ERROR_NONE) {
+            *outVsyncPeriods = std::vector<VsyncPeriodNanos>();
+            return static_cast<Error>(error);
+        }
+        return Error::NONE;
+    }
+
+    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 setActiveConfigAndVsyncPeriod(
+            Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos,
+            const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+            int64_t* outNewVsyncAppliedTime) override {
+        if (!mDispatch.setActiveConfigAndVsyncPeriod) {
+            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;
+
+        int32_t error = mDispatch.setActiveConfigAndVsyncPeriod(
+                mDevice, display, config, vsyncPeriodNanos, &vsync_period_change_constraints,
+                outNewVsyncAppliedTime);
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+        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_REGISTER_CALLBACK, &mDispatch.registerCallback);
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_DISPLAY_VSYNC_PERIODS,
+                                   &mDispatch.getSupportedDisplayVsyncPeriods);
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD,
+                                   &mDispatch.getDisplayVsyncPeriod);
+        this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_AND_VSYNC_PERIOD,
+                                   &mDispatch.setActiveConfigAndVsyncPeriod);
+        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);
+    }
+
+  private:
+    struct {
+        HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType;
+        HWC2_PFN_REGISTER_CALLBACK registerCallback;
+        HWC2_PFN_GET_SUPPORTED_DISPLAY_VSYNC_PERIODS getSupportedDisplayVsyncPeriods;
+        HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod;
+        HWC2_PFN_SET_ACTIVE_CONFIG_AND_VSYNC_PERIOD setActiveConfigAndVsyncPeriod;
+    } 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..b02a59a
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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;
+}
+
+Error ComposerClient::getSupportedDisplayVsyncPeriods(
+        Display display, Config config, std::vector<VsyncPeriodNanos>* outSupportedVsyncPeriods) {
+    Error error = Error::NONE;
+    mClient->getSupportedDisplayVsyncPeriods(
+            display, config, [&](const auto& tmpError, const auto& tmpSupportedVsyncPeriods) {
+                error = tmpError;
+                *outSupportedVsyncPeriods = tmpSupportedVsyncPeriods;
+            });
+    return error;
+}
+
+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::setActiveConfigAndVsyncPeriod(
+        Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos,
+        const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+        int64_t* outNewVsyncAppliedTime) {
+    Error error = Error::NONE;
+    mClient->setActiveConfigAndVsyncPeriod(
+            display, config, vsyncPeriodNanos, vsyncPeriodChangeConstraints,
+            [&](const auto& tmpError, const auto& tmpNewVsyncAppliedTime) {
+                error = tmpError;
+                *outNewVsyncAppliedTime = tmpNewVsyncAppliedTime;
+            });
+    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..e8a3905
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -0,0 +1,98 @@
+/*
+ * 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);
+
+    std::unique_ptr<ComposerClient> createClient();
+
+  protected:
+    explicit Composer(const sp<IComposer>& composer);
+
+  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);
+
+    Error getSupportedDisplayVsyncPeriods(Display display, Config config,
+                                          std::vector<VsyncPeriodNanos>* outSupportedVsyncPeriods);
+
+    Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriods);
+
+    Error setActiveConfigAndVsyncPeriod(
+            Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos,
+            const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+            int64_t* outNewVsyncAppliedTime);
+
+  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..921c421
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -0,0 +1,54 @@
+//
+// 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",
+    ],
+}
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..3d967fc
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -0,0 +1,384 @@
+/*
+ * 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 <VtsHalHidlTargetTestBase.h>
+#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 <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;
+
+// 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:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(
+                mComposer = std::make_unique<Composer>(
+                        GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+        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_setActiveConfigAndVsyncPeriod(
+            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_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
+    std::vector<IComposerClient::DisplayCapability> capabilities;
+    const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities);
+    EXPECT_EQ(Error::BAD_DISPLAY, error);
+}
+
+TEST_F(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_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadDisplay) {
+    std::vector<VsyncPeriodNanos> supportedVsyncPeriods;
+    EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->getSupportedDisplayVsyncPeriods(
+                                          mInvalidDisplayId, Config(0), &supportedVsyncPeriods));
+}
+
+TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadConfig) {
+    for (Display display : mComposerCallback->getDisplays()) {
+        Config invalidConfigId = GetInvalidConfigId(display);
+        std::vector<VsyncPeriodNanos> supportedVsyncPeriods;
+        EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->getSupportedDisplayVsyncPeriods(
+                                             display, invalidConfigId, &supportedVsyncPeriods));
+    }
+}
+
+TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods) {
+    for (Display display : mComposerCallback->getDisplays()) {
+        for (Config config : mComposerClient->getDisplayConfigs(display)) {
+            std::vector<VsyncPeriodNanos> supportedVsyncPeriods;
+
+            // Get the default vsync period from the config
+            VsyncPeriodNanos defaultVsyncPeiord = mComposerClient->getDisplayAttribute(
+                    display, config, IComposerClient::Attribute::VSYNC_PERIOD);
+            // Get all supported vsync periods for this config
+            EXPECT_EQ(Error::NONE, mComposerClient->getSupportedDisplayVsyncPeriods(
+                                           display, config, &supportedVsyncPeriods));
+            // Default vsync period must be present in the list
+            EXPECT_NE(std::find(supportedVsyncPeriods.begin(), supportedVsyncPeriods.end(),
+                                defaultVsyncPeiord),
+                      supportedVsyncPeriods.end());
+
+            // Each vsync period must be unique
+            std::unordered_set<VsyncPeriodNanos> vsyncPeriodSet;
+            for (VsyncPeriodNanos vsyncPeriodNanos : supportedVsyncPeriods) {
+                EXPECT_TRUE(vsyncPeriodSet.insert(vsyncPeriodNanos).second);
+            }
+        }
+    }
+}
+
+TEST_F(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) {
+    VsyncPeriodNanos vsyncPeriodNanos;
+    EXPECT_EQ(Error::BAD_DISPLAY,
+              mComposerClient->getDisplayVsyncPeriod(mInvalidDisplayId, &vsyncPeriodNanos));
+}
+
+TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadDisplay) {
+    int64_t newVsyncAppliedTime;
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime();
+
+    EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setActiveConfigAndVsyncPeriod(
+                                          mInvalidDisplayId, Config(0), VsyncPeriodNanos(0),
+                                          constraints, &newVsyncAppliedTime));
+}
+
+TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadConfig) {
+    int64_t newVsyncAppliedTime;
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime();
+
+    for (Display display : mComposerCallback->getDisplays()) {
+        Config invalidConfigId = GetInvalidConfigId(display);
+        EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->setActiveConfigAndVsyncPeriod(
+                                             display, invalidConfigId, VsyncPeriodNanos(0),
+                                             constraints, &newVsyncAppliedTime));
+    }
+}
+
+TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadVsyncPeriod) {
+    int64_t newVsyncAppliedTime;
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime();
+
+    for (Display display : mComposerCallback->getDisplays()) {
+        for (Config config : mComposerClient->getDisplayConfigs(display)) {
+            EXPECT_EQ(Error::BAD_VSYNC_PERIOD, mComposerClient->setActiveConfigAndVsyncPeriod(
+                                                       display, config, VsyncPeriodNanos(0),
+                                                       constraints, &newVsyncAppliedTime));
+        }
+    }
+}
+
+void GraphicsComposerHidlTest::Test_setActiveConfigAndVsyncPeriod(
+        const IComposerClient::VsyncPeriodChangeConstraints& constraints) {
+    int64_t newVsyncAppliedTime;
+
+    for (Display display : mComposerCallback->getDisplays()) {
+        for (Config config : mComposerClient->getDisplayConfigs(display)) {
+            std::vector<VsyncPeriodNanos> supportedVsyncPeriods;
+
+            EXPECT_EQ(Error::NONE, mComposerClient->getSupportedDisplayVsyncPeriods(
+                                           display, config, &supportedVsyncPeriods));
+            for (VsyncPeriodNanos newVsyncPeriod : supportedVsyncPeriods) {
+                VsyncPeriodNanos vsyncPeriodNanos;
+                EXPECT_EQ(Error::NONE,
+                          mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+
+                if (vsyncPeriodNanos == newVsyncPeriod) {
+                    continue;
+                }
+
+                EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigAndVsyncPeriod(
+                                               display, config, newVsyncPeriod, constraints,
+                                               &newVsyncAppliedTime));
+
+                EXPECT_TRUE(newVsyncAppliedTime >= constraints.desiredTimeNanos);
+
+                // Refresh rate should change within a reasonable time
+                constexpr nsecs_t kReasonableTimeForChange = 1'000'000'000;  // 1 second
+                EXPECT_TRUE(newVsyncAppliedTime - constraints.desiredTimeNanos <=
+                            kReasonableTimeForChange);
+
+                while (systemTime() <= newVsyncAppliedTime) {
+                    EXPECT_EQ(Error::NONE,
+                              mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+                    if (systemTime() <= constraints.desiredTimeNanos) {
+                        EXPECT_NE(vsyncPeriodNanos, newVsyncPeriod);
+                    }
+
+                    if (vsyncPeriodNanos == newVsyncPeriod) {
+                        break;
+                    }
+                    std::this_thread::sleep_for(10ms);
+                }
+                EXPECT_EQ(Error::NONE,
+                          mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+                EXPECT_EQ(vsyncPeriodNanos, newVsyncPeriod);
+            }
+        }
+    }
+}
+
+TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod) {
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime();
+    Test_setActiveConfigAndVsyncPeriod(constraints);
+}
+
+TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_delayed) {
+    IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+    constexpr auto kDelayForChange = 300ms;
+    constraints.seamlessRequired = false;
+    constraints.desiredTimeNanos = systemTime() + kDelayForChange.count();
+    Test_setActiveConfigAndVsyncPeriod(constraints);
+}
+
+}  // namespace
+}  // namespace vts
+}  // namespace V2_4
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    using android::hardware::graphics::composer::V2_4::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/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..85c7c81
--- /dev/null
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -0,0 +1,307 @@
+/*
+ * 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 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;
+    };
+
+    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. Specifically, when layered buffers are not supported, this
+     * function must return `UNSUPPORTED` if `description.layers` is great than
+     * 1.
+     *
+     * @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.
+     *
+     * 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.
+     *
+     * On success, bytesPerPixel must contain the number of bytes per pixel in
+     * the buffer. If the bytesPerPixel is unknown or variable, a value of -1
+     * should be returned. bytesPerStride must contain the bytes per stride of
+     * the buffer. If the bytesPerStride is unknown or variable, a value of -1
+     * should be returned.
+     *
+     * 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.
+     *     - `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.
+     * @return bytesPerPixel the number of bytes per pixel in the buffer
+     * @return bytesPerStride the number of bytes per stride of the buffer
+     */
+    lock(pointer buffer,
+         uint64_t cpuUsage,
+         Rect accessRegion,
+         handle acquireFence)
+            generates (Error error,
+                       pointer data,
+                       int32_t bytesPerPixel,
+                       int32_t bytesPerStride);
+
+    /**
+     * Locks a YCbCr buffer for the specified CPU usage.
+     *
+     * This is largely the same as lock(), except that instead of returning a
+     * pointer directly to the buffer data, it returns a `YCbCrLayout` struct
+     * describing how to access the data planes.
+     *
+     * This function must 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.
+     *
+     * @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 empty 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.
+     *     - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
+     *       that locking may succeed at a later time.
+     * @return layout Data layout of the locked buffer.
+     */
+    lockYCbCr(pointer buffer,
+              uint64_t cpuUsage,
+              Rect accessRegion,
+              handle acquireFence)
+            generates (Error error,
+                       YCbCrLayout layout);
+
+    /**
+     * 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);
+
+    /**
+     * 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);
+
+};
+
diff --git a/graphics/mapper/4.0/types.hal b/graphics/mapper/4.0/types.hal
new file mode 100644
index 0000000..603b243
--- /dev/null
+++ b/graphics/mapper/4.0/types.hal
@@ -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.
+ */
+
+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<uint32_t> BufferDescriptor;
+
+/**
+ * Structure for describing YCbCr formats for consumption by applications.
+ * This is used with PixelFormat::YCBCR_*_888.
+ *
+ * Buffer chroma subsampling is defined in the format.
+ * e.g. PixelFormat::YCBCR_420_888 has subsampling 4:2:0.
+ *
+ * Buffers must have a 8 bit depth.
+ *
+ * y, cb, and cr point to the first byte of their respective planes.
+ *
+ * Stride describes the distance in bytes from the first value of one row of
+ * the image to the first value of the next row. It includes the width of the
+ * image plus padding.
+ * yStride is the stride of the luma plane.
+ * cStride is the stride of the chroma planes.
+ *
+ * chromaStep is the distance in bytes from one chroma pixel value to the
+ * next. This is 2 bytes for semiplanar (because chroma values are interleaved
+ * and each chroma value is one byte) and 1 for planar.
+ */
+struct YCbCrLayout {
+    pointer y;
+    pointer cb;
+    pointer cr;
+    uint32_t yStride;
+    uint32_t cStride;
+    uint32_t chromaStep;
+};
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..e451584
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_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",
+    ],
+    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..056b7c9
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -0,0 +1,304 @@
+/*
+ * 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 <mapper-vts/4.0/MapperVts.h>
+
+#include <VtsHalHidlTargetTestBase.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 = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+    ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+
+    mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(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 = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+
+    mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(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;
+}
+
+std::string Gralloc::dumpDebugInfo() {
+    std::string debugInfo;
+    mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+    return debugInfo;
+}
+
+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,
+                                                      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++) {
+                                 if (import) {
+                                     ASSERT_NO_FATAL_FAILURE(
+                                             bufferHandles.push_back(importBuffer(tmpBuffers[i])));
+                                 } else {
+                                     ASSERT_NO_FATAL_FAILURE(
+                                             bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
+                                 }
+                             }
+
+                             if (outStride) {
+                                 *outStride = tmpStride;
+                             }
+                         });
+
+    if (::testing::Test::HasFatalFailure()) {
+        bufferHandles.clear();
+    }
+
+    return bufferHandles;
+}
+
+const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                         bool import, uint32_t* outStride) {
+    BufferDescriptor descriptor = createDescriptor(descriptorInfo);
+    if (::testing::Test::HasFatalFailure()) {
+        return nullptr;
+    }
+
+    auto buffers = allocate(descriptor, 1, import, outStride);
+    if (::testing::Test::HasFatalFailure()) {
+        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) {
+    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, int32_t* outBytesPerPixel,
+                    int32_t* outBytesPerStride) {
+    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;
+    }
+
+    *outBytesPerPixel = -1;
+    *outBytesPerStride = -1;
+
+    void* data = nullptr;
+    mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+                  [&](const auto& tmpError, const auto& tmpData, int32_t tmpBytesPerPixel,
+                      int32_t tmpBytesPerStride) {
+                      ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer;
+                      data = tmpData;
+                      *outBytesPerPixel = tmpBytesPerPixel;
+                      *outBytesPerStride = tmpBytesPerStride;
+                  });
+
+    if (acquireFence >= 0) {
+        close(acquireFence);
+    }
+
+    return data;
+}
+
+YCbCrLayout Gralloc::lockYCbCr(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;
+    }
+
+    YCbCrLayout layout = {};
+    mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+                       [&](const auto& tmpError, const auto& tmpLayout) {
+                           ASSERT_EQ(Error::NONE, tmpError)
+                                   << "failed to lockYCbCr buffer " << buffer;
+                           layout = tmpLayout;
+                       });
+
+    if (acquireFence >= 0) {
+        close(acquireFence);
+    }
+
+    return layout;
+}
+
+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;
+}
+
+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;
+}
+
+}  // 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..03ce764
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -0,0 +1,105 @@
+/*
+ * 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 <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;
+
+    std::string dumpDebugInfo();
+
+    // 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, uint32_t* outStride = nullptr);
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import = true, 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, int32_t* outBytesPerPixel,
+               int32_t* outBytesPerStride);
+    YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                          const IMapper::Rect& accessRegion, int acquireFence);
+    int unlock(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);
+
+  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..a90ee0c
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/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_test {
+    name: "VtsHalGraphicsMapperV4_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
+    static_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",
+        "android.hardware.graphics.mapper@4.0-vts",
+    ],
+    test_suites: ["general-tests"],
+}
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..706c658
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -0,0 +1,494 @@
+/*
+ * 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 <chrono>
+#include <thread>
+#include <vector>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <mapper-vts/4.0/MapperVts.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;
+
+// Test environment for graphics.mapper.
+class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    // get the test environment singleton
+    static GraphicsMapperHidlEnvironment* Instance() {
+        static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override {
+        registerTestService<IAllocator>();
+        registerTestService<IMapper>();
+    }
+};
+
+class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+  protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(
+                mGralloc = std::make_unique<Gralloc>(
+                        GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
+                        GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+
+        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);
+    }
+
+    void TearDown() override {}
+
+    std::unique_ptr<Gralloc> mGralloc;
+    IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
+};
+
+/**
+ * Test IAllocator::dumpDebugInfo by calling it.
+ */
+TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
+    mGralloc->dumpDebugInfo();
+}
+
+/**
+ * Test IAllocator::allocate with valid buffer descriptors.
+ */
+TEST_F(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, &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_F(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_F(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_F(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_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
+    ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
+}
+
+/**
+ * Test IMapper::createDescriptor with invalid descriptor info.
+ */
+TEST_F(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_F(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_F(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_F(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>(
+                    GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
+                    GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+    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_F(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_F(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_F(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_F(GraphicsMapperHidlTest, LockUnlockBasic) {
+    const auto& info = mDummyDescriptorInfo;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &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;
+    int32_t bytesPerPixel = -1;
+    int32_t bytesPerStride = -1;
+    ASSERT_NO_FATAL_FAILURE(
+            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence,
+                                                        &bytesPerPixel, &bytesPerStride)));
+
+    // Valid return values are -1 for unsupported or the number bytes for supported which is >=0
+    EXPECT_GT(bytesPerPixel, -1);
+    EXPECT_GT(bytesPerStride, -1);
+
+    // RGBA_8888
+    size_t strideInBytes = stride * 4;
+    size_t writeInBytes = info.width * 4;
+
+    for (uint32_t y = 0; y < info.height; y++) {
+        memset(data, y, writeInBytes);
+        data += strideInBytes;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+
+    bytesPerPixel = -1;
+    bytesPerStride = -1;
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(
+            data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence,
+                                                        &bytesPerPixel, &bytesPerStride)));
+    for (uint32_t y = 0; y < info.height; y++) {
+        for (size_t i = 0; i < writeInBytes; i++) {
+            EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
+        }
+        data += strideInBytes;
+    }
+
+    EXPECT_GT(bytesPerPixel, -1);
+    EXPECT_GT(bytesPerStride, -1);
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+    if (fence >= 0) {
+        close(fence);
+    }
+}
+
+/**
+ * Test IMapper::lockYCbCr.  This locks a YV12 buffer, and makes sure we can
+ * write to and read from it.
+ */
+TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::YV12;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &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;
+    YCbCrLayout layout;
+    ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
+
+    auto yData = static_cast<uint8_t*>(layout.y);
+    auto cbData = static_cast<uint8_t*>(layout.cb);
+    auto crData = static_cast<uint8_t*>(layout.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);
+
+            yData[layout.yStride * y + x] = val;
+            if (y % 2 == 0 && x % 2 == 0) {
+                cbData[layout.cStride * y / 2 + x / 2] = val;
+                crData[layout.cStride * y / 2 + x / 2] = val;
+            }
+        }
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+
+    // lock again for reading
+    ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
+
+    yData = static_cast<uint8_t*>(layout.y);
+    cbData = static_cast<uint8_t*>(layout.cb);
+    crData = static_cast<uint8_t*>(layout.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[layout.yStride * y + x]);
+            if (y % 2 == 0 && x % 2 == 0) {
+                EXPECT_EQ(val, cbData[layout.cStride * y / 2 + x / 2]);
+                EXPECT_EQ(val, crData[layout.cStride * y / 2 + x / 2]);
+            }
+        }
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+    if (fence >= 0) {
+        close(fence);
+    }
+}
+
+/**
+ * Test IMapper::unlock with invalid buffers.
+ */
+TEST_F(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::isSupported with required format RGBA_8888
+ */
+TEST_F(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_F(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_F(GraphicsMapperHidlTest, IsSupportedY16) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::Y16;
+    bool supported = false;
+
+    ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+}
+
+}  // namespace
+}  // namespace vts
+}  // namespace V4_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    using android::hardware::graphics::mapper::V4_0::vts::GraphicsMapperHidlEnvironment;
+    ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
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/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/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 03fcc17..dc54f27 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
@@ -130,8 +130,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/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
index e63faa2..1cad913 100644
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -147,8 +147,8 @@
             .width = size,
             .height = 1,
             .layerCount = 1,
-            .format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
             .usage = kBufferUsage,
+            .format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
     };
 
     BufferDescriptor descriptor;
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/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 a0cf0d9..fa00a6e 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 397ad17..6fa6e7e 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -28,7 +28,9 @@
     shared_libs: [
         "libnativehelper",
     ],
-    static_libs: ["android.hardware.wifi@1.0"],
+    static_libs: [
+        "android.hardware.wifi@1.0",
+    ],
 }
 
 cc_test {
@@ -36,7 +38,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",
@@ -52,11 +53,14 @@
     test_suites: ["general-tests"],
 }
 
+// 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: [
@@ -65,3 +69,20 @@
     ],
     test_suites: ["general-tests"],
 }
+
+// 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",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
index e7b8593..9d25014 100644
--- a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
+++ b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
@@ -41,10 +41,7 @@
     ::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;
-    }
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
     return status;
 }
diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
index e5762f2..c55221d 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
@@ -29,21 +29,17 @@
 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 {
    public:
     virtual void SetUp() override {
-        if (!gEnv->isSoftApOn) return;
         wifi_ap_iface_ = getWifiApIface();
         ASSERT_NE(nullptr, wifi_ap_iface_.get());
     }
 
     virtual void TearDown() override {
-        if (!gEnv->isSoftApOn) return;
         stopWifi();
     }
 
@@ -57,7 +53,6 @@
  * successfully created.
  */
 TEST(WifiApIfaceHidlTestNoFixture, Create) {
-    if (!gEnv->isSoftApOn) return;
     EXPECT_NE(nullptr, getWifiApIface().get());
     stopWifi();
 }
@@ -67,7 +62,6 @@
  * Ensures that the correct interface type is returned for AP interface.
  */
 TEST_F(WifiApIfaceHidlTest, GetType) {
-    if (!gEnv->isSoftApOn) return;
     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);
@@ -79,7 +73,6 @@
  * status code.
  */
 TEST_F(WifiApIfaceHidlTest, SetCountryCode) {
-    if (!gEnv->isSoftApOn) return;
     const android::hardware::hidl_array<int8_t, 2> kCountryCode{
         std::array<int8_t, 2>{{0x55, 0x53}}};
     EXPECT_EQ(WifiStatusCode::SUCCESS,
@@ -91,7 +84,6 @@
  * Ensures that we can retrieve valid frequencies for 2.4 GHz band.
  */
 TEST_F(WifiApIfaceHidlTest, GetValidFrequenciesForBand) {
-    if (!gEnv->isSoftApOn) return;
     const auto& status_and_freqs = HIDL_INVOKE(
         wifi_ap_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code);
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..232ffdd
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/IWifiChip.h>
+
+#include <VtsHalHidlTargetTestBase.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::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::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        wifi_chip_ = getWifiChip();
+        ASSERT_NE(nullptr, wifi_chip_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(); }
+
+   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_;
+};
+
+/*
+ * CreateApIface
+ * Configures the chip in AP mode and ensures that at least 1 iface creation
+ * succeeds.
+ */
+TEST_F(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_F(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_F(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_F(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));
+}
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..595f23a
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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/IWifiChip.h>
+
+#include <VtsHalHidlTargetTestBase.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::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::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        wifi_chip_ = getWifiChip();
+        ASSERT_NE(nullptr, wifi_chip_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(); }
+
+   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_;
+};
+
+/*
+ * CreateNanIface
+ * Configures the chip in NAN mode and ensures that at least 1 iface creation
+ * succeeds.
+ */
+TEST_F(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_F(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_F(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_F(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));
+}
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..2601b78 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -36,9 +36,7 @@
 using ::android::hardware::wifi::V1_0::WifiStatus;
 using ::android::hardware::wifi::V1_0::WifiStatusCode;
 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;
@@ -64,7 +62,10 @@
 }  // 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 {
    public:
@@ -114,26 +115,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;
@@ -360,201 +341,6 @@
 }
 
 /*
- * 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.
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 d430ce0..7dacaf1 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -54,48 +54,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.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
index a0f97f8..673fed3 100644
--- a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
+++ b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
@@ -41,10 +41,7 @@
     ::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;
-    }
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
     return status;
 }
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/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
index 71e90ac..d382f30 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
@@ -27,6 +27,8 @@
 #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;
 
@@ -59,14 +61,11 @@
  * and return a success status code.
  */
 TEST_F(WifiStaIfaceHidlTest, GetFactoryMacAddress) {
-    const auto& status_and_mac =
+    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);
 }
 
 /*
diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp
new file mode 100644
index 0000000..aba8b44
--- /dev/null
+++ b/wifi/1.4/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi@1.4",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IWifi.hal",
+        "IWifiApIface.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..af88afb
--- /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.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 99%
rename from wifi/1.3/default/hidl_struct_util.cpp
rename to wifi/1.4/default/hidl_struct_util.cpp
index 2e4db70..47713cd 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 {
 
@@ -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);
@@ -2683,7 +2683,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 99%
rename from wifi/1.3/default/hidl_struct_util.h
rename to wifi/1.4/default/hidl_struct_util.h
index 3eefd95..c9f1c26 100644
--- a/wifi/1.3/default/hidl_struct_util.h
+++ b/wifi/1.4/default/hidl_struct_util.h
@@ -37,7 +37,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;
@@ -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 98%
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..14a1504 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;
@@ -277,9 +277,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 +292,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 99%
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..b0357ba 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,
@@ -865,7 +866,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 99%
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..8aefa92 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,7 +38,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 
 bool CaptureIfaceEventHandlers(
@@ -142,7 +142,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 71%
rename from wifi/1.3/default/wifi_ap_iface.cpp
rename to wifi/1.4/default/wifi_ap_iface.cpp
index 9a8681a..e677f19 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();
@@ -85,6 +70,20 @@
                            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_};
 }
@@ -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 75%
rename from wifi/1.3/default/wifi_ap_iface.h
rename to wifi/1.4/default/wifi_ap_iface.h
index 98c5c9c..4f3438c 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();
@@ -53,6 +50,10 @@
                                 setCountryCode_cb hidl_status_cb) override;
     Return<void> getValidFrequenciesForBand(
         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.
@@ -61,18 +62,20 @@
     WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
     std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
     getValidFrequenciesForBandInternal(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 99%
rename from wifi/1.3/default/wifi_chip.cpp
rename to wifi/1.4/default/wifi_chip.cpp
index e9991dc..408096f 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()),
@@ -806,8 +805,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()) {
@@ -1539,7 +1537,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 98%
rename from wifi/1.3/default/wifi_chip.h
rename to wifi/1.4/default/wifi_chip.h
index 153ca6a..0d7061c 100644
--- a/wifi/1.3/default/wifi_chip.h
+++ b/wifi/1.4/default/wifi_chip.h
@@ -37,7 +37,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -251,7 +251,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_;
@@ -273,7 +272,7 @@
 };
 
 }  // 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..8139253 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
@@ -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 99%
rename from wifi/1.3/default/wifi_nan_iface.cpp
rename to wifi/1.4/default/wifi_nan_iface.cpp
index ff9f422..981acb2 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;
 
@@ -881,7 +881,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 99%
rename from wifi/1.3/default/wifi_nan_iface.h
rename to wifi/1.4/default/wifi_nan_iface.h
index 737be93..e3a5c34 100644
--- a/wifi/1.3/default/wifi_nan_iface.h
+++ b/wifi/1.4/default/wifi_nan_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;
 
@@ -160,7 +160,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 99%
rename from wifi/1.3/default/wifi_rtt_controller.cpp
rename to wifi/1.4/default/wifi_rtt_controller.cpp
index 3dcbee6..d50c7cf 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;
 
@@ -271,7 +271,7 @@
     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 98%
rename from wifi/1.3/default/wifi_rtt_controller.h
rename to wifi/1.4/default/wifi_rtt_controller.h
index eedd22a..1415ff7 100644
--- a/wifi/1.3/default/wifi_rtt_controller.h
+++ b/wifi/1.4/default/wifi_rtt_controller.h
@@ -27,7 +27,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 
 /**
@@ -98,7 +98,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 99%
rename from wifi/1.3/default/wifi_sta_iface.cpp
rename to wifi/1.4/default/wifi_sta_iface.cpp
index a6539e5..3e0127e 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;
 
@@ -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 99%
rename from wifi/1.3/default/wifi_sta_iface.h
rename to wifi/1.4/default/wifi_sta_iface.h
index 9224939..d8f7a01 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;
 
@@ -171,7 +171,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 97%
rename from wifi/1.3/default/wifi_status_util.h
rename to wifi/1.4/default/wifi_status_util.h
index bc8baa9..41bcfaf 100644
--- a/wifi/1.3/default/wifi_status_util.h
+++ b/wifi/1.4/default/wifi_status_util.h
@@ -24,7 +24,7 @@
 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.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..42c60f2
--- /dev/null
+++ b/wifi/1.4/vts/functional/Android.bp
@@ -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.
+//
+
+// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest.
+cc_test {
+    name: "VtsHalWifiApV1_4TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalWifiV1_4TargetTest.cpp",
+        "wifi_ap_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",
+    ],
+}
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..deac0fa
--- /dev/null
+++ b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/wifi/1.4/IWifi.h>
+
+#include "wifi_hidl_test_utils.h"
+
+using ::android::hardware::wifi::V1_4::IWifi;
+
+// Test environment for Wifi HIDL HAL.
+class WifiHidlEnvironment_1_4 : public WifiHidlEnvironment {
+   public:
+    // get the test environment singleton
+    static WifiHidlEnvironment_1_4* Instance() {
+        static WifiHidlEnvironment_1_4* instance = new WifiHidlEnvironment_1_4;
+        return instance;
+    }
+
+    virtual void registerTestServices() override {
+        registerTestService<android::hardware::wifi::V1_4::IWifi>();
+    }
+
+   private:
+    WifiHidlEnvironment_1_4() {}
+};
+
+WifiHidlEnvironment_1_4* gEnv = WifiHidlEnvironment_1_4::Instance();
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnv->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/wifi/1.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..68e9bbb
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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/IWifiApIface.h>
+
+#include <VtsHalHidlTargetTestBase.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::IWifiApIface;
+
+extern WifiHidlEnvironment* gEnv;
+
+/**
+ * Fixture to use for all STA Iface HIDL interface tests.
+ */
+class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        wifi_ap_iface_ = IWifiApIface::castFrom(getWifiApIface());
+        ASSERT_NE(nullptr, wifi_ap_iface_.get());
+    }
+
+    virtual void TearDown() override {
+        stopWifi();
+    }
+
+   protected:
+    sp<IWifiApIface> wifi_ap_iface_;
+};
+
+/*
+ * SetMacAddress:
+ * Ensures that calls to set MAC address will return a success status
+ * code.
+ */
+TEST_F(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_F(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);
+}
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..cb207d8
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal
@@ -0,0 +1,57 @@
+/*
+ * 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);
+};
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..7874399
--- /dev/null
+++ b/wifi/supplicant/1.3/types.hal
@@ -0,0 +1,60 @@
+/*
+ * 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;
+};
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..62f3228
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+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);
+        });
+}
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);
+        });
+}